Source code for secml.optim.optimizers.c_optimizer

"""
.. module:: COptimizer
   :synopsis: Interface for function optimization and minimization.

.. moduleauthor:: Marco Melis <marco.melis@unica.it>
.. moduleauthor:: Battista Biggio <battista.biggio@unica.it>

"""
from abc import ABCMeta, abstractmethod
from functools import partial

from secml.core import CCreator
from secml.optim.function import CFunction
from secml.optim.constraints import CConstraint, CConstraintBox


[docs]class COptimizer(CCreator, metaclass=ABCMeta): """Interface for optimizers. Implements: minimize f(x) s.t. gi(x) <= 0, i=1,...,m (inequality constraints) hj(x) = 0, j = 1,..., n (equality constraints) Parameters ---------- fun : CFunction The objective function to be optimized, along with 1st-order (Jacobian) and 2nd-order (Hessian) derivatives (if available). """ __super__ = 'COptimizer' def __init__(self, fun, constr=None, bounds=None): # The following will set both f and fun # fun: the internal function to be always minimized # f: the "public" function. By default, minimize f(x), so fun=f if not isinstance(fun, CFunction): raise TypeError( "Input parameter is not a `CFunction` object.") self._f = fun self._fun = fun # Read/write attributes self.constr = constr self.bounds = bounds # Internal attributes self._x_opt = None # solution point self._f_opt = None # last score f_seq[-1] self._f_seq = None # sequence of fun values at each iteration self._x_seq = None # sequence of x values at each iteration ########################################################################### # READ-ONLY ATTRIBUTES ########################################################################### @property def f(self): """The objective function""" return self._f @property def x_opt(self): return self._x_opt @property def f_opt(self): return self._f_seq[-1].item() @property def x_seq(self): return self._x_seq @property def f_seq(self): return self._f_seq @property def n_dim(self): return self._fun.n_dim @property def f_eval(self): return self._fun.n_fun_eval @property def grad_eval(self): return self._fun.n_grad_eval ########################################################################### # READ-WRITE ATTRIBUTES ########################################################################### @property def constr(self): """Optimization constraint.""" return self._constr @constr.setter def constr(self, constr): """Optimization constraint.""" if constr is None: self._constr = None return if not isinstance(constr, CConstraint): raise TypeError( "Input parameter is not a `CConstraint` object.") self._constr = constr @property def bounds(self): """Optimization bounds.""" return self._bounds @bounds.setter def bounds(self, bounds): """Optimization bounds.""" if bounds is None: self._bounds = None return if not isinstance(bounds, CConstraintBox): raise TypeError( "Input parameter is not a `CConstraintBox` object.") self._bounds = bounds ########################################## # METHODS ##########################################
[docs] @abstractmethod def minimize(self, x_init, args=(), **kwargs): """Interface for minimizers. Implementing: min fun(x) s.t. constraint Parameters ---------- x_init : CArray The initial input point. args : tuple, optional Extra arguments passed to the objective function and its gradient. kwargs Additional parameters of the minimization method. """ raise NotImplementedError('Function `minimize` is not implemented.')
[docs] def maximize(self, x_init, args=(), **kwargs): """Interface for maximizers. Implementing: max fun(x) s.t. constraint This is implemented by inverting the sign of fun and gradient and running the `COptimizer.minimize()`. Parameters ---------- x_init : CArray The initial input point. args : tuple, optional Extra arguments passed to the objective function and its gradient. kwargs Additional parameters of the minimization method. """ # Invert sign of fun(x) and grad(x) and run minimize # We use def statements and partial to respect PEP8 and scopes def fun_inv(wrapped_fun, z, *f_args, **f_kwargs): return -wrapped_fun(z, *f_args, **f_kwargs) def grad_inv(wrapped_grad, z, *f_args, **f_kwargs): return -wrapped_grad(z, *f_args, **f_kwargs) self._fun = CFunction( fun=partial(fun_inv, self._f.fun), gradient=partial(grad_inv, self._f.gradient) ) x = self.minimize(x_init, args=args, **kwargs) # fix solution variables self._f_seq = -self._f_seq # restore fun to its default self._fun = self.f return x