operator_adapter.py 2.73 KB
Newer Older
Martin Reinecke's avatar
Martin Reinecke committed
1
2
3
4
5
6
7
8
9
10
11
12
13
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
Martin Reinecke's avatar
Martin Reinecke committed
14
# Copyright(C) 2013-2018 Max-Planck-Society
Martin Reinecke's avatar
Martin Reinecke committed
15
16
17
18
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik
# and financially supported by the Studienstiftung des deutschen Volkes.

Martin Reinecke's avatar
Martin Reinecke committed
19
from __future__ import absolute_import, division, print_function
20
21
22

import numpy as np

Martin Reinecke's avatar
Martin Reinecke committed
23
from ..compat import *
Martin Reinecke's avatar
Martin Reinecke committed
24
25
26
from .linear_operator import LinearOperator


Martin Reinecke's avatar
Martin Reinecke committed
27
class OperatorAdapter(LinearOperator):
Martin Reinecke's avatar
Martin Reinecke committed
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    """Class representing the inverse and/or adjoint of another operator.

    Objects of this class are created internally by `LinearOperator` whenever
    the inverse and/or adjoint of an already existing operator object is
    requested via the `LinearOperator` attributes `inverse`, `adjoint` or
    `_flip_modes()`.

    Users should never have to create instances of this class directly.

    Parameters
    ----------
    op : LinearOperator
        The operator on which the adapter will act
    op_transform : int
        1) adjoint
        2) inverse
        3) adjoint inverse
    """
Martin Reinecke's avatar
Martin Reinecke committed
46

47
    def __init__(self, op, op_transform):
Martin Reinecke's avatar
Martin Reinecke committed
48
        self._op = op
49
50
        self._trafo = int(op_transform)
        if self._trafo < 1 or self._trafo > 3:
51
            raise ValueError("invalid operator transformation")
Martin Reinecke's avatar
Martin Reinecke committed
52
53
        self._domain = self._op._dom(1 << self._trafo)
        self._target = self._op._tgt(1 << self._trafo)
Martin Reinecke's avatar
Martin Reinecke committed
54
        self._capability = self._capTable[self._trafo][self._op.capability]
Martin Reinecke's avatar
Martin Reinecke committed
55

56
57
58
59
    def _flip_modes(self, trafo):
        newtrafo = trafo ^ self._trafo
        return self._op if newtrafo == 0 \
            else OperatorAdapter(self._op, newtrafo)
60

Martin Reinecke's avatar
Martin Reinecke committed
61
    def apply(self, x, mode):
Martin Reinecke's avatar
PEP8    
Martin Reinecke committed
62
63
        return self._op.apply(x,
                              self._modeTable[self._trafo][self._ilog[mode]])
Martin Reinecke's avatar
Martin Reinecke committed
64

65
    def draw_sample(self, from_inverse=False, dtype=np.float64):
66
        if self._trafo & self.INVERSE_BIT:
67
68
            return self._op.draw_sample(not from_inverse, dtype)
        return self._op.draw_sample(from_inverse, dtype)
Martin Reinecke's avatar
Martin Reinecke committed
69
70
71

    def __repr__(self):
        from ..utilities import indent
Martin Reinecke's avatar
Martin Reinecke committed
72
        mode = ["adjoint", "inverse", "adjoint inverse"][self._trafo-1]
Martin Reinecke's avatar
Martin Reinecke committed
73
74
        res = "OperatorAdapter: {}\n".format(mode)
        return res + indent(self._op.__repr__())