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, ...@@ -31,40 +31,38 @@ From such a perspective,
- IFT problems largely consist of *minimization* problems involving a large number of equations. - 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 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 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. 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/. 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: A domain must be able to answer the following queries:
- its total number of data entries (pixels) - its total number of data entries (pixels)
- the shape of the array that is supposed to hold them - the shape of the array that is supposed to hold them
- equality/inequality to another :py:class:`DomainObject` instance - equality/inequality to another :py:class:`Domain` instance
.. _domains:
Unstructured domains Unstructured domains
.................... ....................
There are domains (e.g. the data domain) which have no geometry associated to the individual data values. 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 In NIFTy4 they are represented by the :py:class:`UnstructuredDomain` class, which is derived from
:py:class:`DomainObject`. :py:class:`Domain`.
Structured domains 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 - methods returing the pixel volume(s) and the total volume
- a :py:attr:`harmonic` property - a :py:attr:`harmonic` property
......
...@@ -25,6 +25,11 @@ import numpy as np ...@@ -25,6 +25,11 @@ import numpy as np
class LinearOperator(with_metaclass( class LinearOperator(with_metaclass(
NiftyMeta, type('NewBase', (object,), {}))): 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) _validMode = (False, True, True, False, True, False, False, False, True)
_inverseMode = (0, 4, 8, 0, 1, 0, 0, 0, 2) _inverseMode = (0, 4, 8, 0, 1, 0, 0, 0, 2)
...@@ -71,11 +76,21 @@ class LinearOperator(with_metaclass( ...@@ -71,11 +76,21 @@ class LinearOperator(with_metaclass(
@property @property
def inverse(self): 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 from .inverse_operator import InverseOperator
return InverseOperator(self) return InverseOperator(self)
@property @property
def adjoint(self): 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 from .adjoint_operator import AdjointOperator
return AdjointOperator(self) return AdjointOperator(self)
...@@ -120,33 +135,116 @@ class LinearOperator(with_metaclass( ...@@ -120,33 +135,116 @@ class LinearOperator(with_metaclass(
other = self._toOperator(other, self.domain) other = self._toOperator(other, self.domain)
return SumOperator.make(other, self, [False, True]) return SumOperator.make(other, self, [False, True])
def supports(self, ops):
return False
@abc.abstractproperty @abc.abstractproperty
def capability(self): 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 raise NotImplementedError
@abc.abstractmethod @abc.abstractmethod
def apply(self, x, mode): 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 raise NotImplementedError
def __call__(self, x): def __call__(self, x):
"""Same as times()"""
return self.apply(x, self.TIMES) return self.apply(x, self.TIMES)
def times(self, x): 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) return self.apply(x, self.TIMES)
def inverse_times(self, x): 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) return self.apply(x, self.INVERSE_TIMES)
def adjoint_times(self, x): 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) return self.apply(x, self.ADJOINT_TIMES)
def adjoint_inverse_times(self, x): 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) return self.apply(x, self.ADJOINT_INVERSE_TIMES)
def inverse_adjoint_times(self, x): def inverse_adjoint_times(self, x):
"""Same as adjoint_inverse_times()"""
return self.apply(x, self.ADJOINT_INVERSE_TIMES) return self.apply(x, self.ADJOINT_INVERSE_TIMES)
def _check_mode(self, mode): 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