code.rst 18.5 KB
 Mihai Baltac committed Feb 12, 2018 1 Martin Reinecke committed Feb 19, 2018 2 ============= Martin Reinecke committed Feb 17, 2018 3 4 Code Overview ============= Mihai Baltac committed Feb 12, 2018 5 Martin Reinecke committed Feb 19, 2018 6 7 8 9 Executive summary ================= Martin Reinecke committed Feb 17, 2018 10 11 The fundamental building blocks required for IFT computations are best recognized from a large distance, ignoring all technical details. Mihai Baltac committed Feb 12, 2018 12 Martin Reinecke committed Feb 17, 2018 13 14 From such a perspective, Martin Reinecke committed Jul 02, 2018 15 - IFT problems largely consist of the combination of several high dimensional Sebastian Hutschenreuter committed Jul 02, 2018 16 *minimization* problems. Philipp Arras committed Jan 07, 2019 17 - Within NIFTy, *operators* are used to define the characteristic equations and Martin Reinecke committed Jul 02, 2018 18 properties of the problems. Martin Reinecke committed Feb 19, 2018 19 20 - The equations are built mostly from the application of *linear operators*, but there may also be nonlinear functions involved. Martin Reinecke committed Feb 17, 2018 21 - The unknowns in the equations represent either continuous physical *fields*, Martin Reinecke committed Feb 19, 2018 22 23 24 25 or they are simply individual measured *data points*. - Discretized *fields* have geometrical information (like locations and volume elements) associated with every entry; this information is called the field's *domain*. Martin Reinecke committed Feb 17, 2018 26 27 28 29 30 31 32 33 34 35 36 37 38 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 ------------------- Philipp Arras committed Jan 10, 2019 39 40 .. currentmodule:: nifty5.domains.domain Philipp Arras committed Jun 18, 2018 41 One of the fundamental building blocks of the NIFTy5 framework is the *domain*. Philipp Arras committed Jan 10, 2019 42 Its required capabilities are expressed by the abstract :py:class:Domain class. Martin Reinecke committed Feb 17, 2018 43 44 45 46 47 48 49 50 51 52 53 54 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 -------------------- Philipp Arras committed Jan 10, 2019 55 56 .. currentmodule:: nifty5.domains.unstructured_domain Martin Reinecke committed Feb 17, 2018 57 58 59 60 61 62 63 64 65 66 67 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 ------------------ Philipp Arras committed Jan 10, 2019 68 69 .. currentmodule:: nifty5.domains.structured_domain Martin Reinecke committed Feb 17, 2018 70 71 72 73 74 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: Martin Reinecke committed Feb 19, 2018 75 - The properties :attr:~StructuredDomain.scalar_dvol, Martin Reinecke committed Feb 17, 2018 76 77 78 79 80 81 82 83 84 85 86 87 88 :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: Philipp Arras committed Jan 10, 2019 89 90 .. currentmodule:: nifty5.domains Philipp Arras committed Jan 11, 2019 91 - :class:~rg_space.RGSpace represents a regular Cartesian grid with an arbitrary Martin Reinecke committed Feb 17, 2018 92 number of dimensions, which is supposed to be periodic in each dimension. Philipp Arras committed Jan 11, 2019 93 94 - :class:~hp_space.HPSpace and :class:~gl_space.GLSpace describe pixelisations of the 2-sphere; their counterpart in harmonic space is :class:~lm_space.LMSpace, which Martin Reinecke committed Feb 17, 2018 95 contains spherical harmonic coefficients. Philipp Arras committed Jan 11, 2019 96 - :class:~power_space.PowerSpace is used to describe one-dimensional power spectra. Martin Reinecke committed Feb 17, 2018 97 Philipp Arras committed Jan 11, 2019 98 99 100 101 Among these, :class:~rg_space.RGSpace can be harmonic or not (depending on constructor arguments), :class:~gl_space.GLSpace, :class:~hp_space.HPSpace, and :class:~power_space.PowerSpace are pure position domains (i.e. nonharmonic), and :class:~lm_space.LMSpace is always harmonic. Martin Reinecke committed Feb 17, 2018 102 103 104 105 106 107 Combinations of domains ======================= The fundamental classes described above are often sufficient to specify the Philipp Arras committed Jan 07, 2019 108 109 domain of a field. In some cases, however, it will be necessary to define the field on a product of elementary domains instead of a single one. Philipp Arras committed Jan 07, 2019 110 More sophisticated operators also require a set of several such fields. Martin Reinecke committed Feb 17, 2018 111 112 Some examples are: Philipp Arras committed Jan 11, 2019 113 114 115 - sky emission depending on location and energy. This could be represented by a product of an :class:~hp_space.HPSpace (for location) with an :class:~rg_space.RGSpace (for energy). Philipp Arras committed Jan 07, 2019 116 - a polarized field, which could be modeled as a product of any structured Martin Reinecke committed Feb 19, 2018 117 domain (representing location) with a four-element Philipp Arras committed Jan 11, 2019 118 :class:~unstructured_domain.UnstructuredDomain holding Stokes I, Q, U and V components. Martin Reinecke committed Aug 08, 2018 119 120 121 - a model for the sky emission, which holds both the current realization (on a harmonic domain) and a few inferred model parameters (e.g. on an unstructured grid). Martin Reinecke committed Feb 17, 2018 122 Philipp Arras committed Jan 11, 2019 123 .. currentmodule:: nifty5 Martin Reinecke committed Feb 17, 2018 124 Philipp Arras committed Jan 11, 2019 125 126 127 128 Consequently, NIFTy defines a class called :class:~domain_tuple.DomainTuple holding a sequence of :class:~domains.domain.Domain objects, which is used to specify full field domains. In principle, a :class:~domain_tuple.DomainTuple can even be empty, which implies that the field living on it is a scalar. Martin Reinecke committed Feb 19, 2018 129 Philipp Arras committed Jan 11, 2019 130 A :class:~domain_tuple.DomainTuple supports iteration and indexing, and also Lukas Platz committed Jan 28, 2019 131 provides the properties :attr:~domain_tuple.DomainTuple.shape and Philipp Arras committed Jan 11, 2019 132 133 134 135 136 137 :attr:~domain_tuple.DomainTuple.size in analogy to the elementary :class:~domains.domain.Domain. An aggregation of several :class:~domain_tuple.DomainTuple s, each member identified by a name, is described by the :class:~multi_domain.MultiDomain class. Martin Reinecke committed Feb 17, 2018 138 139 140 141 Fields ====== Martin Reinecke committed Aug 08, 2018 142 143 144 Fields on a single DomainTuple ------------------------------ Philipp Arras committed Jan 11, 2019 145 A :class:~field.Field object consists of the following components: Martin Reinecke committed Feb 17, 2018 146 Philipp Arras committed Jan 11, 2019 147 - a domain in form of a :class:~domain_tuple.DomainTuple object Martin Reinecke committed Feb 17, 2018 148 149 150 - a data type (e.g. numpy.float64) - an array containing the actual values Martin Reinecke committed Dec 21, 2018 151 Usually, the array is stored in the form of a numpy.ndarray, but for very Martin Reinecke committed Feb 19, 2018 152 153 154 155 156 157 158 resource-intensive tasks NIFTy also provides an alternative storage method to be used with distributed memory processing. Fields support a wide range of arithmetic operations, either involving two fields with equal domains, or a field and a scalar. Contractions (like summation, integration, minimum/maximum, computation of statistical moments) can be carried out either over an entire field (producing Philipp Arras committed Jan 13, 2019 159 a scalar result) or over sub-domains (resulting in a field defined on a smaller Martin Reinecke committed Jan 30, 2019 160 161 domain). Scalar products of two fields can also be computed easily. See the documentation of :class:~field.Field for details. Martin Reinecke committed Feb 19, 2018 162 163 164 There is also a set of convenience functions to generate fields with constant values or fields filled with random numbers according to a user-specified Lukas Platz committed Jan 28, 2019 165 distribution: :attr:~sugar.full, :attr:~sugar.from_random. Martin Reinecke committed Feb 19, 2018 166 Martin Reinecke committed Jul 05, 2018 167 168 169 170 171 Like almost all NIFTy objects, fields are immutable: their value or any other attribute cannot be modified after construction. To manipulate a field in ways that are not covered by the provided standard operations, its data content must be extracted first, then changed, and a new field has to be created from the result. Martin Reinecke committed Feb 19, 2018 172 Philipp Arras committed Jan 07, 2019 173 Fields defined on a MultiDomain Martin Reinecke committed Jan 09, 2019 174 ------------------------------- Martin Reinecke committed Aug 08, 2018 175 Philipp Arras committed Jan 11, 2019 176 177 178 The :class:~multi_field.MultiField class can be seen as a dictionary of individual :class:~field.Field s, each identified by a name, which is defined on a :class:~multi_domain.MultiDomain. Martin Reinecke committed Aug 08, 2018 179 180 181 182 183 Operators ========= Philipp Arras committed Jan 11, 2019 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 All transformations between different NIFTy fields are expressed in the form of :class:~operators.operator.Operator objects. The interface of this class is rather minimalistic: it has a property called :attr:~operators.operator.Operator.domain which returns a :class:~domain_tuple.DomainTuple or :class:~multi_domain.MultiDomain object specifying the structure of the :class:~field.Field or :class:~multi_field.MultiField it expects as input, another property :attr:~operators.operator.Operator.target describing its output, and finally an overloaded :attr:~operators.operator.Operator.apply method, which can take: - a :class:~field.Field/:class:~multi_field.MultiField object, in which case it returns the transformed :class:~field.Field/:class:~multi_field.MultiField. - a :class:~linearization.Linearization object, in which case it returns the transformed :class:~linearization.Linearization. This is the interface that all objects derived from :class:~operators.operator.Operator must implement. In addition, :class:~operators.operator.Operator objects can be added/subtracted, Philipp Arras committed Jan 14, 2019 202 203 204 multiplied, chained (via the :attr:__call__ method or the @ operator) and support point-wise application of functions like :class:exp(), :class:log(), :class:sqrt(), :class:conjugate(). Martin Reinecke committed Aug 08, 2018 205 Martin Reinecke committed Feb 17, 2018 206 Martin Reinecke committed Jan 09, 2019 207 208 209 Advanced operators ------------------ Philipp Arras committed Jan 11, 2019 210 NIFTy provides a library of commonly employed operators which can be used for Martin Reinecke committed Jan 09, 2019 211 212 specific inference problems. Currently these are: Philipp Arras committed Jan 14, 2019 213 214 .. currentmodule:: nifty5.library Philipp Arras committed Jan 14, 2019 215 - :class:~smooth_linear_amplitude.SLAmplitude, which returns a smooth power spectrum. Philipp Arras committed Jan 14, 2019 216 - :class:~inverse_gamma_operator.InverseGammaOperator, which models point sources which are Philipp Arras committed Jan 11, 2019 217 distributed according to a inverse-gamma distribution. Philipp Arras committed Jan 14, 2019 218 - :class:~correlated_fields.CorrelatedField, which models a diffuse log-normal field. It takes an Philipp Arras committed Jan 11, 2019 219 amplitude operator to specify the correlation structure of the field. Martin Reinecke committed Jan 09, 2019 220 221 Martin Reinecke committed Feb 17, 2018 222 223 224 Linear Operators ================ Philipp Arras committed Jan 14, 2019 225 226 227 228 229 230 231 232 .. currentmodule:: nifty5.operators A linear operator (represented by NIFTy5's abstract :class:~linear_operator.LinearOperator class) is derived from :class:~operator.Operator and can be interpreted as an (implicitly defined) matrix. Since its operation is linear, it can provide some additional functionality which is not available for the more generic :class:~operator.Operator class. Martin Reinecke committed Feb 17, 2018 233 Martin Reinecke committed Feb 18, 2018 234 Martin Reinecke committed Jan 09, 2019 235 236 Linear Operator basics ---------------------- Martin Reinecke committed Feb 18, 2018 237 Philipp Arras committed Jan 14, 2019 238 There are four basic ways of applying an operator :math:A to a field :math:s: Martin Reinecke committed Feb 17, 2018 239 Philipp Arras committed Jan 14, 2019 240 241 242 243 - direct application: :math:A(s) - adjoint application: :math:A^\dagger (s) - inverse application: :math:A^{-1} (s) - adjoint inverse application: :math:(A^\dagger)^{-1} (s) Martin Reinecke committed Feb 17, 2018 244 Philipp Arras committed Jan 14, 2019 245 246 Note: The inverse of the adjoint of a linear map and the adjoint of the inverse of a linear map (if all those exist) are the same. Martin Reinecke committed Feb 17, 2018 247 Martin Reinecke committed Jan 09, 2019 248 249 These different actions of a linear operator Op on a field f can be invoked in various ways: Martin Reinecke committed Feb 17, 2018 250 251 252 253 254 255 256 257 - 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 Philipp Arras committed Jan 14, 2019 258 :attr:~linear_operator.LinearOperator.capability property. Martin Reinecke committed Feb 17, 2018 259 260 If needed, the set of supported operations can be enhanced by iterative Philipp Arras committed Jan 14, 2019 261 262 263 264 inversion methods; for example, an operator defining direct and adjoint multiplication could be enhanced by this approach to support the complete set. This functionality is provided by NIFTy's :class:~inversion_enabler.InversionEnabler class, which is itself a linear Martin Reinecke committed Feb 17, 2018 265 266 operator. Philipp Arras committed Jan 17, 2019 267 .. currentmodule:: nifty5.operators.operator Philipp Arras committed Jan 14, 2019 268 Martin Reinecke committed Feb 17, 2018 269 Direct multiplication and adjoint inverse multiplication transform a field Philipp Arras committed Jan 17, 2019 270 271 272 273 defined on the operator's :attr:~Operator.domain to one defined on the operator's :attr:~Operator.target, whereas adjoint multiplication and inverse multiplication transform from :attr:~Operator.target to :attr:~Operator.domain. Philipp Arras committed Jan 14, 2019 274 275 .. currentmodule:: nifty5.operators Martin Reinecke committed Feb 17, 2018 276 277 Operators with identical domain and target can be derived from Philipp Arras committed Jan 14, 2019 278 279 280 281 282 283 284 :class:~endomorphic_operator.EndomorphicOperator. Typical examples for this category are the :class:~scaling_operator.ScalingOperator, which simply multiplies its input by a scalar value, and :class:~diagonal_operator.DiagonalOperator, which multiplies every value of its input field with potentially different values. .. currentmodule:: nifty5 Martin Reinecke committed Feb 17, 2018 285 286 287 Further operator classes provided by NIFTy are Philipp Arras committed Jan 14, 2019 288 289 290 291 292 293 294 295 296 - :class:~operators.harmonic_operators.HarmonicTransformOperator for transforms from a harmonic domain to its counterpart in position space, and their adjoint - :class:~operators.distributors.PowerDistributor for transforms from a :class:~domains.power_space.PowerSpace to an associated harmonic domain, and their adjoint. - :class:~operators.simple_linear_operators.GeometryRemover, which transforms from structured domains to unstructured ones. This is typically needed when building instrument response operators. Martin Reinecke committed Feb 17, 2018 297 Martin Reinecke committed Feb 18, 2018 298 Martin Reinecke committed Feb 19, 2018 299 300 Syntactic sugar --------------- Martin Reinecke committed Feb 18, 2018 301 Martin Reinecke committed Jun 19, 2018 302 Nifty5 allows simple and intuitive construction of altered and combined Martin Reinecke committed Feb 17, 2018 303 operators. Philipp Arras committed Jan 14, 2019 304 As an example, if A, B and C are of type :class:~operators.linear_operator.LinearOperator Philipp Arras committed Jan 11, 2019 305 and f1 and f2 are of type :class:~field.Field, writing:: Martin Reinecke committed Feb 17, 2018 306 Martin Reinecke committed Aug 08, 2018 307 X = A(B.inverse(A.adjoint)) + C Martin Reinecke committed Feb 17, 2018 308 309 f2 = X(f1) Philipp Arras committed Jan 14, 2019 310 311 .. currentmodule:: nifty5.operators.linear_operator Martin Reinecke committed Feb 17, 2018 312 313 314 315 316 will perform the operation suggested intuitively by the notation, checking domain compatibility while building the composed operator. 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. Lukas Platz committed Jan 28, 2019 317 318 319 320 321 322 The combined operator infers its domain and target from its constituents, as well as the set of operations it can support. Instantiating operator adjoints or inverses by :attr:~LinearOperator.adjoint and similar methods is to be distinguished from the instant application of operators performed by :attr:~LinearOperator.adjoint_times and similar methods. Martin Reinecke committed Feb 17, 2018 323 324 325 326 .. _minimization: Martin Reinecke committed Feb 19, 2018 327 Martin Reinecke committed Feb 17, 2018 328 329 330 Minimization ============ Martin Reinecke committed Feb 18, 2018 331 332 333 Most problems in IFT are solved by (possibly nested) minimizations of high-dimensional functions, which are often nonlinear. Philipp Arras committed Jan 14, 2019 334 .. currentmodule:: nifty5.minimization Martin Reinecke committed Feb 18, 2018 335 336 337 Energy functionals ------------------ Martin Reinecke committed Feb 17, 2018 338 Philipp Arras committed Jan 14, 2019 339 340 341 342 343 In NIFTy5 such functions are represented by objects of type :class:~energy.Energy. These hold the prescription how to calculate the function's :attr:~energy.Energy.value, :attr:~energy.Energy.gradient and (optionally) :attr:~energy.Energy.metric at any given :attr:~energy.Energy.position in parameter space. Function values are Philipp Arras committed Jan 14, 2019 344 floating-point scalars, gradients have the form of fields defined on the energy's Philipp Arras committed Jan 14, 2019 345 346 347 position domain, and metrics are represented by linear operator objects. .. currentmodule:: nifty5 Martin Reinecke committed Feb 17, 2018 348 Martin Reinecke committed Feb 19, 2018 349 Energies are classes that typically have to be provided by the user when Philipp Arras committed Jan 14, 2019 350 351 352 tackling new IFT problems. An example of concrete energy classes delivered with NIFTy5 is :class:~minimization.quadratic_energy.QuadraticEnergy (with position-independent metric, mainly used with conjugate gradient minimization). Martin Reinecke committed Feb 17, 2018 353 Martin Reinecke committed Feb 19, 2018 354 355 356 Iteration control ----------------- Martin Reinecke committed Feb 18, 2018 357 Philipp Arras committed Jan 14, 2019 358 359 .. currentmodule:: nifty5.minimization.iteration_controllers Martin Reinecke committed Feb 18, 2018 360 Iterative minimization of an energy reqires some means of Martin Reinecke committed Feb 19, 2018 361 checking the quality of the current solution estimate and stopping once Martin Reinecke committed Feb 18, 2018 362 363 364 it is sufficiently accurate. In case of numerical problems, the iteration needs to be terminated as well, returning a suitable error description. Philipp Arras committed Jun 18, 2018 365 In NIFTy5, this functionality is encapsulated in the abstract Martin Reinecke committed Feb 18, 2018 366 367 368 369 370 371 372 373 374 :class:IterationController class, which is provided with the initial energy object before starting the minimization, and is updated with the improved energy after every iteration. Based on this information, it can either continue the minimization or return the current estimate indicating convergence or failure. Sensible stopping criteria can vary significantly with the problem being solved; NIFTy provides one concrete sub-class of :class:IterationController called :class:GradientNormController, which should be appropriate in many Lukas Platz committed Jan 28, 2019 375 376 circumstances, but users have complete freedom to implement custom :class:IterationController sub-classes for their specific applications. Martin Reinecke committed Feb 18, 2018 377 378 379 380 381 Minimization algorithms ----------------------- Philipp Arras committed Jan 14, 2019 382 383 .. currentmodule:: nifty5.minimization Martin Reinecke committed Feb 19, 2018 384 All minimization algorithms in NIFTy inherit from the abstract Philipp Arras committed Jan 14, 2019 385 :class:~minimizer.Minimizer class, which presents a minimalistic interface Philipp Arras committed Jan 17, 2019 386 consisting only of a :meth:~minimizer.Minimizer.__call__ method taking an Philipp Arras committed Jan 14, 2019 387 388 :class:~energy.Energy object and optionally a preconditioning operator, and returning the energy at the discovered minimum and a status code. Martin Reinecke committed Feb 19, 2018 389 Philipp Arras committed Jan 14, 2019 390 391 392 For energies with a quadratic form (i.e. which can be expressed by means of a :class:~quadratic_energy.QuadraticEnergy object), an obvious choice of algorithm is the :class:~conjugate_gradient.ConjugateGradient minimizer. Martin Reinecke committed Feb 19, 2018 393 394 A similar algorithm suited for nonlinear problems is provided by Philipp Arras committed Jan 14, 2019 395 :class:~nonlinear_cg.NonlinearCG. Martin Reinecke committed Feb 19, 2018 396 Martin Reinecke committed Feb 19, 2018 397 Many minimizers for nonlinear problems can be characterized as Martin Reinecke committed Feb 19, 2018 398 Philipp Arras committed Jan 14, 2019 399 400 - First deciding on a direction for the next step. - Then finding a suitable step length along this direction, resulting in the Martin Reinecke committed Feb 19, 2018 401 402 next energy estimate. Philipp Arras committed Jan 14, 2019 403 404 405 406 407 This family of algorithms is encapsulated in NIFTy's :class:~descent_minimizers.DescentMinimizer class, which currently has three concrete implementations: :class:~descent_minimizers.SteepestDescent, :class:~descent_minimizers.NewtonCG, :class:~descent_minimizers.L_BFGS and :class:~descent_minimizers.VL_BFGS. Of these algorithms, only Martin Reinecke committed Jan 16, 2019 408 :class:~descent_minimizers.NewtonCG requires the energy object to provide Philipp Arras committed Jan 14, 2019 409 410 411 412 413 414 a :attr:~energy.Energy.metric property, the others only need energy values and gradients. The flexibility of NIFTy's design allows using externally provided minimizers. With only small effort, adapters for two SciPy minimizers were written; they are available under the names :class:~scipy_minimizer.ScipyCG and Martin Reinecke committed Jan 16, 2019 415 :class:~scipy_minimizer.L_BFGS_B. Martin Reinecke committed Feb 19, 2018 416 Martin Reinecke committed Feb 19, 2018 417 418 419 420 Application to operator inversion --------------------------------- Philipp Arras committed Jan 14, 2019 421 .. currentmodule:: nifty5 Martin Reinecke committed Feb 18, 2018 422 Philipp Arras committed Jan 14, 2019 423 424 425 426 The machinery presented here cannot only be used for minimizing functionals derived from IFT, but also for the numerical inversion of linear operators, if the desired application mode is not directly available. A classical example is the information propagator whose inverse is defined as: Martin Reinecke committed Feb 18, 2018 427 Martin Reinecke committed Jan 14, 2019 428 :math:D^{-1} = \left(R^\dagger N^{-1} R + S^{-1}\right). Martin Reinecke committed Feb 18, 2018 429 Philipp Arras committed Jan 14, 2019 430 It needs to be applied in forward direction in order to calculate the Wiener Lukas Platz committed Jan 28, 2019 431 432 filter solution, but only its inverse application is straightforward. To use it in forward direction, we make use of NIFTy's Philipp Arras committed Jan 14, 2019 433 :class:~operators.inversion_enabler.InversionEnabler class, which internally Martin Reinecke committed Jan 30, 2019 434 applies the (approximate) inverse of the given operator :math:x = Op^{-1} (y) by Lukas Platz committed Jan 28, 2019 435 436 437 438 439 solving the equation :math:y = Op (x) for :math:x. This is accomplished by minimizing a suitable :class:~minimization.quadratic_energy.QuadraticEnergy with the :class:~minimization.conjugate_gradient.ConjugateGradient algorithm. An example is provided in Philipp Arras committed Jan 17, 2019 440 :func:~library.wiener_filter_curvature.WienerFilterCurvature.