Commit 550aee99 authored by Martin Reinecke's avatar Martin Reinecke
Browse files

Merge remote-tracking branch 'origin/NIFTy_5' into fft_tweaks

parents f60c348b 3996cb92
...@@ -19,7 +19,7 @@ There is a full toolbox of methods that can be used, like the classical approxim ...@@ -19,7 +19,7 @@ There is a full toolbox of methods that can be used, like the classical approxim
.. [3] T.A. Enßlin (2014), "Astrophysical data analysis with information field theory", AIP Conference Proceedings, Volume 1636, Issue 1, p.49; `arXiv:1405.7701 <http://arxiv.org/abs/1405.7701>`_ .. [3] T.A. Enßlin (2014), "Astrophysical data analysis with information field theory", AIP Conference Proceedings, Volume 1636, Issue 1, p.49; `arXiv:1405.7701 <http://arxiv.org/abs/1405.7701>`_
.. [4] Wikipedia contributors (2018), `"Information field theory" <https://en.wikipedia.org/w/index.php?title=Information_field_theory&oldid=876731720>`_, Wikipedia, The Free Encyclopedia. .. [4] Wikipedia contributors (2018), `"Information field theory" <https://en.wikipedia.org/w/index.php?title=Information_field_theory&oldid=876731720>`_, Wikipedia, The Free Encyclopedia.
.. [5] T.A. Enßlin (2019), "Information theory for fields", accepted by Annalen der Physik; `arXiv:1804.03350 <http://arxiv.org/abs/1804.03350>`_ .. [5] T.A. Enßlin (2019), "Information theory for fields", accepted by Annalen der Physik; `arXiv:1804.03350 <http://arxiv.org/abs/1804.03350>`_
...@@ -85,7 +85,7 @@ The above line of argumentation analogously applies to the discretization of ope ...@@ -85,7 +85,7 @@ The above line of argumentation analogously applies to the discretization of ope
The proper discretization of spaces, fields, and operators, as well as the normalization of position integrals, is essential for the conservation of the continuum limit. Their consistent implementation in NIFTY allows a pixelization independent coding of algorithms. The proper discretization of spaces, fields, and operators, as well as the normalization of position integrals, is essential for the conservation of the continuum limit. Their consistent implementation in NIFTY allows a pixelization independent coding of algorithms.
Free Theory & Implicit Operators Free Theory & Implicit Operators
-------------------------------- --------------------------------
A free IFT appears when the signal field :math:`{s}` and the noise :math:`{n}` of the data :math:`{d}` are independent, zero-centered Gaussian processes of kown covariances :math:`{S}` and :math:`{N}`, respectively, A free IFT appears when the signal field :math:`{s}` and the noise :math:`{n}` of the data :math:`{d}` are independent, zero-centered Gaussian processes of kown covariances :math:`{S}` and :math:`{N}`, respectively,
...@@ -94,7 +94,7 @@ A free IFT appears when the signal field :math:`{s}` and the noise :math:`{n}` o ...@@ -94,7 +94,7 @@ A free IFT appears when the signal field :math:`{s}` and the noise :math:`{n}` o
\mathcal{P}(s,n) = \mathcal{G}(s,S)\,\mathcal{G}(n,N), \mathcal{P}(s,n) = \mathcal{G}(s,S)\,\mathcal{G}(n,N),
and the measurement equation is linear in both, signal and noise, and the measurement equation is linear in both signal and noise,
.. math:: .. math::
...@@ -109,15 +109,15 @@ associate professor ...@@ -109,15 +109,15 @@ associate professor
\mathcal{H}(d,s)= -\log \mathcal{P}(d,s)= \frac{1}{2} s^\dagger S^{-1} s + \frac{1}{2} (d-R\,s)^\dagger N^{-1} (d-R\,s) + \mathrm{const} \mathcal{H}(d,s)= -\log \mathcal{P}(d,s)= \frac{1}{2} s^\dagger S^{-1} s + \frac{1}{2} (d-R\,s)^\dagger N^{-1} (d-R\,s) + \mathrm{const}
is only of quadratic order in :math:`{s}`, which leads to a linear relation between the data and the posterior mean field. is only of quadratic order in :math:`{s}`, which leads to a linear relation between the data and the posterior mean field.
In this case, the posterior is In this case, the posterior is
.. math:: .. math::
\mathcal{P}(s|d) = \mathcal{G}(s-m,D) \mathcal{P}(s|d) = \mathcal{G}(s-m,D)
with with
.. math:: .. math::
...@@ -129,7 +129,7 @@ the posterior mean field, ...@@ -129,7 +129,7 @@ the posterior mean field,
D = \left( S^{-1} + R^\dagger N^{-1} R\right)^{-1} D = \left( S^{-1} + R^\dagger N^{-1} R\right)^{-1}
the posterior covariance operator, and the posterior covariance operator, and
.. math:: .. math::
...@@ -137,7 +137,7 @@ the posterior covariance operator, and ...@@ -137,7 +137,7 @@ the posterior covariance operator, and
the information source. The operation in :math:`{d= D\,R^\dagger N^{-1} d}` is also called the generalized Wiener filter. the information source. The operation in :math:`{d= D\,R^\dagger N^{-1} d}` is also called the generalized Wiener filter.
NIFTy permits to define the involved operators :math:`{R}`, :math:`{R^\dagger}`, :math:`{S}`, and :math:`{N}` implicitely, as routines that can be applied to vectors, but which do not require the explicit storage of the matrix elements of the operators. NIFTy permits to define the involved operators :math:`{R}`, :math:`{R^\dagger}`, :math:`{S}`, and :math:`{N}` implicitely, as routines that can be applied to vectors, but which do not require the explicit storage of the matrix elements of the operators.
Some of these operators are diagonal in harmonic (Fourier) basis, and therefore only require the specification of a (power) spectrum and :math:`{S= F\,\widehat{P_s} F^\dagger}`. Here :math:`{F = \mathrm{HarmonicTransformOperator}}`, :math:`{\widehat{P_s} = \mathrm{DiagonalOperator}(P_s)}`, and :math:`{P_s(k)}` is the power spectrum of the process that generated :math:`{s}` as a function of the (absolute value of the) harmonic (Fourier) space koordinate :math:`{k}`. For those, NIFTy can easily also provide inverse operators, as :math:`{S^{-1}= F\,\widehat{\frac{1}{P_s}} F^\dagger}` in case :math:`{F}` is unitary, :math:`{F^\dagger=F^{-1}}`. Some of these operators are diagonal in harmonic (Fourier) basis, and therefore only require the specification of a (power) spectrum and :math:`{S= F\,\widehat{P_s} F^\dagger}`. Here :math:`{F = \mathrm{HarmonicTransformOperator}}`, :math:`{\widehat{P_s} = \mathrm{DiagonalOperator}(P_s)}`, and :math:`{P_s(k)}` is the power spectrum of the process that generated :math:`{s}` as a function of the (absolute value of the) harmonic (Fourier) space koordinate :math:`{k}`. For those, NIFTy can easily also provide inverse operators, as :math:`{S^{-1}= F\,\widehat{\frac{1}{P_s}} F^\dagger}` in case :math:`{F}` is unitary, :math:`{F^\dagger=F^{-1}}`.
...@@ -170,7 +170,7 @@ The joint information Hamiltonian for the whitened signal field :math:`{\xi}` re ...@@ -170,7 +170,7 @@ The joint information Hamiltonian for the whitened signal field :math:`{\xi}` re
\mathcal{H}(d,\xi)= -\log \mathcal{P}(d,s)= \frac{1}{2} \xi^\dagger \xi + \frac{1}{2} (d-R\,A\,\xi)^\dagger N^{-1} (d-R\,A\,\xi) + \mathrm{const}. \mathcal{H}(d,\xi)= -\log \mathcal{P}(d,s)= \frac{1}{2} \xi^\dagger \xi + \frac{1}{2} (d-R\,A\,\xi)^\dagger N^{-1} (d-R\,A\,\xi) + \mathrm{const}.
NIFTy takes advantage of this formulation in several ways: NIFTy takes advantage of this formulation in several ways:
1) All prior degrees of freedom have unit covariance which improves the condition number of operators which need to be inverted. 1) All prior degrees of freedom have unit covariance which improves the condition number of operators which need to be inverted.
2) The amplitude operator can be regarded as part of the response, :math:`{R'=R\,A}`. In general, more sophisticated responses can be constructed out of the composition of simpler operators. 2) The amplitude operator can be regarded as part of the response, :math:`{R'=R\,A}`. In general, more sophisticated responses can be constructed out of the composition of simpler operators.
......
...@@ -46,9 +46,10 @@ from .operators.outer_product_operator import OuterProduct ...@@ -46,9 +46,10 @@ from .operators.outer_product_operator import OuterProduct
from .operators.simple_linear_operators import ( from .operators.simple_linear_operators import (
VdotOperator, ConjugationOperator, Realizer, VdotOperator, ConjugationOperator, Realizer,
FieldAdapter, ducktape, GeometryRemover, NullOperator) FieldAdapter, ducktape, GeometryRemover, NullOperator)
from .operators.value_inserter import ValueInserter
from .operators.energy_operators import ( from .operators.energy_operators import (
EnergyOperator, GaussianEnergy, PoissonianEnergy, InverseGammaLikelihood, EnergyOperator, GaussianEnergy, PoissonianEnergy, InverseGammaLikelihood,
BernoulliEnergy, Hamiltonian, SampledKullbachLeiblerDivergence) BernoulliEnergy, Hamiltonian, AveragedEnergy)
from .probing import probe_with_posterior_samples, probe_diagonal, \ from .probing import probe_with_posterior_samples, probe_diagonal, \
StatCalculator StatCalculator
......
...@@ -442,7 +442,7 @@ class Field(object): ...@@ -442,7 +442,7 @@ class Field(object):
---------- ----------
spaces : None, int or tuple of int spaces : None, int or tuple of int
The summation is only carried out over the sub-domains in this The summation is only carried out over the sub-domains in this
tuple. If None, it is carried out over all sub-domains. Default: None. tuple. If None, it is carried out over all sub-domains.
Returns Returns
------- -------
...@@ -463,7 +463,6 @@ class Field(object): ...@@ -463,7 +463,6 @@ class Field(object):
spaces : None, int or tuple of int spaces : None, int or tuple of int
The summation is only carried out over the sub-domains in this The summation is only carried out over the sub-domains in this
tuple. If None, it is carried out over all sub-domains. tuple. If None, it is carried out over all sub-domains.
Default: None.
Returns Returns
------- -------
...@@ -547,7 +546,7 @@ class Field(object): ...@@ -547,7 +546,7 @@ class Field(object):
---------- ----------
spaces : None, int or tuple of int spaces : None, int or tuple of int
The operation is only carried out over the sub-domains in this The operation is only carried out over the sub-domains in this
tuple. If None, it is carried out over all sub-domains. Default: None. tuple. If None, it is carried out over all sub-domains.
Returns Returns
------- -------
......
...@@ -34,7 +34,7 @@ def _float_or_listoffloat(inp): ...@@ -34,7 +34,7 @@ def _float_or_listoffloat(inp):
return [float(x) for x in inp] if isinstance(inp, list) else float(inp) return [float(x) for x in inp] if isinstance(inp, list) else float(inp)
def _make_dynamic_operator(domain, def _make_dynamic_operator(target,
harmonic_padding, harmonic_padding,
sm_s0, sm_s0,
sm_x0, sm_x0,
...@@ -44,8 +44,10 @@ def _make_dynamic_operator(domain, ...@@ -44,8 +44,10 @@ def _make_dynamic_operator(domain,
minimum_phase, minimum_phase,
sigc=None, sigc=None,
quant=None): quant=None):
if not isinstance(domain, RGSpace): if not isinstance(target, RGSpace):
raise TypeError("RGSpace required") raise TypeError("RGSpace required")
if not target.harmonic:
raise TypeError("Target space must be harmonic")
if not (isinstance(harmonic_padding, int) or harmonic_padding is None if not (isinstance(harmonic_padding, int) or harmonic_padding is None
or all(isinstance(ii, int) for ii in harmonic_padding)): or all(isinstance(ii, int) for ii in harmonic_padding)):
raise TypeError raise TypeError
...@@ -62,7 +64,7 @@ def _make_dynamic_operator(domain, ...@@ -62,7 +64,7 @@ def _make_dynamic_operator(domain,
if cone and (sigc is None or quant is None): if cone and (sigc is None or quant is None):
raise RuntimeError raise RuntimeError
dom = DomainTuple.make(domain) dom = DomainTuple.make(target.get_default_codomain())
ops = {} ops = {}
FFT = FFTOperator(dom) FFT = FFTOperator(dom)
Real = Realizer(dom) Real = Realizer(dom)
...@@ -134,7 +136,8 @@ def _make_dynamic_operator(domain, ...@@ -134,7 +136,8 @@ def _make_dynamic_operator(domain,
return m, ops return m, ops
def dynamic_operator(domain, def dynamic_operator(*,
target,
harmonic_padding, harmonic_padding,
sm_s0, sm_s0,
sm_x0, sm_x0,
...@@ -143,11 +146,22 @@ def dynamic_operator(domain, ...@@ -143,11 +146,22 @@ def dynamic_operator(domain,
minimum_phase=False): minimum_phase=False):
'''Constructs an operator encoding the Green's function of a linear '''Constructs an operator encoding the Green's function of a linear
homogeneous dynamic system. homogeneous dynamic system.
When evaluated, this operator returns the Green's function representation
in harmonic space. This result can be used as a convolution kernel to
construct solutions of the homogeneous stochastic differential equation
encoded in this operator. Note that if causal is True, the Green's function
is convolved with a step function in time, where the temporal axis is the
first axis of the space. In this case the resulting function only extends
up to half the length of the first axis of the space to avoid boundary
effects during convolution. If minimum_phase is true then the spectrum of
the Green's function is used to construct a corresponding minimum phase
filter.
Parameters Parameters
---------- ----------
domain : RGSpace target : RGSpace
The position space in which the Green's function shall be constructed. The harmonic space in which the Green's function shall be constructed.
harmonic_padding : None, int, list of int harmonic_padding : None, int, list of int
Amount of central padding in harmonic space in pixels. If None the Amount of central padding in harmonic space in pixels. If None the
field is not padded at all. field is not padded at all.
...@@ -159,13 +173,15 @@ def dynamic_operator(domain, ...@@ -159,13 +173,15 @@ def dynamic_operator(domain,
key for dynamics encoding parameter. key for dynamics encoding parameter.
causal : boolean causal : boolean
Whether or not the Green's function shall be causal in time. Whether or not the Green's function shall be causal in time.
Default is True.
minimum_phase: boolean minimum_phase: boolean
Whether or not the Green's function shall be a minimum phase filter. Whether or not the Green's function shall be a minimum phase filter.
Default is False.
Returns Returns
------- -------
Operator Operator
The Operator encoding the dynamic Green's function in harmonic space. The Operator encoding the dynamic Green's function in target space.
Dictionary of Operator Dictionary of Operator
A collection of sub-chains of Operator which can be used for plotting A collection of sub-chains of Operator which can be used for plotting
and evaluation. and evaluation.
...@@ -175,7 +191,7 @@ def dynamic_operator(domain, ...@@ -175,7 +191,7 @@ def dynamic_operator(domain,
The first axis of the domain is interpreted the time axis. The first axis of the domain is interpreted the time axis.
''' '''
dct = { dct = {
'domain': domain, 'target': target,
'harmonic_padding': harmonic_padding, 'harmonic_padding': harmonic_padding,
'sm_s0': sm_s0, 'sm_s0': sm_s0,
'sm_x0': sm_x0, 'sm_x0': sm_x0,
...@@ -187,7 +203,8 @@ def dynamic_operator(domain, ...@@ -187,7 +203,8 @@ def dynamic_operator(domain,
return _make_dynamic_operator(**dct) return _make_dynamic_operator(**dct)
def dynamic_lightcone_operator(domain, def dynamic_lightcone_operator(*,
target,
harmonic_padding, harmonic_padding,
sm_s0, sm_s0,
sm_x0, sm_x0,
...@@ -199,11 +216,16 @@ def dynamic_lightcone_operator(domain, ...@@ -199,11 +216,16 @@ def dynamic_lightcone_operator(domain,
minimum_phase=False): minimum_phase=False):
'''Extends the functionality of :function: dynamic_operator to a Green's '''Extends the functionality of :function: dynamic_operator to a Green's
function which is constrained to be within a light cone. function which is constrained to be within a light cone.
The resulting Green's function is constrained to be within a light cone.
This is achieved via convolution of the function with a light cone in
space-time. Thereby the first axis of the space is set to be the teporal
axis.
Parameters Parameters
---------- ----------
domain : RGSpace target : RGSpace
The position space in which the Green's function shall be constructed. The harmonic space in which the Green's function shall be constructed.
It needs to have at least two dimensions. It needs to have at least two dimensions.
harmonic_padding : None, int, list of int harmonic_padding : None, int, list of int
Amount of central padding in harmonic space in pixels. If None the Amount of central padding in harmonic space in pixels. If None the
...@@ -222,8 +244,10 @@ def dynamic_lightcone_operator(domain, ...@@ -222,8 +244,10 @@ def dynamic_lightcone_operator(domain,
Quantization of the light cone in pixels. Quantization of the light cone in pixels.
causal : boolean causal : boolean
Whether or not the Green's function shall be causal in time. Whether or not the Green's function shall be causal in time.
Default is True.
minimum_phase: boolean minimum_phase: boolean
Whether or not the Green's function shall be a minimum phase filter. Whether or not the Green's function shall be a minimum phase filter.
Default is False.
Returns Returns
------- -------
...@@ -238,10 +262,10 @@ def dynamic_lightcone_operator(domain, ...@@ -238,10 +262,10 @@ def dynamic_lightcone_operator(domain,
The first axis of the domain is interpreted the time axis. The first axis of the domain is interpreted the time axis.
''' '''
if len(domain.shape) < 2: if len(target.shape) < 2:
raise ValueError("Space must be at least 2 dimensional!") raise ValueError("Space must be at least 2 dimensional!")
dct = { dct = {
'domain': domain, 'target': target,
'harmonic_padding': harmonic_padding, 'harmonic_padding': harmonic_padding,
'sm_s0': sm_s0, 'sm_s0': sm_s0,
'sm_x0': sm_x0, 'sm_x0': sm_x0,
......
...@@ -187,6 +187,18 @@ class Linearization(object): ...@@ -187,6 +187,18 @@ class Linearization(object):
return self.__mul__(other) return self.__mul__(other)
def outer(self, other): def outer(self, other):
"""Computes the outer product of this Linearization with a Field or
another Linearization
Parameters
----------
other : Field or MultiField or Linearization
Returns
-------
Linearization
the outer product of self and other
"""
from .operators.outer_product_operator import OuterProduct from .operators.outer_product_operator import OuterProduct
if isinstance(other, Linearization): if isinstance(other, Linearization):
return self.new( return self.new(
...@@ -200,6 +212,18 @@ class Linearization(object): ...@@ -200,6 +212,18 @@ class Linearization(object):
OuterProduct(self._jac(self._val), other.domain)) OuterProduct(self._jac(self._val), other.domain))
def vdot(self, other): def vdot(self, other):
"""Computes the inner product of this Linearization with a Field or
another Linearization
Parameters
----------
other : Field or MultiField or Linearization
Returns
-------
Linearization
the inner product of self and other
"""
from .operators.simple_linear_operators import VdotOperator from .operators.simple_linear_operators import VdotOperator
if isinstance(other, (Field, MultiField)): if isinstance(other, (Field, MultiField)):
return self.new( return self.new(
...@@ -211,6 +235,19 @@ class Linearization(object): ...@@ -211,6 +235,19 @@ class Linearization(object):
VdotOperator(other._val)(self._jac)) VdotOperator(other._val)(self._jac))
def sum(self, spaces=None): def sum(self, spaces=None):
"""Computes the (partial) sum over self
Parameters
----------
spaces : None, int or list of int
- if None, sum over the entire domain
- else sum over the specified subspaces
Returns
-------
Linearization
the (partial) sum
"""
from .operators.contraction_operator import ContractionOperator from .operators.contraction_operator import ContractionOperator
if spaces is None: if spaces is None:
return self.new( return self.new(
...@@ -222,6 +259,19 @@ class Linearization(object): ...@@ -222,6 +259,19 @@ class Linearization(object):
ContractionOperator(self._jac.target, spaces)(self._jac)) ContractionOperator(self._jac.target, spaces)(self._jac))
def integrate(self, spaces=None): def integrate(self, spaces=None):
"""Computes the (partial) integral over self
Parameters
----------
spaces : None, int or list of int
- if None, integrate over the entire domain
- else integrate over the specified subspaces
Returns
-------
Linearization
the (partial) integral
"""
from .operators.contraction_operator import ContractionOperator from .operators.contraction_operator import ContractionOperator
if spaces is None: if spaces is None:
return self.new( return self.new(
...@@ -309,18 +359,72 @@ class Linearization(object): ...@@ -309,18 +359,72 @@ class Linearization(object):
@staticmethod @staticmethod
def make_var(field, want_metric=False): def make_var(field, want_metric=False):
"""Converts a Field to a Linearization, with a unity Jacobian
Parameters
----------
field : Field or Multifield
the field to be converted
want_metric : bool
If True, the metric will be computed for other Linearizations
derived from this one. Default: False.
Returns
-------
Linearization
the requested Linearization
"""
from .operators.scaling_operator import ScalingOperator from .operators.scaling_operator import ScalingOperator
return Linearization(field, ScalingOperator(1., field.domain), return Linearization(field, ScalingOperator(1., field.domain),
want_metric=want_metric) want_metric=want_metric)
@staticmethod @staticmethod
def make_const(field, want_metric=False): def make_const(field, want_metric=False):
"""Converts a Field to a Linearization, with a zero Jacobian
Parameters
----------
field : Field or Multifield
the field to be converted
want_metric : bool
If True, the metric will be computed for other Linearizations
derived from this one. Default: False.
Returns
-------
Linearization
the requested Linearization
Notes
-----
The Jacobian is square and contains only zeroes.
"""
from .operators.simple_linear_operators import NullOperator from .operators.simple_linear_operators import NullOperator
return Linearization(field, NullOperator(field.domain, field.domain), return Linearization(field, NullOperator(field.domain, field.domain),
want_metric=want_metric) want_metric=want_metric)
@staticmethod @staticmethod
def make_const_empty_input(field, want_metric=False): def make_const_empty_input(field, want_metric=False):
"""Converts a Field to a Linearization, with a zero Jacobian
Parameters
----------
field : Field or Multifield
the field to be converted
want_metric : bool
If True, the metric will be computed for other Linearizations
derived from this one. Default: False.
Returns
-------
Linearization
the requested Linearization
Notes
-----
The Jacobian has an empty input domain, i.e. its matrix representation
has 0 columns.
"""
from .operators.simple_linear_operators import NullOperator from .operators.simple_linear_operators import NullOperator
from .multi_domain import MultiDomain from .multi_domain import MultiDomain
return Linearization( return Linearization(
...@@ -329,6 +433,29 @@ class Linearization(object): ...@@ -329,6 +433,29 @@ class Linearization(object):
@staticmethod @staticmethod
def make_partial_var(field, constants, want_metric=False): def make_partial_var(field, constants, want_metric=False):
"""Converts a MultiField to a Linearization, with a Jacobian that is
unity for some MultiField components and a zero matrix for others.
Parameters
----------
field : Multifield
the field to be converted
constants : list of string
the MultiField components for which the Jacobian should be
a zero matrix.
want_metric : bool
If True, the metric will be computed for other Linearizations
derived from this one. Default: False.
Returns
-------
Linearization
the requested Linearization
Notes
-----
The Jacobian is square.
"""
from .operators.scaling_operator import ScalingOperator from .operators.scaling_operator import ScalingOperator
from .operators.block_diagonal_operator import BlockDiagonalOperator from .operators.block_diagonal_operator import BlockDiagonalOperator
if len(constants) == 0: if len(constants) == 0:
......
...@@ -15,11 +15,14 @@ ...@@ -15,11 +15,14 @@
# #
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik. # NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
import numpy as np
from .. import utilities from .. import utilities
from ..domain_tuple import DomainTuple from ..domain_tuple import DomainTuple
from ..field import Field from ..field import Field
from ..linearization import Linearization from ..linearization import Linearization
from ..sugar import makeOp, makeDomain from ..sugar import makeDomain, makeOp
from .linear_operator import LinearOperator
from .operator import Operator from .operator import Operator
from .sampling_enabler import SamplingEnabler from .sampling_enabler import SamplingEnabler
from .sandwich_operator import SandwichOperator from .sandwich_operator import SandwichOperator
...@@ -27,11 +30,28 @@ from .simple_linear_operators import VdotOperator ...@@ -27,11 +30,28 @@ from .simple_linear_operators import VdotOperator
class EnergyOperator(Operator): class EnergyOperator(Operator):
"""Operator which has a scalar domain as target domain.""" """Operator which has a scalar domain as target domain.
It is intended as an objective function for field inference.
Examples
--------
- Information Hamiltonian, i.e. negative-log-probabilities.
- Gibbs free energy, i.e. an averaged Hamiltonian, aka Kullbach-Leibler
divergence.
"""
_target = DomainTuple.scalar_domain() _target = DomainTuple.scalar_domain()
class SquaredNormOperator(EnergyOperator):