diff --git a/docs/source/code.rst b/docs/source/code.rst index 1cdec8c8910202d8ca3381ab09078af4d8f5e1b6..cdcdb074eeee59bbad5e372f5f0e3f9c9eed808c 100644 --- a/docs/source/code.rst +++ b/docs/source/code.rst @@ -1,15 +1,220 @@ -NIFTy Code -========== +.. currentmodule:: nifty4 -The NIFTy code is divided in the concepts Domains, Fields, Operators and Minimization +Code Overview +============= +The fundamental building blocks required for IFT computations are best +recognized from a large distance, ignoring all technical details. -.. toctree:: - :maxdepth: 2 - :caption: Concepts - :glob: +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 + *domains* 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. + + +Domains +======= + + +Abstract base class +------------------- + +One of the fundamental building blocks of the NIFTy4 framework is the *domain*. +Its required capabilities are expressed by the abstract :class:Domain class. +A domain must be able to answer the following queries: + +- its total number of data entries (pixels), which is accessible via the + :attr:~Domain.size property +- the shape of the array that is supposed to hold these data entries + (obtainable by means of the :attr:~Domain.shape property) +- equality comparison to another :class:Domain instance + + +Unstructured domains +-------------------- + +Domains can be either *structured* (i.e. there is geometrical information +associated with them, like position in space and volume factors), +or *unstructured* (meaning that the data points have no associated manifold). + +Unstructured domains can be described by instances of NIFTy's +:class:UnstructuredDomain class. + + +Structured domains +------------------ + +In contrast to unstructured domains, these domains have an assigned geometry. +NIFTy requires them to provide the volume elements of their grid cells. +The additional methods are specified in the abstract class +:class:StructuredDomain: + +- The attributes :attr:~StructuredDomain.scalar_dvol, + :attr:~StructuredDomain.dvol, and :attr:~StructuredDomain.total_volume + provide information about the domain's pixel volume(s) and its total volume. +- The property :attr:~StructuredDomain.harmonic specifies whether a domain + is harmonic (i.e. describes a frequency space) or not +- Iff the domain is harmonic, the methods + :meth:~StructuredDomain.get_k_length_array, + :meth:~StructuredDomain.get_unique_k_lengths, and + :meth:~StructuredDomain.get_fft_smoothing_kernel_function provide absolute + distances of the individual grid cells from the origin and assist with + Gaussian convolution. + +NIFTy comes with several concrete subclasses of :class:StructuredDomain: + +- :class:RGSpace represents a regular Cartesian grid with an arbitrary + number of dimensions, which is supposed to be periodic in each dimension. +- :class:HPSpace and :class:GLSpace describe pixelisations of the + 2-sphere; their counterpart in harmonic space is :class:LMSpace, which + contains spherical harmonic coefficients. +- :class:PowerSpace is used to describe one-dimensional power spectra. + +Among these, :class:RGSpace can be harmonic or not (depending on constructor arguments), :class:GLSpace, :class:HPSpace, and :class:PowerSpace are +pure position domains (i.e. nonharmonic), and :class:LMSpace is always +harmonic. + + +Combinations of domains +======================= + +The fundamental classes described above are often sufficient to specify the +domain of a field. In some cases, however, it will be necessary to have the +field live on a product of elementary domains instead of a single one. +Some examples are: + +- sky emission depending on location and energy. This could be represented by + a product of an :class:HPSpace (for location) with an :class:RGSpace + (for energy). +- a polarised field, which could be modeled as a product of any structured + domain representing location with a four-element :class:UnstructuredDomain + holding Stokes I, Q, U and V components. + +Consequently, NIFTy defines a class called :class:DomainTuple holding +a sequence of :class:Domain objects, which is used to specify full field +domains. In principle, a :class:DomainTuple can even be empty, which implies +that the field living on it is a scalar. + + +Fields +====== + +A :class:Field object consists of the following components: + +- a domain in form of a :class:DomainTuple object +- a data type (e.g. numpy.float64) +- an array containing the actual values + +Fields support arithmetic operations, contractions, etc. + +Linear Operators +================ + +A linear operator (represented by NIFTy4's abstract :class:LinearOperator +class) can be interpreted as an (implicitly defined) matrix. +It can be applied to :class:Field instances, resulting in other :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.) + +These different actions of an operator Op on a field f can be invoked +in various ways: + +- direct multiplication: Op(f) or Op.times(f) or Op.apply(f, Op.TIMES) +- adjoint multiplication: Op.adjoint_times(f) or Op.apply(f, Op.ADJOINT_TIMES) +- inverse multiplication: Op.inverse_times(f) or Op.apply(f, Op.INVERSE_TIMES) +- adjoint inverse multiplication: Op.adjoint_inverse_times(f) or Op.apply(f, Op.ADJOINT_INVERSE_TIMES) + +Operator classes defined in NIFTy may implement an arbitrary subset of these +four operations. This subset can be queried using the +:attr:~LinearOperator.capability property. + +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. This functionality is +provided by NIFTy's :class:InversionEnabler class, which is itself a linear +operator. + +There are two :class:DomainTuple objects associated with a +:class:LinearOperator: a :attr:~LinearOperator.domain and a +:attr:~LinearOperator.target. +Direct multiplication and adjoint inverse multiplication transform a field +living on the operator's :attr:~LinearOperator.domain to one living on the operator's :attr:~LinearOperator.target, whereas adjoint multiplication +and inverse multiplication transform from :attr:~LinearOperator.target to :attr:~LinearOperator.domain. + +Operators with identical domain and target can be derived from +:class:EndomorphicOperator; typical examples for this category are the :class:ScalingOperator, which simply multiplies its input by a scalar +value, and :class:DiagonalOperator, which multiplies every value of its input +field with potentially different values. + +Further operator classes provided by NIFTy are + +- :class:HarmonicTransformOperator for transforms from harmonic domain to + their counterparts in position space, and their adjoint +- :class:PowerDistributor for transforms from a :class:PowerSpace to + the associated harmonic domain, and their adjoint +- :class:GeometryRemover, which transforms from structured domains to + unstructured ones. This is typically needed when building instrument response + operators. + +Nifty4 allows simple and intuitive construction of altered and combined +operators. +As an example, if A, B and C are of type :class:LinearOperator +and f1 and f2 are :class:Field s, 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. +The combined operator infers its domain and target from its constituents, +as well as the set of operations it can support. +The properties :attr:~LinearOperator.adjoint and +:attr:~LinearOperator.inverse return a new operator which behaves as if it +were the original operator's adjoint or inverse, respectively. + + +.. _minimization: + +Minimization +============ + +Most problems in IFT are solved by (possibly nested) minimizations of high-dimensional functions, which are often nonlinear. + +In NIFTy4 such functions are represented by objects of type :class:Energy. +These hold the prescription how to calculate the function's value, gradient and (optionally) curvature at any given position. +Function values are floating-point scalars, gradients have the form of fields living on the energy's position domain, and curvatures are represented by linear operator objects. + +Some examples of concrete energy classes delivered with NIFTy4 are :class:QuadraticEnergy (with position-independent curvature, mainly used with conjugate gradient minimization) and :class:WienerFilterEnergy. +Energies are classes that typically have to be provided by the user when tackling new IFT problems. + +The minimization procedure can be carried out by one of several algorithms; NIFTy4 currently ships solvers based on + +- the conjugate gradient method (for quadratic energies) +- the steepest descent method +- the VL-BFGS method +- the relaxed Newton method, and +- a nonlinear conjugate gradient method - Domains - Fields - Operators - Minimization diff --git a/docs/source/concepts/domains.rst b/docs/source/concepts/domains.rst index 5cf5e6362472630d7e2db8f98b600de7f5bc9141..fc9770f98a48e4f8adb6c716f095b2242154b3b2 100644 --- a/docs/source/concepts/domains.rst +++ b/docs/source/concepts/domains.rst @@ -37,8 +37,8 @@ NIFTy requires them to provide the volume elements of their grid cells. The additional methods are specified in the abstract class :class:StructuredDomain: -- Methods :meth:~StructuredDomain.scalar_dvol, - :meth:~StructuredDomain.dvol, and :meth:~StructuredDomain.total_volume +- The attributes :attr:~StructuredDomain.scalar_dvol, + :attr:~StructuredDomain.dvol, and :attr:~StructuredDomain.total_volume provide information about the domain's pixel volume(s) and its total volume. - The property :attr:~StructuredDomain.harmonic specifies whether a domain is harmonic (i.e. describes a frequency space) or not diff --git a/docs/source/index.rst b/docs/source/index.rst index df154d75040983b8b77813b6bd9a5c212b89f438..c0efefcf9826ac9cddc0a08ed7f677f295c7b00e 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -24,7 +24,6 @@ Contents ift Gallery installation - start code Indices and tables diff --git a/nifty4/operators/inversion_enabler.py b/nifty4/operators/inversion_enabler.py index 08639dd3d4ab46865ccd9c898ff9e5a34370ee87..ae32ed4cd3a33bfaebd83057fbe5173a944744e4 100644 --- a/nifty4/operators/inversion_enabler.py +++ b/nifty4/operators/inversion_enabler.py @@ -25,6 +25,20 @@ from .linear_operator import LinearOperator class InversionEnabler(LinearOperator): """Class which augments the capability of another operator object via numerical inversion. + + Parameters + ---------- + op : :class:EndomorphicOperator + The operator to be enhanced. + The InversionEnabler object will support the same operation modes as + op, and additionally the inverse set. The newly-added modes will + be computed by iterative inversion. + inverter : :class:Minimizer + The minimizer to use for the iterative numerical inversion. + Typically, this is a :class:ConjugateGradient object. + preconditioner : :class:LinearOperator, optional + if not None, this operator is used as a preconditioner during the + iterative inversion, to accelerate convergence. """ def __init__(self, op, inverter, preconditioner=None): diff --git a/nifty4/operators/linear_operator.py b/nifty4/operators/linear_operator.py index 1fbdf30757c72c9b40ba82dd7f256655e78aa203..132e564833d1708058a61e7ed78b359f7633af22 100644 --- a/nifty4/operators/linear_operator.py +++ b/nifty4/operators/linear_operator.py @@ -29,6 +29,25 @@ class LinearOperator(with_metaclass( The base NIFTY operator class is an abstract class from which other specific operator subclasses are derived. + + Attributes + ---------- + TIMES : int + Symbolic constant representing normal operator application + ADJOINT_TIMES : int + Symbolic constant representing adjoint operator application + INVERSE_TIMES : int + Symbolic constant representing inverse operator application + ADJOINT_INVERSE_TIMES : int + Symbolic constant representing adjoint inverse operator application + INVERSE_ADJOINT_TIMES : int + same as ADJOINT_INVERSE_TIMES + + Notes + ----- + The symbolic constants for the operation modes can be combined by the + "bitwise-or" operator "|", for expressing the capability of the operator + by means of a single integer number. """ _validMode = (False, True, True, False, True, False, False, False, True) @@ -131,7 +150,7 @@ class LinearOperator(with_metaclass( def capability(self): """int : the supported operation modes - Returns the suppoerted subset of :attr:TIMES, :attr:ADJOINT_TIMES, + Returns the supported subset of :attr:TIMES, :attr:ADJOINT_TIMES, :attr:INVERSE_TIMES, and :attr:ADJOINT_INVERSE_TIMES, joined together by the "|" operator. """