Commit c72df706 authored by Martin Reinecke's avatar Martin Reinecke

add nonlinear CG; try new fix for line search overflows

parent ad2cd090
Pipeline #16964 passed with stage
in 10 minutes and 31 seconds
......@@ -21,6 +21,7 @@ from iteration_controller import IterationController
from default_iteration_controller import DefaultIterationController
from minimizer import Minimizer
from conjugate_gradient import ConjugateGradient
from nonlinear_cg import NonlinearCG
from descent_minimizer import DescentMinimizer
from steepest_descent import SteepestDescent
from vl_bfgs import VL_BFGS
......
......@@ -37,7 +37,7 @@ class DefaultIterationController(IterationController):
def check(self, energy):
self._itcount += 1
print "iteration",self._itcount,"gradnorm",energy.gradient_norm,"level",self._ccount, self._tol_rel_gradnorm
print "iteration",self._itcount,"gradnorm",energy.gradient_norm,"level",self._ccount, energy.value
if self._iteration_limit is not None:
if self._itcount >= self._iteration_limit:
return self.CONVERGED
......
......@@ -121,7 +121,7 @@ class LineSearchStrongWolfe(LineSearch):
if alpha1 < 0:
alpha1 = 1.0
else:
alpha1 = 1.0
alpha1 = 1.0/pk.norm()
# start the minimization loop
for i in xrange(self.max_iterations):
......@@ -181,14 +181,15 @@ class LineSearchStrongWolfe(LineSearch):
phi_0 : float
Value of the energy at the starting point of the line search
algorithm.
phiprime_0 : Field
Gradient at the starting point of the line search algorithm.
phiprime_0 : float
directional derivative at the starting point of the line search
algorithm.
phi_lo : float
Value of the energy if we perform a step of length alpha_lo in
descent direction.
phiprime_lo : Field
Gradient at the nwe position if we perform a step of length
alpha_lo in descent direction.
phiprime_lo : float
directional derivative at the new position if we perform a step of
length alpha_lo in descent direction.
phi_hi : float
Value of the energy if we perform a step of length alpha_hi in
descent direction.
......
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright(C) 2013-2017 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik
# and financially supported by the Studienstiftung des deutschen Volkes.
from __future__ import division
import numpy as np
from .minimizer import Minimizer
from .line_searching import LineSearchStrongWolfe
class NonlinearCG(Minimizer):
""" Implementation of the nonlinear Conjugate Gradient scheme according to
Polak-Ribiere.
Parameters
----------
controller : IterationController
Object that decides when to terminate the minimization.
References
----------
Jorge Nocedal & Stephen Wright, "Numerical Optimization", Second Edition,
2006, Springer-Verlag New York
"""
def __init__(self, controller, line_searcher=LineSearchStrongWolfe()):
self._controller = controller
self._line_searcher = line_searcher
def __call__(self, energy):
""" Runs the conjugate gradient minimization.
Algorithm 5.4 from Nocedal & Wright
Eq. (5.41a) has been replaced by eq. (5.49)
Parameters
----------
energy : Energy object at the starting point of the iteration.
Returns
-------
energy :
state at last point of the iteration
status : integer
Can be controller.CONVERGED or controller.ERROR
"""
controller = self._controller
status = controller.start(energy)
if status != controller.CONTINUE:
return energy, status
f_k_minus_1 = None
p = -energy.gradient
while True:
grad_old = energy.gradient
gnold = energy.gradient_norm
f_k = energy.value
energy = self._line_searcher.perform_line_search(energy, p,
f_k_minus_1)
f_k_minus_1 = f_k
status = self._controller.check(energy)
if status != controller.CONTINUE:
return energy, status
grad_new = energy.gradient
gnnew = energy.gradient_norm
beta = gnnew*gnnew/(grad_new-grad_old).vdot(p).real
p = beta*p - grad_new
......@@ -10,13 +10,13 @@ from test.common import expand
spaces = [ift.RGSpace([1024], distances=0.123), ift.HPSpace(32)]
minimizers = [ift.SteepestDescent, ift.RelaxedNewton, ift.VL_BFGS,
ift.ConjugateGradient]
ift.ConjugateGradient, ift.NonlinearCG]
class Test_Minimizers(unittest.TestCase):
@expand(product(minimizers, spaces))
def test_minimization(self, minimizer_class, space):
def test_quadratic_minimization(self, minimizer_class, space):
np.random.seed(42)
starting_point = ift.Field.from_random('normal', domain=space)*10
covariance_diagonal = ift.Field.from_random(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment