Source code for pycif.plugins.minimizers.scipy.minimize

import numpy as np
import scipy

from logging import info


[docs] def minimize(self, finit, gradinit, chi0, **kwargs): """Run :func:`scipy.optimize.minimize` and return the optimal iterate. Wraps the simulator into a ``(f, g)`` callable compatible with scipy's ``jac=True`` interface and hooks a gradient-norm callback for the ``epsg`` convergence criterion. Args: self (Plugin): scipy minimizer plugin instance. finit (float): initial cost function value (unused; kept for interface consistency with other minimizers). gradinit (np.ndarray): initial gradient, shape ``(n,)``. chi0 (np.ndarray): initial iterate, shape ``(n,)``. **kwargs: forwarded to the simulator. Returns: np.ndarray: optimal iterate :math:`\chi_\mathrm{opt}`, shape ``(n,)``. """ # Initialize iteration number and initial norm of the gradient self.iter_id = 0 self.grad_norm_0 = np.sqrt(np.dot(gradinit, gradinit)) # Wrap the simulator into a function compatible with scipy def fun(x): f, g = self.simulator.simul(x, run_id=self.iter_id, **kwargs) self.iter_id += 1 self.current_function = f self.current_gradient = g[:] return f, g # Define Call Back to check convergence with regards to the norm of the gradient def callback(xk): if hasattr(self, "epsg"): gradopt = self.current_gradient if np.sqrt(np.dot(gradopt, gradopt)) < self.epsg * self.grad_norm_0: self.xopt = xk raise StopIteration return False # Running scipy minimizer try: results = scipy.optimize.minimize( fun, chi0, jac=True, method=self.method, bounds=self.bounds, options=self.options, callback=callback ) # Final verbose and output info(results) # Outputs xopt = results.x gradopt = results.jac fopt = results.fun except StopIteration: info("The convergence criterion on epsg has been reached") xopt = self.xopt gradopt = self.current_gradient fopt = self.current_function r1 = np.sqrt(np.dot(xopt, xopt)) r2 = np.sqrt(np.dot(gradopt, gradopt)) info("norm of x = " + str(r1)) info("f = " + str(fopt)) info("norm of g = " + str(r2)) return xopt