Commit 50c56bdd authored by Martin Reinecke's avatar Martin Reinecke
Browse files

add documentation to LinearOperator

parent 2e5933f5
Pipeline #24642 passed with stage
in 12 minutes and 34 seconds
......@@ -31,40 +31,38 @@ From such a perspective,
- IFT problems largely consist of *minimization* problems involving a large number of equations.
- The equations are built mostly from the application of *linear operators*, but there may also be nonlinear functions involved.
- The unknowns in the equations represent either continuous physical *fields*, or they are simply individual measured *data* points.
- The locations and volume elements attached to discretized *field* values are supplied by *domain* objects. There are many variants of such discretized *domain* supported by NIFTy4, including Cartesian and spherical geometries and their harmonic counterparts. *Fields* can live on arbitrary products of such *domains*.
- The locations and volume elements attached to discretized *field* values are supplied by *domain* objects. There are many variants of such discretized *domain*s supported by NIFTy4, including Cartesian and spherical geometries and their harmonic counterparts. *Fields* can live on arbitrary products of such *domains*.
In the following sections, the concepts briefly presented here will be discussed in more detail; this is done in reversed order of their introduction, to avoid forward references.
.. _domainobjects:
.. _domains:
DomainObjects
.............
Domains
.......
One of the fundamental building blocks of the NIFTy4 framework is the /domain/.
Its required capabilities are expressed by the abstract :py:class:`DomainObject` class.
Its required capabilities are expressed by the abstract :py:class:`Domain` class.
A domain must be able to answer the following queries:
- its total number of data entries (pixels)
- the shape of the array that is supposed to hold them
- equality/inequality to another :py:class:`DomainObject` instance
.. _domains:
- equality/inequality to another :py:class:`Domain` instance
Unstructured domains
....................
There are domains (e.g. the data domain) which have no geometry associated to the individual data values.
In NIFTy4 they are represented by the :py:class:`UnstructuredDomain` class, which is derived from
:py:class:`DomainObject`.
:py:class:`Domain`.
Structured domains
..................
All domains defined on a geometrical manifold are derived from :py:class:`StructuredDomain` (which is in turn derived from :py:class:`DomainObject`).
All domains defined on a geometrical manifold are derived from :py:class:`StructuredDomain` (which is in turn derived from :py:class:`Domain`).
In addition to the capabilities of :py:class:`DomainObject`, :py:class:`StructuredDomain` offers the following functionality:
In addition to the capabilities of :py:class:`Domain`, :py:class:`StructuredDomain` offers the following functionality:
- methods returing the pixel volume(s) and the total volume
- a :py:attr:`harmonic` property
......
......@@ -25,6 +25,11 @@ import numpy as np
class LinearOperator(with_metaclass(
NiftyMeta, type('NewBase', (object,), {}))):
"""NIFTY base class for linear operators.
The base NIFTY operator class is an abstract class from which
other specific operator subclasses are derived.
"""
_validMode = (False, True, True, False, True, False, False, False, True)
_inverseMode = (0, 4, 8, 0, 1, 0, 0, 0, 2)
......@@ -71,11 +76,21 @@ class LinearOperator(with_metaclass(
@property
def inverse(self):
"""
inverse : LinearOperator
Returns a LinearOperator object which behaves as if it were
the inverse of this operator.
"""
from .inverse_operator import InverseOperator
return InverseOperator(self)
@property
def adjoint(self):
"""
adjoint : LinearOperator
Returns a LinearOperator object which behaves as if it were
the adjoint of this operator.
"""
from .adjoint_operator import AdjointOperator
return AdjointOperator(self)
......@@ -120,33 +135,116 @@ class LinearOperator(with_metaclass(
other = self._toOperator(other, self.domain)
return SumOperator.make(other, self, [False, True])
def supports(self, ops):
return False
@abc.abstractproperty
def capability(self):
""" Specifies the application modes supported by this operator
Returns
-------
out : integer
This is any subset of LinearOperator.{TIMES, ADJOINT_TIMES,
INVERSE_TIMES, ADJOINT_INVERSE_TIMES, INVERSE_ADJOINT_TIMES},
joined together by the "|" operator.
"""
raise NotImplementedError
@abc.abstractmethod
def apply(self, x, mode):
""" Applies the Operator to a given Field, in a specified mode.
Parameters
----------
x : Field
The input Field, living on the Operator's domain or target,
depending on mode.
mode : integer
LinearOperator.TIMES: normal application
LinearOperator.ADJOINT_TIMES: adjoint application
LinearOperator.INVERSE_TIMES: inverse application
LinearOperator.ADJOINT_INVERSE_TIMES or
LinearOperator.INVERSE_ADJOINT_TIMES:
adjoint inverse application
Returns
-------
out : Field
The processed Field living on the Operator's target or domain,
depending on mode.
"""
raise NotImplementedError
def __call__(self, x):
"""Same as times()"""
return self.apply(x, self.TIMES)
def times(self, x):
""" Applies the Operator to a given Field.
Parameters
----------
x : Field
The input Field, living on the Operator's domain.
Returns
-------
out : Field
The processed Field living on the Operator's target domain.
"""
return self.apply(x, self.TIMES)
def inverse_times(self, x):
"""Applies the inverse Operator to a given Field.
Parameters
----------
x : Field
The input Field, living on the Operator's target domain
Returns
-------
out : Field
The processed Field living on the Operator's domain.
"""
return self.apply(x, self.INVERSE_TIMES)
def adjoint_times(self, x):
"""Applies the adjoint-Operator to a given Field.
Parameters
----------
x : Field
The input Field, living on the Operator's target domain
Returns
-------
out : Field
The processed Field living on the Operator's domain.
"""
return self.apply(x, self.ADJOINT_TIMES)
def adjoint_inverse_times(self, x):
""" Applies the adjoint-inverse Operator to a given Field.
Parameters
----------
x : Field
The input Field, living on the Operator's domain.
Returns
-------
out : Field
The processed Field living on the Operator's target domain.
Notes
-----
If the operator has an `inverse` then the inverse adjoint is identical
to the adjoint inverse. We provide both names for convenience.
"""
return self.apply(x, self.ADJOINT_INVERSE_TIMES)
def inverse_adjoint_times(self, x):
"""Same as adjoint_inverse_times()"""
return self.apply(x, self.ADJOINT_INVERSE_TIMES)
def _check_mode(self, mode):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment