Commit 4ebe2364 authored by Martin Reinecke's avatar Martin Reinecke
Browse files

do not use iteration controllers for Scipy minimizers

parent 5623a2a9
Pipeline #26190 failed with stages
in 4 minutes and 54 seconds
...@@ -21,6 +21,32 @@ from .minimizer import Minimizer ...@@ -21,6 +21,32 @@ from .minimizer import Minimizer
from ..field import Field from ..field import Field
from .. import dobj from .. import dobj
from ..logger import logger from ..logger import logger
from .iteration_controller import IterationController
class _MinHelper(object):
def __init__(self, energy):
self._energy = energy
self._domain = energy.position.domain
def _update(self, x):
pos = Field(self._domain, x.reshape(self._domain.shape))
if (pos.val != self._energy.position.val).any():
self._energy = self._energy.at(pos.locked_copy())
def fun(self, x):
self._update(x)
return self._energy.value
def jac(self, x):
self._update(x)
return self._energy.gradient.val.flatten()
def hessp(self, x, p):
self._update(x)
vec = Field(self._domain, p.reshape(self._domain.shape))
res = self._energy.curvature(vec)
return res.val.flatten()
class ScipyMinimizer(Minimizer): class ScipyMinimizer(Minimizer):
...@@ -28,100 +54,62 @@ class ScipyMinimizer(Minimizer): ...@@ -28,100 +54,62 @@ class ScipyMinimizer(Minimizer):
Parameters Parameters
---------- ----------
controller : IterationController
Object that decides when to terminate the minimization.
method : str method : str
The selected Scipy minimization method. The selected Scipy minimization method.
options : dictionary options : dictionary
A set of custom options for the selected minimizer. A set of custom options for the selected minimizer.
""" """
def __init__(self, controller, method, options, need_hessp): def __init__(self, method, options, need_hessp, bounds):
super(ScipyMinimizer, self).__init__() super(ScipyMinimizer, self).__init__()
if not dobj.is_numpy(): if not dobj.is_numpy():
raise NotImplementedError raise NotImplementedError
self._controller = controller
self._method = method self._method = method
self._options = options self._options = options
self._need_hessp = need_hessp self._need_hessp = need_hessp
self._bounds = bounds
def __call__(self, energy): def __call__(self, energy):
class _MinimizationDone(BaseException):
pass
class _MinHelper(object):
def __init__(self, controller, energy):
self._controller = controller
self._energy = energy
self._domain = energy.position.domain
def _update(self, x):
pos = Field(self._domain, x.reshape(self._domain.shape))
if (pos.val != self._energy.position.val).any():
self._energy = self._energy.at(pos.locked_copy())
status = self._controller.check(self._energy)
if status != self._controller.CONTINUE:
raise _MinimizationDone
def fun(self, x):
self._update(x)
return self._energy.value
def jac(self, x):
self._update(x)
return self._energy.gradient.val.flatten()
def hessp(self, x, p):
self._update(x)
vec = Field(self._domain, p.reshape(self._domain.shape))
res = self._energy.curvature(vec)
return res.val.flatten()
import scipy.optimize as opt import scipy.optimize as opt
hlp = _MinHelper(self._controller, energy) hlp = _MinHelper(energy)
energy = None energy = None # drop handle, since we don't need it any more
status = self._controller.start(hlp._energy) bounds = None
if status != self._controller.CONTINUE: if self._bounds is not None:
return hlp._energy, status if len(self._bounds) == 2:
x = hlp._energy.position.val.flatten() lo = self._bounds[0]
try: hi = self._bounds[1]
if self._need_hessp: bounds = [(lo, hi)]*hlp._energy.position.size
r = opt.minimize(hlp.fun, x,
method=self._method, jac=hlp.jac,
hessp=hlp.hessp,
options=self._options)
else: else:
r = opt.minimize(hlp.fun, x, raise ValueError("unrecognized bounds")
method=self._method, jac=hlp.jac,
options=self._options) x = hlp._energy.position.val.flatten()
except _MinimizationDone: hessp = hlp.hessp if self._need_hessp else None
status = self._controller.check(hlp._energy) r = opt.minimize(hlp.fun, x, method=self._method, jac=hlp.jac,
return hlp._energy, self._controller.check(hlp._energy) hessp=hessp, options=self._options, bounds=bounds)
if not r.success: if not r.success:
logger.error("Problem in Scipy minimization:", r.message) logger.error("Problem in Scipy minimization:", r.message)
else: return hlp._energy, IterationController.ERROR
logger.error("Problem in Scipy minimization") return hlp._energy, IterationController.CONVERGED
return hlp._energy, self._controller.ERROR
def NewtonCG(controller): def NewtonCG(xtol, maxiter, disp=False):
"""Returns a ScipyMinimizer object carrying out the Newton-CG algorithm. """Returns a ScipyMinimizer object carrying out the Newton-CG algorithm.
See Also See Also
-------- --------
ScipyMinimizer ScipyMinimizer
""" """
return ScipyMinimizer(controller, "Newton-CG", options = {"xtol": xtol, "maxiter": maxiter, "disp": verbose}
{"xtol": 1e-20, "maxiter": None}, True) return ScipyMinimizer("Newton-CG", options, True, None)
def L_BFGS_B(controller, maxcor=10): def L_BFGS_B(ftol, gtol, maxiter, maxcor=10, disp=False, bounds=None):
"""Returns a ScipyMinimizer object carrying out the L-BFGS-B algorithm. """Returns a ScipyMinimizer object carrying out the L-BFGS-B algorithm.
See Also See Also
-------- --------
ScipyMinimizer ScipyMinimizer
""" """
return ScipyMinimizer(controller, "L-BFGS-B", options = {"ftol": ftol, "gtol": gtol, "maxiter": maxiter,
{"ftol": 1e-20, "gtol": 1e-20, "maxcor": maxcor}, "maxcor": maxcor, "disp": verbose}
False) return ScipyMinimizer("L-BFGS-B", options, False, bounds)
...@@ -30,11 +30,11 @@ spaces = [ift.RGSpace([1024], distances=0.123), ift.HPSpace(32)] ...@@ -30,11 +30,11 @@ spaces = [ift.RGSpace([1024], distances=0.123), ift.HPSpace(32)]
minimizers = ['ift.VL_BFGS(IC)', minimizers = ['ift.VL_BFGS(IC)',
'ift.NonlinearCG(IC, "Polak-Ribiere")', 'ift.NonlinearCG(IC, "Polak-Ribiere")',
# ift.NonlinearCG(IC, "Hestenes-Stiefel"), #'ift.NonlinearCG(IC, "Hestenes-Stiefel"),
'ift.NonlinearCG(IC, "Fletcher-Reeves")', 'ift.NonlinearCG(IC, "Fletcher-Reeves")',
'ift.NonlinearCG(IC, "5.49")', 'ift.NonlinearCG(IC, "5.49")',
'ift.NewtonCG(IC)', 'ift.NewtonCG(xtol=1e-5,maxiter=1000)',
'ift.L_BFGS_B(IC)', 'ift.L_BFGS_B(ftol=1e-10,gtol=1e-5,maxiter=1000)',
'ift.L_BFGS(IC)'] 'ift.L_BFGS(IC)']
newton_minimizers = ['ift.RelaxedNewton(IC)'] newton_minimizers = ['ift.RelaxedNewton(IC)']
......
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