diff --git a/demos/critical_filtering.py b/demos/critical_filtering.py index acc270d5b1002b83d6d929bbb04b1ccce8a1f713..5387d5595e7ab3e4483ed922b98a31a02e0d9706 100644 --- a/demos/critical_filtering.py +++ b/demos/critical_filtering.py @@ -102,8 +102,8 @@ if __name__ == "__main__": data_power = log(fft(d).power_analyze(logarithmic=p_space.config["logarithmic"], nbin=p_space.config["nbin"])) d_data = d.val.get_full_data().real - if rank == 0: - pl.plot([go.Heatmap(z=d_data)], filename='data.html') + #if rank == 0: + # pl.plot([go.Heatmap(z=d_data)], filename='data.html') # minimization strategy @@ -150,7 +150,7 @@ if __name__ == "__main__": # Plotting current estimate print i - if i%50 == 0: - plot_parameters(m0,t0,log(sp), data_power) + #if i%50 == 0: + # plot_parameters(m0,t0,log(sp), data_power) diff --git a/nifty/energies/line_energy.py b/nifty/energies/line_energy.py index fe0c1ec1e6ba4753b7a0b10018ca801e154e0ae6..e79ee2b829a2d389bbff27df23a0d86ac8931925 100644 --- a/nifty/energies/line_energy.py +++ b/nifty/energies/line_energy.py @@ -16,10 +16,8 @@ # NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik # and financially supported by the Studienstiftung des deutschen Volkes. -from .energy import Energy - -class LineEnergy(Energy): +class LineEnergy: """ Evaluates an underlying Energy along a certain line direction. Given an Energy class and a line direction, its position is parametrized by @@ -27,34 +25,31 @@ class LineEnergy(Energy): Parameters ---------- - position : float - The step length parameter along the given line direction. + linepos : float + Defines the full spatial position of this energy via + self.energy.position = zero_point + linepos*line_direction energy : Energy The Energy object which will be evaluated along the given direction. - line_direction : Field - Direction used for line evaluation. - zero_point : Field *optional* - Fixing the zero point of the line restriction. Used to memorize this - position in new initializations. By the default the current position - of the supplied `energy` instance is used (default : None). + linedir : Field + Direction used for line evaluation. Does not have to be normalized. + offset : float *optional* + Indirectly defines the zero point of the line via the equation + energy.position = zero_point + offset*line_direction + (default : 0.). Attributes ---------- - position : float + linepos : float The position along the given line direction relative to the zero point. value : float - The value of the energy functional at given `position`. - gradient : float - The gradient of the underlying energy instance along the line direction - projected on the line direction. - curvature : callable - A positive semi-definite operator or function describing the curvature - of the potential at given `position`. - line_direction : Field + The value of the energy functional at the given position + dd : float + The directional derivative at the given position + linedir : Field Direction along which the movement is restricted. Does not have to be normalized. energy : Energy - The underlying Energy at the `position` along the line direction. + The underlying Energy at the given position Raises ------ @@ -72,45 +67,44 @@ class LineEnergy(Energy): """ - def __init__(self, position, energy, line_direction, zero_point=None): - super(LineEnergy, self).__init__(position=position) - self.line_direction = line_direction - - if zero_point is None: - zero_point = energy.position - self._zero_point = zero_point + def __init__(self, linepos, energy, linedir, offset=0.): + self._linepos = float(linepos) + self._linedir = linedir - position_on_line = self._zero_point + self.position*line_direction - self.energy = energy.at(position=position_on_line) + pos = energy.position + (self._linepos-float(offset))*self._linedir + self.energy = energy.at(position=pos) - def at(self, position): + def at(self, linepos): """ Returns LineEnergy at new position, memorizing the zero point. Parameters ---------- - position : float + linepos : float Parameter for the new position on the line direction. Returns ------- - out : LineEnergy LineEnergy object at new position with same zero point as `self`. """ - return self.__class__(position, + return self.__class__(linepos, self.energy, - self.line_direction, - zero_point=self._zero_point) + self.linedir, + offset=self.linepos) @property def value(self): return self.energy.value @property - def gradient(self): - return self.energy.gradient.vdot(self.line_direction) + def linepos(self): + return self._linepos + + @property + def linedir(self): + return self._linedir @property - def curvature(self): - return self.energy.curvature + def dd(self): + return self.energy.gradient.vdot(self.linedir) diff --git a/nifty/field.py b/nifty/field.py index 9dce821f4f216884bb535e83f35c88377e132ca8..b92f64ed4c66daaa60a642fef883aed217623955 100644 --- a/nifty/field.py +++ b/nifty/field.py @@ -181,7 +181,7 @@ class Field(Loggable, Versionable, object): elif isinstance(val, Field): distribution_strategy = val.distribution_strategy else: - self.logger.debug("distribution_strategy set to default!") + #self.logger.debug("distribution_strategy set to default!") distribution_strategy = gc['default_distribution_strategy'] elif distribution_strategy not in DISTRIBUTION_STRATEGIES['global']: raise ValueError( diff --git a/nifty/minimization/descent_minimizer.py b/nifty/minimization/descent_minimizer.py index d65b9d86b23151c8c870c2245d157033dbe5c6db..964489c1460870b05681cd058c9ab5af4ce6313c 100644 --- a/nifty/minimization/descent_minimizer.py +++ b/nifty/minimization/descent_minimizer.py @@ -121,12 +121,18 @@ class DescentMinimizer(Loggable, object): """ + print "into line search:" + print " pos: ",energy.position.val[0] + print " ene: ",energy.value convergence = 0 f_k_minus_1 = None step_length = 0 iteration_number = 1 while True: + print "line search next iteration:" + print " pos: ",energy.position.val[0] + print " ene: ",energy.value if self.callback is not None: try: self.callback(energy, iteration_number) @@ -147,7 +153,7 @@ class DescentMinimizer(Loggable, object): # current position is encoded in energy object descent_direction = self.get_descent_direction(energy) - + print "descent direction:",descent_direction.val[0] # compute the step length, which minimizes energy.value along the # search direction step_length, f_k, new_energy = \ @@ -155,10 +161,20 @@ class DescentMinimizer(Loggable, object): energy=energy, pk=descent_direction, f_k_minus_1=f_k_minus_1) + print "out of wolfe:" + print " old pos: ",energy.position.val[0] + print " old ene: ",energy.value + print " new pos: ",new_energy.position.val[0] + print " new ene: ",new_energy.value + print " f_k: ",f_k f_k_minus_1 = energy.value - + print " step length: ", step_length + tx1=energy.position-new_energy.position + print " step length 2: ", (energy.position-new_energy.position).norm() + print " step length 3: ", new_energy.position.val[0]-energy.position.val[0] # check if new energy value is bigger than old energy value if (new_energy.value - energy.value) > 0: + print "Line search algorithm returned a new energy that was larger than the old one. Stopping." self.logger.info("Line search algorithm returned a new energy " "that was larger than the old one. Stopping.") break diff --git a/nifty/minimization/line_searching/line_search.py b/nifty/minimization/line_searching/line_search.py index 6debbc5d2c18dfedf644f70a715feda7296d0ead..9456b9acca50ff6dc8d3a3f7fe6dda1ffb397150 100644 --- a/nifty/minimization/line_searching/line_search.py +++ b/nifty/minimization/line_searching/line_search.py @@ -66,9 +66,9 @@ class LineSearch(Loggable, object): iteration of the line search procedure. (Default: None) """ - self.line_energy = LineEnergy(position=0., + self.line_energy = LineEnergy(linepos=0., energy=energy, - line_direction=pk) + linedir=pk) if f_k_minus_1 is not None: f_k_minus_1 = f_k_minus_1.copy() self.f_k_minus_1 = f_k_minus_1 diff --git a/nifty/minimization/line_searching/line_search_strong_wolfe.py b/nifty/minimization/line_searching/line_search_strong_wolfe.py index 9a4941e34de94096af886aa67419f1bb1c286257..c9424512f18705490d32251d29a547860429c74a 100644 --- a/nifty/minimization/line_searching/line_search_strong_wolfe.py +++ b/nifty/minimization/line_searching/line_search_strong_wolfe.py @@ -103,16 +103,14 @@ class LineSearchStrongWolfe(LineSearch): """ self._set_line_energy(energy, pk, f_k_minus_1=f_k_minus_1) - c1 = self.c1 - c2 = self.c2 max_step_size = self.max_step_size max_iterations = self.max_iterations # initialize the zero phis old_phi_0 = self.f_k_minus_1 - energy_0 = self.line_energy.at(0) - phi_0 = energy_0.value - phiprime_0 = energy_0.gradient + le_0 = self.line_energy.at(0) + phi_0 = le_0.value + phiprime_0 = le_0.dd if phiprime_0 == 0: self.logger.warn("Flat gradient in search direction.") @@ -135,45 +133,52 @@ class LineSearchStrongWolfe(LineSearch): # start the minimization loop for i in xrange(max_iterations): - energy_alpha1 = self.line_energy.at(alpha1) - phi_alpha1 = energy_alpha1.value + print "a0a1:",alpha0, alpha1 + print "line search outer iteration", i + le_alpha1 = self.line_energy.at(alpha1) + print "position:", le_alpha1.energy.position.val[0] + phi_alpha1 = le_alpha1.value + print "energy:", le_alpha1.value if alpha1 == 0: self.logger.warn("Increment size became 0.") alpha_star = 0. phi_star = phi_0 - energy_star = energy_0 + le_star = le_0 break - if (phi_alpha1 > phi_0 + c1*alpha1*phiprime_0) or \ + if (phi_alpha1 > phi_0 + self.c1*alpha1*phiprime_0) or \ ((phi_alpha1 >= phi_alpha0) and (i > 1)): - (alpha_star, phi_star, energy_star) = self._zoom( + (alpha_star, phi_star, le_star) = self._zoom( alpha0, alpha1, phi_0, phiprime_0, phi_alpha0, phiprime_alpha0, - phi_alpha1, - c1, c2) + phi_alpha1) break - phiprime_alpha1 = energy_alpha1.gradient - if abs(phiprime_alpha1) <= -c2*phiprime_0: + phiprime_alpha1 = le_alpha1.dd + if abs(phiprime_alpha1) <= -self.c2*phiprime_0: alpha_star = alpha1 phi_star = phi_alpha1 - energy_star = energy_alpha1 + le_star = le_alpha1 break if phiprime_alpha1 >= 0: - (alpha_star, phi_star, energy_star) = self._zoom( + (alpha_star, phi_star, le_star) = self._zoom( alpha1, alpha0, phi_0, phiprime_0, phi_alpha1, phiprime_alpha1, - phi_alpha0, - c1, c2) + phi_alpha0) break # update alphas alpha0, alpha1 = alpha1, min(2*alpha1, max_step_size) + if alpha1 == max_step_size: + alpha_star = alpha1 + phi_star = phi_alpha1 + le_star = le_alpha1 + break phi_alpha0 = phi_alpha1 phiprime_alpha0 = phiprime_alpha1 # phi_alpha1 = self._phi(alpha1) @@ -182,17 +187,17 @@ class LineSearchStrongWolfe(LineSearch): # max_iterations was reached alpha_star = alpha1 phi_star = phi_alpha1 - energy_star = energy_alpha1 + le_star = le_alpha1 self.logger.error("The line search algorithm did not converge.") # extract the full energy from the line_energy - energy_star = energy_star.energy + energy_star = le_star.energy direction_length = pk.norm() step_length = alpha_star * direction_length return step_length, phi_star, energy_star def _zoom(self, alpha_lo, alpha_hi, phi_0, phiprime_0, - phi_lo, phiprime_lo, phi_hi, c1, c2): + phi_lo, phiprime_lo, phi_hi): """Performs the second stage of the line search algorithm. If the first stage was not successful then the Zoom algorithm tries to @@ -203,7 +208,7 @@ class LineSearchStrongWolfe(LineSearch): ---------- alpha_lo : float The lower boundary for the step length interval. - alph_hi : float + alpha_hi : float The upper boundary for the step length interval. phi_0 : float Value of the energy at the starting point of the line search @@ -219,10 +224,6 @@ class LineSearchStrongWolfe(LineSearch): phi_hi : float Value of the energy if we perform a step of length alpha_hi in descent direction. - c1 : float - Parameter for Armijo condition rule. - c2 : float - Parameter for curvature condition rule. Returns ------- @@ -234,6 +235,10 @@ class LineSearchStrongWolfe(LineSearch): The new Energy object on the new position. """ + print "entering zoom" + print alpha_lo, alpha_hi + print "pos1:",self.line_energy.at(alpha_lo).energy.position.val[0] + print "pos2:",self.line_energy.at(alpha_hi).energy.position.val[0] max_iterations = self.max_zoom_iterations # define the cubic and quadratic interpolant checks cubic_delta = 0.2 # cubic @@ -262,28 +267,28 @@ class LineSearchStrongWolfe(LineSearch): quad_check = quad_delta * delta_alpha alpha_j = self._quadmin(alpha_lo, phi_lo, phiprime_lo, alpha_hi, phi_hi) - # If quadratic was not successfull, try bisection + # If quadratic was not successful, try bisection if (alpha_j is None) or (alpha_j > b - quad_check) or \ (alpha_j < a + quad_check): alpha_j = alpha_lo + 0.5*delta_alpha # Check if the current value of alpha_j is already sufficient - energy_alphaj = self.line_energy.at(alpha_j) - phi_alphaj = energy_alphaj.value + le_alphaj = self.line_energy.at(alpha_j) + phi_alphaj = le_alphaj.value # If the first Wolfe condition is not met replace alpha_hi # by alpha_j - if (phi_alphaj > phi_0 + c1*alpha_j*phiprime_0) or\ + if (phi_alphaj > phi_0 + self.c1*alpha_j*phiprime_0) or\ (phi_alphaj >= phi_lo): alpha_recent, phi_recent = alpha_hi, phi_hi alpha_hi, phi_hi = alpha_j, phi_alphaj else: - phiprime_alphaj = energy_alphaj.gradient + phiprime_alphaj = le_alphaj.dd # If the second Wolfe condition is met, return the result - if abs(phiprime_alphaj) <= -c2*phiprime_0: + if abs(phiprime_alphaj) <= -self.c2*phiprime_0: alpha_star = alpha_j phi_star = phi_alphaj - energy_star = energy_alphaj + le_star = le_alphaj break # If not, check the sign of the slope if phiprime_alphaj*delta_alpha >= 0: @@ -296,12 +301,12 @@ class LineSearchStrongWolfe(LineSearch): phiprime_alphaj) else: - alpha_star, phi_star, energy_star = \ - alpha_j, phi_alphaj, energy_alphaj + alpha_star, phi_star, le_star = \ + alpha_j, phi_alphaj, le_alphaj self.logger.error("The line search algorithm (zoom) did not " "converge.") - return alpha_star, phi_star, energy_star + return alpha_star, phi_star, le_star def _cubicmin(self, a, fa, fpa, b, fb, c, fc): """Estimating the minimum with cubic interpolation.