Source code for triqs_maxent.cost_functions.cost_function

# 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/>.



from ..functions import DoublyDerivableFunction, cached, \
    NormalChi2, NormalEntropy, NormalH_of_v, IdentityA_of_H


[docs] class CostFunction(DoublyDerivableFunction): r""" The base class for the function to be minimized Parameters ---------- chi2 : Chi2 the expression for chi2 (e.g. :py:class:`.NormalChi2`) S : Entropy the expression for S (e.g. :py:class:`.NormalEntropy`) H_of_v : H_of_v the expression for :math:`H(v)` (e.g. :py:class:`.NormalH_of_v`) A_of_H : A_of_H the expression for :math:`A(H)` (e.g. :py:class:`.IdentityA_of_H`) chi2_factor : float an additional factor for the :math:`\chi^2` term of the cost function (default: 1.0) """ def __init__(self, chi2=None, S=None, H_of_v=None, A_of_H=None, chi2_factor=1.0): self._chi2 = chi2 self._S = S self._H_of_v = H_of_v self._A_of_H = A_of_H self.chi2_factor = chi2_factor if self._chi2 is None: self._chi2 = NormalChi2() if self._S is None: self._S = NormalEntropy() if self._H_of_v is None: self._H_of_v = NormalH_of_v() if self._A_of_H is None: omega = None try: omega = self._chi2.omega except: pass self._A_of_H = IdentityA_of_H(omega) self._alpha = None
[docs] def set_alpha(self, alpha): """ Set the hyper-parameter. """ self._alpha = alpha
def __call__(self, x): ret = super(CostFunction, self).__call__(x) ret._H_of_v = ret.H_of_v(ret._x) H = ret._H_of_v.f() ret._A_of_H = ret.A_of_H(H) # we explicitly set it to the same object ret._H_of_v._x = ret._x ret._A_of_H._x = H ret._chi2 = ret.chi2(H) ret._chi2._x = H ret._S = ret.S(H) ret._S._x = H return ret
[docs] def f(self, v): r""" Calculate the function to be minimized, :math:`Q_{\alpha}(v)`. Parameters ========== v : array vector in singular space giving the solution; if None, the last supplied value should be reused """ raise NotImplementedError('Please use a subclass of CostFunction.')
[docs] def d(self, v): r""" Calculate the derivative of the function to be minimized Parameters ========== v : array vector in singular space giving the solution if None, the last supplied value should be reused """ raise NotImplementedError('Please use a subclass of CostFunction.')
[docs] def dd(self, v): r""" Calculate the 2nd derivative of the function to be minimized Parameters ========== v : array vector in singular space giving the solution if None, the last supplied value should be reused """ raise NotImplementedError('Please use a subclass of CostFunction.')
[docs] def parameter_change(self): pass
####### Helper functions ####### def get_K(self): return self.chi2.K def set_K(self, K, update_chi2=True, update_H_of_v=True, update_Q=True): self.chi2.set_K(K, update_chi2=update_chi2) self.H_of_v.set_K(K, update_H_of_v=update_H_of_v) if update_Q: self.parameter_change() K = property(get_K, set_K) def get_G(self): return self.chi2.G def set_G(self, G, update_chi2=True, update_Q=True): self.chi2.set_G(G, update_chi2=update_chi2) if update_Q: self.parameter_change() G = property(get_G, set_G) def get_err(self): return self.chi2.err def set_err(self, err, update_chi2=True, update_Q=True): self.chi2.set_err(err, update_chi2=update_chi2) if update_Q: self.parameter_change() err = property(get_err, set_err) def get_omega(self): return self.chi2.K.omega def set_omega(self, omega, update_K=True, update_chi2=True, update_D=True, update_S=True, update_H_of_v=True, update_A_of_H=True, update_Q=True): self.chi2.set_omega(omega, update_K=update_K, update_chi2=update_chi2) if update_K: # we use update_H_of_v = False here, because it gets updated # anyhow when omega is set later on self.H_of_v.set_K(self.K, update_H_of_v=False) self.S.set_omega(omega, update_D=update_D, update_S=update_S) self.H_of_v.set_omega(omega, update_D=update_D, update_H_of_v=update_H_of_v) self.A_of_H.set_omega(omega, update_A_of_H=update_A_of_H) if update_Q: self.parameter_change() omega = property(get_omega, set_omega) # ``data_variable`` is a name we use for tau # because in general we might want to use a different kernel # and then the supplied data is not G(tau) but, eg, G(iw) def get_data_variable(self): return self.chi2.K.data_variable def set_data_variable(self, data_variable, update_K=True, update_chi2=True, update_Q=True, update_H_of_v=True): self.chi2.set_data_variable(data_variable, update_K=update_K, update_chi2=update_chi2) if update_K: self.H_of_v.set_K(self.K, update_H_of_v=update_H_of_v) if update_Q: self.parameter_change() data_variable = property(get_data_variable, set_data_variable) def get_D(self): return self.S.D def set_D(self, D, update_S=True, update_H_of_v=True, update_Q=True, update_A_of_H=True): self.S.set_D(D, update_S=update_S) self.H_of_v.set_D(D, update_H_of_v=update_H_of_v) self.A_of_H.set_omega(D.omega, update_A_of_H=update_A_of_H) if update_Q: self.parameter_change() D = property(get_D, set_D) def get_chi2(self): return self._chi2 def set_chi2(self, chi2, update_Q=True): self._chi2 = chi2 if update_Q: self.parameter_change() chi2 = property(get_chi2, set_chi2) def get_S(self): return self._S def set_S(self, S, update_Q=True): self._S = S if update_Q: self.parameter_change() S = property(get_S, set_S) def get_H_of_v(self): return self._H_of_v def set_H_of_v(self, H_of_v, update_Q=True): self._H_of_v = H_of_v if update_Q: self.parameter_change() H_of_v = property(get_H_of_v, set_H_of_v) def get_A_of_H(self): return self._A_of_H def set_A_of_H(self, A_of_H, update_Q=True): self._A_of_H = A_of_H if update_Q: self.parameter_change() A_of_H = property(get_A_of_H, set_A_of_H) @property def G_orig(self): if hasattr(self, "_G_orig"): return self._G_orig else: return self.G