Source code for sfepy.solvers.solvers

"""
Base (abstract) solver classes.
"""
from sfepy.base.base import get_default, Struct

[docs]def make_get_conf(conf, kwargs): def _get_conf_item(name, default=None, msg_if_none=None): return kwargs.get(name, conf.get(name, default=default, msg_if_none=msg_if_none)) return _get_conf_item
[docs]class Solver(Struct): """ Base class for all solver kinds. Takes care of processing of common configuration options. The factory method any_from_conf() can be used to create an instance of any subclass. The subclasses have to reimplement __init__() and __call__(). The subclasses that implement process_conf() have to call Solver.process_conf(). All solvers use the following configuration parameters: Parameters ---------- name : str The name referred to in problem description options. kind : str The solver kind, as given by the `name` class attribute of the Solver subclasses. verbose : bool If True, the solver can print more information about the solution. """ @staticmethod
[docs] def process_conf(conf, kwargs=None): """ Ensures conf contains 'name' and 'kind'. """ get = conf.get name = get('name', None, 'missing "name" in options!') kind = get('kind', None, 'missing "kind" in options!') verbose = get('verbose', False) return Struct(name=name, kind=kind, verbose=verbose)
def __init__(self, conf=None, **kwargs): if conf is None: conf = Struct() elif isinstance(conf, dict): conf = Struct(**conf) if conf.get('name', None) is None: conf.name = 'auto_' + self.__class__.__name__ if conf.get('kind', None) is None: if hasattr(self.__class__, 'name'): conf.kind = self.__class__.name else: raise ValueError('solver kind cannot be determined!') new_conf = self.process_conf(conf, kwargs) Struct.__init__(self, conf=new_conf, orig_conf=conf, **kwargs) def __call__(self, **kwargs): raise ValueError('called an abstract Solver instance!')
[docs]class LinearSolver(Solver): """ Abstract linear solver class. """ def __init__(self, conf, mtx=None, status=None, **kwargs): Solver.__init__(self, conf=conf, mtx=mtx, status=status, **kwargs) def __call__(self, rhs, x0=None, conf=None, eps_a=None, eps_r=None, i_max=None, mtx=None, status=None, **kwargs): raise ValueError('called an abstract LinearSolver instance!')
[docs] def get_tolerance(self): """ Return tuple `(eps_a, eps_r)` of absolute and relative tolerance settings. Either value can be `None`, meaning that the solver does not use that setting. """ return self.conf.eps_a, self.conf.eps_r
[docs]class NonlinearSolver(Solver): """ Abstract nonlinear solver class. """ def __init__(self, conf, fun=None, fun_grad=None, lin_solver=None, iter_hook=None, status=None, **kwargs): Solver.__init__(self, conf=conf, fun=fun, fun_grad=fun_grad, lin_solver=lin_solver, iter_hook=iter_hook, status=status, **kwargs) def __call__(self, state0, conf=None, fun=None, fun_grad=None, lin_solver=None, iter_hook=None, status=None): raise ValueError('called an abstract NonlinearSolver instance!')
[docs]class TimeSteppingSolver(Solver): """ Abstract time stepping solver class. """ def __init__(self, conf, **kwargs): Solver.__init__(self, conf=conf, **kwargs) def __call__(self, state0=None, save_results=True, step_hook=None, post_process_hook=None, nls_status=None): raise ValueError('called an abstract TimeSteppingSolver instance!')
[docs]class OptimizationSolver(Solver): """ Abstract optimization solver class. """ def __init__(self, conf, obj_fun=None, obj_fun_grad=None, status=None, obj_args=None, **kwargs ): Solver.__init__(self, conf=conf, obj_fun=obj_fun, obj_fun_grad=obj_fun_grad, status=status, obj_args=obj_args, **kwargs) def __call__(self, state0, conf=None, obj_fun=None, obj_fun_grad=None, status=None, obj_args=None): raise ValueError('called an abstract OptimizationSolver instance!')
[docs]class EigenvalueSolver(Solver): """ Abstract eigenvalue solver class. """ def __init__(self, conf, mtx_a=None, mtx_b=None, n_eigs=None, eigenvectors=None, status=None): Solver.__init__(self, conf=conf, mtx_a=mtx_a, mtx_b=mtx_b, n_eigs=n_eigs, eigenvectors=eigenvectors, status=status) def __call__(self, mtx_a, mtx_b=None, n_eigs=None, eigenvectors=None, status=None, conf=None): raise ValueError('called an abstract EigenvalueSolver instance!') def _to_array(self, mtx_a, mtx_b=None): if hasattr(mtx_a, 'toarray'): mtx_a = mtx_a.toarray() if mtx_b is not None: if hasattr(mtx_b, 'toarray'): mtx_b = mtx_b.toarray() return mtx_a, mtx_b