Commit 3d4b1b18 authored by Martin Reinecke's avatar Martin Reinecke
Browse files

more documentation, a few fixes

parent 3ad3e82b
Pipeline #23918 passed with stage
in 4 minutes and 42 seconds
...@@ -201,13 +201,13 @@ html_last_updated_fmt = '%b %d, %Y' ...@@ -201,13 +201,13 @@ html_last_updated_fmt = '%b %d, %Y'
html_domain_indices = False html_domain_indices = False
# If false, no index is generated. # If false, no index is generated.
#html_use_index = True html_use_index = False
# If true, the index is split into individual pages for each letter. # If true, the index is split into individual pages for each letter.
#html_split_index = False #html_split_index = False
# If true, links to the reST sources are added to the pages. # If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True html_show_sourcelink = False
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True #html_show_sphinx = True
......
NIFTy -- Numerical Information Field Theory NIFTy -- Numerical Information Field Theory
=========================================== ===========================================
**NIFTy** [1]_, "\ **N**\umerical **I**\nformation **F**\ield **T**\heor\ **y**\ ", is a versatile library designed to enable the development of signal inference algorithms that operate regardless of the underlying spatial grid and its resolution. Its object-oriented framework is written in Python, although it accesses libraries written in Cython, C++, and C for efficiency. **NIFTy** [1]_, "\ **N**\umerical **I**\nformation **F**\ield **T**\heor\ **y**\ ", is a versatile library designed to enable the development of signal inference algorithms that operate regardless of the underlying spatial grid and its resolution.
Its object-oriented framework is written in Python, although it accesses libraries written in C++ and C for efficiency.
NIFTy offers a toolkit that abstracts discretized representations of continuous spaces, fields in these spaces, and operators acting on fields into classes. Thereby, the correct normalization of operations on fields is taken care of automatically without concerning the user. This allows for an abstract formulation and programming of inference algorithms, including those derived within information field theory. Thus, NIFTy permits its user to rapidly prototype algorithms in 1D and then apply the developed code in higher-dimensional settings of real world problems. The set of spaces on which NIFTy operates comprises point sets, *n*-dimensional regular grids, spherical spaces, their harmonic counterparts, and product spaces constructed as combinations of those. NIFTy offers a toolkit that abstracts discretized representations of continuous spaces, fields in these spaces, and operators acting on fields into classes.
Thereby, the correct normalization of operations on fields is taken care of automatically without concerning the user.
This allows for an abstract formulation and programming of inference algorithms, including those derived within information field theory.
Thus, NIFTy permits its user to rapidly prototype algorithms in 1D and then apply the developed code in higher-dimensional settings of real world problems.
The set of spaces on which NIFTy operates comprises point sets, *n*-dimensional regular grids, spherical spaces, their harmonic counterparts, and product spaces constructed as combinations of those.
References References
---------- ----------
...@@ -27,6 +32,5 @@ Contents ...@@ -27,6 +32,5 @@ Contents
Indices and tables Indices and tables
.................. ..................
* :ref:`genindex`
* :any:`Module Index <mod/modules>` * :any:`Module Index <mod/modules>`
* :ref:`search` * :ref:`search`
...@@ -10,39 +10,76 @@ NIFTy4 Tutorial ...@@ -10,39 +10,76 @@ NIFTy4 Tutorial
.. automodule:: nifty4 .. automodule:: nifty4
NIFTy4 enables the programming of grid and resolution independent algorithms. In particular for signal inference algorithms, where a continuous signal field is to be recovered, this freedom is desirable. This is achieved with an object-oriented infrastructure that comprises, among others, abstract classes for :ref:`Spaces <spaces>`, :ref:`Fields <fields>`, and :ref:`Operators <operators>`. All those are covered in this tutorial. NIFTy4 enables the programming of grid and resolution independent algorithms.
In particular for signal inference algorithms, where a continuous signal field is to be recovered, this freedom is desirable.
It is achieved with an object-oriented infrastructure that comprises, among others, abstract classes for :ref:`Spaces <spaces>`, :ref:`Fields <fields>`, and :ref:`Operators <operators>`.
All those are covered in this tutorial.
You should be able to import NIFTy4 like this after a successful `installation <install.html>`_. You should be able to import NIFTy4 like this after a successful `installation <install.html>`_.
>>> import nifty4 as ift >>> import nifty4 as ift
.. _domainobjects:
DomainObjects
.............
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.
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
- the pixel volume(s)
- the total volume
- equality/unequality to another :py:class:`DomainObject` instance
.. _spaces: .. _spaces:
Spaces Unstructured spaces
...... ...................
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:`FieldArray` class, which is dreived from
:py:class:`DomainObject` and simply returns 1.0 as the volume element for every pixel and the total
number of pixels as the total volume.
The very foundation of NIFTy4's framework are spaces, all of which are derived from the :py:class:`DomainObject` class.
A space can be either unstructured or live on a geometrical manifold; the former case is supported by objects of type :py:class:`FieldArray`, while the latter must be derived from :py:class:`Space` (both of which are in turn derived from :py:class:`DomainObject`). Structured Spaces
.................
All domains defined on a geometrical manifold are derived from :py:class:`Space` (which is in turn derived from :py:class:`DomainObject`).
In addition to the capabilities of :py:class:`DomainObject`, :py:class:`Space` offers the following functionality:
- a :py:attr:`harmonic` property
- (iff the space is harmonic) some methods concerned with Gaussian convolution and the absolute distances of the individual grid cells from the origin
Examples for structured spaces are Examples for structured spaces are
- :py:class:`RGSpace` (an equidistant Cartesian grid with a user-definable number of dimensions), - :py:class:`RGSpace` (an equidistant Cartesian grid with a user-definable number of dimensions),
- :py:class:`GLSpace` (a Gauss-Legendre grid on the sphere), and - :py:class:`GLSpace` (a Gauss-Legendre grid on the sphere), and
- :py:class:`LMSpace` (a grid storing spherical harmonic coefficients). - :py:class:`LMSpace` (a grid storing spherical harmonic coefficients).
Among these, :py:class:`RGSpace` can be harmonic or not (depending on constructor arguments), :py:class:`GLSpace` is a pure position space (i.e. nonharmonic), and :py:class:`LMSpace` is always harmonic.
Domains Full domains
------- ............
A field can live on a single space, but it can also live on a product of spaces (or no space at all, in which case it is a scalar). A field can live on a single space, but it can also live on a product of spaces (or no space at all, in which case it is a scalar).
The set of spaces on which a field lives is a called a _domain_ in NIFTy terminology; it is described by a :py:class:`DomainTuple` object. The tuple of spaces on which a field lives is a called a *domain* in NIFTy terminology; it is described by a :py:class:`DomainTuple` object.
A :py:class:`DomainTuple` object can be constructed from
- a single instance of anything derived from :py:class:`DomainTuple`
- a tuple of such instances (possibly empty)
- another :py:class:`DomainTuple` object
.. _fields: .. _fields:
Fields Fields
------ ......
A field object is specified by A :py:class:`Field` object consists of the following components:
- a domain in form of a :py:class:`DomainTuple` object - a domain in form of a :py:class:`DomainTuple` object
- a data type (e.g. numpy.float64) - a data type (e.g. numpy.float64)
...@@ -52,6 +89,41 @@ Fields support arithmetic operations, contractions, etc. ...@@ -52,6 +89,41 @@ Fields support arithmetic operations, contractions, etc.
.. _operators: .. _operators:
Operators Linear Operators
--------- ................
A linear operator (represented by NIFTy4's abstract :py:class:`LinearOperator` class) can be interpreted as an (implicitly defined) matrix.
It can be applied to :py:class:`Field` instances, resulting in other :py:class:`Field` instances that potentially live on other domains.
There are four basic ways of applying an operator :math:`A` to a field :math:`f`:
- direct multiplication: :math:`A\cdot f`
- adjoint multiplication: :math:`A^\dagger \cdot f`
- inverse multiplication: :math:`A^{-1}\cdot f`
- adjoint inverse multiplication: :math:`(A^\dagger)^{-1}\cdot f`
(For linear operators, inverse adjoint multiplication and adjoint inverse multiplication are equivalent.)
Operator classes defined in NIFTy may implement an arbitrary subset of these four operations.
If needed, the set of supported operations can be enhanced by iterative inversion methods;
for example, an operator defining direct and adjoint multiplication, could be enhanced to support the complete set by this method.
There are two domains associated with a :py:class:`LinearOperator`: a *domain* and a *target*.
Direct multiplication and adjoint inverse multiplication transform a field living on the operator's *domain* to one living on the operator's *target*, whereas adjoint multiplication and inverse multiplication transform from *target* to *domain*.
Operators with identical domain and target can be derived from :py:class:`EndomorphicOperator`;
typical examples for this category are the :py:class:`ScalingOperator`, which simply multiplies its input by a scalar value and :py:class:`DiagonalOperator`, which multiplies every value of its input field with potentially different values.
Nifty4 allows simple and intuitive construction of combined operators.
As an example, if :math:`A`, :math:`B` and :math:`C` are of type :py:class:`LinearOperator` and :math:`f_1` and :math:`f_2` are fields, writing::
X = A*B.inverse*A.adjoint + C
f2 = X(f1)
will perform the operation suggested intuitively by the notation, checking domain compatibility while building the composed operator.
.. _minimization:
Minimization
............
...@@ -3,7 +3,6 @@ from .version import __version__ ...@@ -3,7 +3,6 @@ from .version import __version__
from . import dobj from . import dobj
from .domain_object import DomainObject from .domain_object import DomainObject
from .domain_tuple import DomainTuple
from .spaces.field_array import FieldArray from .spaces.field_array import FieldArray
from .spaces.space import Space from .spaces.space import Space
...@@ -14,6 +13,8 @@ from .spaces.gl_space import GLSpace ...@@ -14,6 +13,8 @@ from .spaces.gl_space import GLSpace
from .spaces.dof_space import DOFSpace from .spaces.dof_space import DOFSpace
from .spaces.power_space import PowerSpace from .spaces.power_space import PowerSpace
from .domain_tuple import DomainTuple
from .operators.linear_operator import LinearOperator from .operators.linear_operator import LinearOperator
from .operators.endomorphic_operator import EndomorphicOperator from .operators.endomorphic_operator import EndomorphicOperator
from .operators.scaling_operator import ScalingOperator from .operators.scaling_operator import ScalingOperator
...@@ -50,3 +51,12 @@ from .minimization.line_energy import LineEnergy ...@@ -50,3 +51,12 @@ from .minimization.line_energy import LineEnergy
from .sugar import * from .sugar import *
from .plotting.plot import plot from .plotting.plot import plot
from . import library from . import library
__all__= ["DomainObject", "FieldArray", "Space", "RGSpace", "LMSpace",
"HPSpace", "GLSpace", "DOFSpace", "PowerSpace", "DomainTuple",
"LinearOperator", "EndomorphicOperator", "Scalingperator",
"DiagonalOperator", "FFTOperator", "FFTSmoothingOperator",
"DirectSmoothingOperator", "ResponseOperator", "LaplaceOperator",
"PowerProjectionOperator", "InversionEnabler",
"Field", "sqrt", "exp", "log",
"Prober", "DiagonalProberMixin", "TraceProberMixin"]
...@@ -61,8 +61,8 @@ class DescentMinimizer(Minimizer): ...@@ -61,8 +61,8 @@ class DescentMinimizer(Minimizer):
status : integer status : integer
Can be controller.CONVERGED or controller.ERROR Can be controller.CONVERGED or controller.ERROR
Note Notes
---- -----
The minimization is stopped if The minimization is stopped if
* the controller returns controller.CONVERGED or controller.ERROR, * the controller returns controller.CONVERGED or controller.ERROR,
* a perfectly flat point is reached, * a perfectly flat point is reached,
......
...@@ -218,6 +218,7 @@ def plot(f, **kwargs): ...@@ -218,6 +218,7 @@ def plot(f, **kwargs):
ycoord = dobj.to_global_data(fld.val) ycoord = dobj.to_global_data(fld.val)
plt.plot(xcoord, ycoord,label=label[i]) plt.plot(xcoord, ycoord,label=label[i])
_limit_xy(**kwargs) _limit_xy(**kwargs)
if label != ([None]*len(f)):
plt.legend() plt.legend()
_makeplot(kwargs.get("name")) _makeplot(kwargs.get("name"))
return return
...@@ -250,6 +251,7 @@ def plot(f, **kwargs): ...@@ -250,6 +251,7 @@ def plot(f, **kwargs):
ycoord = dobj.to_global_data(fld.val) ycoord = dobj.to_global_data(fld.val)
plt.plot(xcoord, ycoord, label=label[i]) plt.plot(xcoord, ycoord, label=label[i])
_limit_xy(**kwargs) _limit_xy(**kwargs)
if label != ([None]*len(f)):
plt.legend() plt.legend()
_makeplot(kwargs.get("name")) _makeplot(kwargs.get("name"))
return return
......
...@@ -36,7 +36,6 @@ class PowerSpace(Space): ...@@ -36,7 +36,6 @@ class PowerSpace(Space):
There will be as many bins as there are distinct k-vector lengths There will be as many bins as there are distinct k-vector lengths
in the harmonic partner space. in the harmonic partner space.
The "binbounds" property of the PowerSpace will also be None. The "binbounds" property of the PowerSpace will also be None.
else: else:
the bin bounds requested for this PowerSpace. The array the bin bounds requested for this PowerSpace. The array
must be sorted and strictly ascending. The first entry is the right must be sorted and strictly ascending. The first entry is the right
......
...@@ -38,8 +38,7 @@ class RGSpace(Space): ...@@ -38,8 +38,7 @@ class RGSpace(Space):
If distances==None: If distances==None:
if harmonic==True, all distances will be set to 1 if harmonic==True, all distances will be set to 1
if harmonic==False, the distance along each axis will be if harmonic==False, the distance along each axis will be
set to the inverse of the number of points along that set to the inverse of the number of points along that axis.
axis.
harmonic : bool, *optional* harmonic : bool, *optional*
Whether the space represents a grid in position or harmonic space. Whether the space represents a grid in position or harmonic space.
(default: False). (default: False).
......
...@@ -34,7 +34,7 @@ def get_slice_list(shape, axes): ...@@ -34,7 +34,7 @@ def get_slice_list(shape, axes):
axes: tuple axes: tuple
Axes which should not be iterated over. Axes which should not be iterated over.
Yields Returns
------- -------
list list
The next list of indices and/or slice objects for each dimension. The next list of indices and/or slice objects for each dimension.
......
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