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

Philipp Arras's avatar
Philipp Arras committed
19
20
21
from .. import Field, exp
from ..operators.diagonal_operator import DiagonalOperator
from ..minimization.energy import Energy
22

23
24
# TODO Take only residual_sample_list as argument

25
26

class NoiseEnergy(Energy):
27
    def __init__(self, position, d, m, D, t, ht, Instrument, nonlinearity,
Martin Reinecke's avatar
Martin Reinecke committed
28
29
                 alpha, q, Projection, samples=3, sample_list=None,
                 inverter=None):
Martin Reinecke's avatar
Martin Reinecke committed
30
        super(NoiseEnergy, self).__init__(position=position)
31
32
33
        self.m = m
        self.D = D
        self.d = d
Martin Reinecke's avatar
Martin Reinecke committed
34
        self.N = DiagonalOperator(diagonal=exp(self.position))
35
36
        self.t = t
        self.samples = samples
37
        self.ht = ht
38
39
40
41
42
43
44
45
46
        self.Instrument = Instrument
        self.nonlinearity = nonlinearity

        self.alpha = alpha
        self.q = q
        self.Projection = Projection
        self.power = self.Projection.adjoint_times(exp(0.5 * self.t))
        self.one = Field(self.position.domain, val=1.)
        if sample_list is None:
Martin Reinecke's avatar
Martin Reinecke committed
47
48
            if samples is None or samples == 0:
                sample_list = [m]
49
            else:
Martin Reinecke's avatar
Martin Reinecke committed
50
                sample_list = [D.generate_posterior_sample() + m
Martin Reinecke's avatar
Martin Reinecke committed
51
                               for _ in range(samples)]
52
53
        self.sample_list = sample_list
        self.inverter = inverter
Martin Reinecke's avatar
Martin Reinecke committed
54
        self._value, self._gradient = self._value_and_grad()
55
56

    def at(self, position):
Martin Reinecke's avatar
Martin Reinecke committed
57
        return self.__class__(
58
            position, self.d, self.m, self.D, self.t, self.ht,
Martin Reinecke's avatar
Martin Reinecke committed
59
60
61
            self.Instrument, self.nonlinearity, self.alpha, self.q,
            self.Projection, sample_list=self.sample_list,
            samples=self.samples, inverter=self.inverter)
62

Martin Reinecke's avatar
Martin Reinecke committed
63
64
    def _value_and_grad(self):
        likelihood_gradient = None
65
        for sample in self.sample_list:
Martin Reinecke's avatar
Martin Reinecke committed
66
67
            residual = self.d - \
                self.Instrument(self.nonlinearity(
68
                    self.ht(self.power*sample)))
Martin Reinecke's avatar
Martin Reinecke committed
69
70
71
72
73
74
75
76
            lh = 0.5 * residual.vdot(self.N.inverse_times(residual))
            grad = -0.5 * self.N.inverse_times(residual.conjugate() * residual)
            if likelihood_gradient is None:
                likelihood = lh
                likelihood_gradient = grad.copy()
            else:
                likelihood += lh
                likelihood_gradient += grad
77

Martin Reinecke's avatar
Martin Reinecke committed
78
        likelihood = ((likelihood / float(len(self.sample_list))) +
79
                      0.5 * self.position.sum() +
Martin Reinecke's avatar
Martin Reinecke committed
80
81
82
83
84
85
86
                      (self.alpha - 1.).vdot(self.position) +
                      self.q.vdot(exp(-self.position)))
        likelihood_gradient = (
            likelihood_gradient / float(len(self.sample_list)) +
            (self.alpha-0.5) -
            self.q * (exp(-self.position)))
        return likelihood, likelihood_gradient
87
88

    @property
Martin Reinecke's avatar
Martin Reinecke committed
89
90
    def value(self):
        return self._value
91
92

    @property
Martin Reinecke's avatar
Martin Reinecke committed
93
94
    def gradient(self):
        return self._gradient