linear_operator.py 4.44 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
# 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/>.
Theo Steininger's avatar
Theo Steininger committed
13
14
15
16
17
#
# Copyright(C) 2013-2017 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik
# and financially supported by the Studienstiftung des deutschen Volkes.
18

19
import abc
Martin Reinecke's avatar
Martin Reinecke committed
20
from ..utilities import NiftyMeta
Martin Reinecke's avatar
Martin Reinecke committed
21
from ..field import Field
Martin Reinecke's avatar
Martin Reinecke committed
22
from future.utils import with_metaclass
23
24


25
class LinearOperator(with_metaclass(
Martin Reinecke's avatar
Martin Reinecke committed
26
        NiftyMeta, type('NewBase', (object,), {}))):
Theo Steininger's avatar
Theo Steininger committed
27

Martin Reinecke's avatar
Martin Reinecke committed
28
29
30
31
32
33
    _validMode = (False, True, True, False, True, False, False, False, True)
    _inverseMode = (0, 4, 8, 0, 1, 0, 0, 0, 2)
    _inverseCapability = (0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15)
    _adjointMode = (0, 2, 1, 0, 8, 0, 0, 0, 4)
    _adjointCapability = (0, 2, 1, 3, 8, 10, 9, 11, 4, 6, 5, 7, 12, 14, 13, 15)
    _addInverse = (0, 5, 10, 15, 5, 5, 15, 15, 10, 15, 10, 15, 15, 15, 15, 15)
34

Martin Reinecke's avatar
Martin Reinecke committed
35
36
    def _dom(self, mode):
        return self.domain if (mode & 9) else self.target
37

Martin Reinecke's avatar
Martin Reinecke committed
38
39
    def _tgt(self, mode):
        return self.domain if (mode & 6) else self.target
40

41
42
    def __init__(self):
        pass
43

44
    @abc.abstractproperty
45
    def domain(self):
46
        """
Martin Reinecke's avatar
Martin Reinecke committed
47
        domain : DomainTuple
Theo Steininger's avatar
Theo Steininger committed
48
49
            The domain on which the Operator's input Field lives.
            Every Operator which inherits from the abstract LinearOperator
50
51
            base class must have this attribute.
        """
52
        raise NotImplementedError
53
54
55

    @abc.abstractproperty
    def target(self):
56
        """
Martin Reinecke's avatar
Martin Reinecke committed
57
        target : DomainTuple
Theo Steininger's avatar
Theo Steininger committed
58
59
            The domain on which the Operator's output Field lives.
            Every Operator which inherits from the abstract LinearOperator
60
61
            base class must have this attribute.
        """
62
63
        raise NotImplementedError

64
    @property
Martin Reinecke's avatar
Martin Reinecke committed
65
66
    def TIMES(self):
        return 1
67

Martin Reinecke's avatar
Martin Reinecke committed
68
69
70
    @property
    def ADJOINT_TIMES(self):
        return 2
71

Martin Reinecke's avatar
Martin Reinecke committed
72
73
74
    @property
    def INVERSE_TIMES(self):
        return 4
75

Martin Reinecke's avatar
Martin Reinecke committed
76
77
78
    @property
    def ADJOINT_INVERSE_TIMES(self):
        return 8
79

Martin Reinecke's avatar
Martin Reinecke committed
80
81
82
    @property
    def INVERSE_ADJOINT_TIMES(self):
        return 8
83

Martin Reinecke's avatar
Martin Reinecke committed
84
85
86
87
    @property
    def inverse(self):
        from .inverse_operator import InverseOperator
        return InverseOperator(self)
88

Martin Reinecke's avatar
Martin Reinecke committed
89
90
91
92
    @property
    def adjoint(self):
        from .adjoint_operator import AdjointOperator
        return AdjointOperator(self)
93

Martin Reinecke's avatar
Martin Reinecke committed
94
95
96
    def __mul__(self, other):
        from .chain_operator import ChainOperator
        return ChainOperator(self, other)
97

Martin Reinecke's avatar
Martin Reinecke committed
98
99
100
    def __add__(self, other):
        from .sum_operator import SumOperator
        return SumOperator(self, other)
101

Martin Reinecke's avatar
Martin Reinecke committed
102
103
104
    def __sub__(self, other):
        from .sum_operator import SumOperator
        return SumOperator(self, other, neg=True)
105

Martin Reinecke's avatar
Martin Reinecke committed
106
107
    def supports(self, ops):
        return False
108

Martin Reinecke's avatar
Martin Reinecke committed
109
110
111
    @abc.abstractproperty
    def capability(self):
        raise NotImplementedError
112

Martin Reinecke's avatar
Martin Reinecke committed
113
114
115
116
117
118
    @abc.abstractmethod
    def apply(self, x, mode):
        raise NotImplementedError

    def __call__(self, x):
        return self.apply(x, self.TIMES)
119

Martin Reinecke's avatar
Martin Reinecke committed
120
121
122
123
124
125
126
127
    def times(self, x):
        return self.apply(x, self.TIMES)

    def inverse_times(self, x):
        return self.apply(x, self.INVERSE_TIMES)

    def adjoint_times(self, x):
        return self.apply(x, self.ADJOINT_TIMES)
128

Martin Reinecke's avatar
Martin Reinecke committed
129
130
    def adjoint_inverse_times(self, x):
        return self.apply(x, self.ADJOINT_INVERSE_TIMES)
131

Martin Reinecke's avatar
Martin Reinecke committed
132
133
    def inverse_adjoint_times(self, x):
        return self.apply(x, self.ADJOINT_INVERSE_TIMES)
134

Martin Reinecke's avatar
Martin Reinecke committed
135
136
137
138
139
    def _check_mode(self, mode):
        if not self._validMode[mode]:
            raise ValueError("invalid operator mode specified")
        if mode & self.capability == 0:
            raise ValueError("requested operator mode is not supported")
140

Martin Reinecke's avatar
Martin Reinecke committed
141
    def _check_input(self, x, mode):
142
        if not isinstance(x, Field):
Martin Reinecke's avatar
updates    
Martin Reinecke committed
143
            raise ValueError("supplied object is not a `Field`.")
144

Martin Reinecke's avatar
Martin Reinecke committed
145
146
147
148
        self._check_mode(mode)
        if x.domain != self._dom(mode):
                raise ValueError("The operator's and and field's domains "
                                 "don't match.")