Source code for triqs_maxent.minimizers.convergence_methods

# TRIQS application maxent
# Copyright (C) 2018 Gernot J. Kraberger
# Copyright (C) 2018 Simons Foundation
# Authors: Gernot J. Kraberger and Manuel Zingl
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.



import numpy as np


[docs] class ConvergenceMethod(object): """ A general convergence method When calling the convergence method, it returns a tuple ``(conv, is_conv)``, where ``conv`` measures the convergence and ``is_conv`` is a ``bool`` that tells whether convergence was reached. Two convergence methods can be combined using the `&` (and) and `|` (or) operators. """ def __and__(self, other): return AndConvergenceMethod(self, other) def __or__(self, other): return OrConvergenceMethod(self, other) def __call__(self, function, v, **kwargs): raise NotImplementedError( 'Please use a subclass of ConvergenceMethod.')
[docs] class AndConvergenceMethod(ConvergenceMethod): """The 'and' conjunction between two convergence methods.""" def __init__(self, one, two): self.one = one self.two = two def __call__(self, function, v, **kwargs): conv1, is_conv1 = self.one(function, v, **kwargs) conv2, is_conv2 = self.two(function, v, **kwargs) if np.isnan(conv1) or np.isnan(conv2): conv = np.nan else: conv = np.min((conv1, conv2)) return conv, is_conv1 or is_conv2
[docs] class OrConvergenceMethod(ConvergenceMethod): """The 'or' conjunction between two convergence methods.""" def __init__(self, one, two): self.one = one self.two = two def __call__(self, function, v, **kwargs): conv1, is_conv1 = self.one(function, v, **kwargs) conv2, is_conv2 = self.two(function, v, **kwargs) if np.isnan(conv1) or np.isnan(conv2): conv = np.nan else: conv = np.min((conv1, conv2)) return conv, is_conv1 or is_conv2
[docs] class MaxDerivativeConvergenceMethod(ConvergenceMethod): """The maximum of the derivative has to be < convergence criterion""" def __init__(self, convergence_criterion): self.convergence_criterion = convergence_criterion def __call__(self, function, v, **kwargs): conv = np.max(np.abs(function.d(v))) return conv, conv < self.convergence_criterion
[docs] class NullConvergenceMethod(ConvergenceMethod): """A convergence method that thinks everything is converged.""" def __call__(self, function, v, **kwargs): return 0, True
[docs] class FunctionChangeConvergenceMethod(ConvergenceMethod): """The function change between two subsequent iterations has to be < convergence criterion""" def __init__(self, convergence_criterion): self.convergence_criterion = convergence_criterion def __call__(self, function, v, **kwargs): assert 'Q0' in kwargs, 'argument Q0 missing' assert 'Q1' in kwargs, 'argument Q1 missing' conv = np.abs(kwargs['Q0'] - kwargs['Q1']) return conv, conv < self.convergence_criterion
[docs] class RelativeFunctionChangeConvergenceMethod(ConvergenceMethod): """The function change between two subsequent iterations divided by the function value has to be < convergence criterion""" def __init__(self, convergence_criterion): self.convergence_criterion = convergence_criterion def __call__(self, function, v, **kwargs): assert 'Q0' in kwargs, 'argument Q0 missing' assert 'Q1' in kwargs, 'argument Q1 missing' conv = np.abs(np.abs(kwargs['Q0'] - kwargs['Q1']) / kwargs['Q1']) return conv, conv < self.convergence_criterion