Source code for pycif.plugins.minimizers.scipy_conjugate.minimize
import numpy as np
import scipy
from scipy.sparse.linalg import LinearOperator, lobpcg, cg
from logging import info
[docs]
def minimize(self, finit, gradinit, chi0, **kwargs):
"""Solve the Gauss-Newton linear system via sparse conjugate gradient.
Builds a :class:`~scipy.sparse.linalg.LinearOperator` whose
matrix-vector product is evaluated by calling the TL/forward simulator,
then dispatches to ``cg`` or ``lobpcg`` according to the ``method``
parameter.
Args:
self (Plugin): scipy conjugate-gradient plugin instance.
finit (float): initial cost value (unused; kept for interface
consistency with other minimizers).
gradinit (np.ndarray): initial gradient :math:`\\nabla J_0`,
shape ``(n,)``; used as the right-hand side of the linear system.
chi0 (np.ndarray): initial iterate (starting guess for the solver),
shape ``(n,)``.
**kwargs: forwarded to the simulator.
Returns:
np.ndarray: solution :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))
# Define A.v
def Amatvec(x):
fb, fo, gb, go = self.simulator.simul(
x.flatten(), run_id=self.iter_id,
linear=self.force_linearize,
split_obs_vs_control=True,
**kwargs
)
self.iter_id += 1
self.current_function = fo
self.current_gradient = go[:]
return go - gradinit
# Defines the A matrix
grad_dim = gradinit.shape[0]
A = LinearOperator(
(grad_dim, grad_dim),
matvec=Amatvec
)
# Defines the preconditioner matrix
# Running scipy minimizer
try:
results = cg(
A, gradinit,
maxiter=self.maxiter,
x0=chi0[:, np.newaxis]
# verbosityLevel=10
)
# Final verbose and output
info(results)
# Outputs
xopt = results[0]
# 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