energy.py 4.54 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
#
Martin Reinecke's avatar
Martin Reinecke committed
14
# Copyright(C) 2013-2018 Max-Planck-Society
Theo Steininger's avatar
Theo Steininger committed
15
16
17
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik
# and financially supported by the Studienstiftung des deutschen Volkes.
18

19
import numpy as np
Philipp Arras's avatar
Philipp Arras committed
20
21
22
from ..field import Field
from ..multi import MultiField
from ..utilities import NiftyMetaBase, memo
23

24

Martin Reinecke's avatar
Martin Reinecke committed
25
class Energy(NiftyMetaBase()):
26
    """ Provides the functional used by minimization schemes.
27

28
29
   The Energy object is an implementation of a scalar function including its
   gradient and curvature at some position.
30
31
32

    Parameters
    ----------
33
34
    position : Field
        The input parameter of the scalar function.
35
36
37

    Notes
    -----
38
39
40
41
42
43
    An instance of the Energy class is defined at a certain location. If one
    is interested in the value, gradient or curvature of the abstract energy
    functional one has to 'jump' to the new position using the `at` method.
    This method returns a new energy instance residing at the new position. By
    this approach, intermediate results from computing e.g. the gradient can
    safely be reused for e.g. the value or the curvature.
44

45
46
47
    Memorizing the evaluations of some quantities (using the memo decorator)
    minimizes the computational effort for multiple calls.

Martin Reinecke's avatar
Martin Reinecke committed
48
    See Also
49
50
    --------
    memo
51
52

    """
53

54
    def __init__(self, position):
55
        super(Energy, self).__init__()
Martin Reinecke's avatar
Martin Reinecke committed
56
        self._position = position.lock()
57
58

    def at(self, position):
Martin Reinecke's avatar
Martin Reinecke committed
59
        """ Returns a new Energy object, initialized at `position`.
60
61
62
63

        Parameters
        ----------
        position : Field
Martin Reinecke's avatar
Martin Reinecke committed
64
            Location in parameter space for the new Energy object.
65
66
67

        Returns
        -------
Martin Reinecke's avatar
Martin Reinecke committed
68
        Energy
69
70
            Energy object at new position.
        """
71
72
        return self.__class__(position)

73
74
    @property
    def position(self):
75
        """
Martin Reinecke's avatar
Martin Reinecke committed
76
77
78
79
        Field : selected location in parameter space.

        The Field location in parameter space where value, gradient and
        curvature are evaluated.
80
        """
81
82
        return self._position

83
84
    @property
    def value(self):
85
        """
Martin Reinecke's avatar
Martin Reinecke committed
86
87
        float : value of the functional.

Martin Reinecke's avatar
Martin Reinecke committed
88
            The value of the energy functional at given `position`.
89
        """
90
91
92
93
        raise NotImplementedError

    @property
    def gradient(self):
94
        """
Martin Reinecke's avatar
Martin Reinecke committed
95
        Field : The gradient at given `position`.
96
        """
97
98
        raise NotImplementedError

Martin Reinecke's avatar
Martin Reinecke committed
99
100
101
102
    @property
    @memo
    def gradient_norm(self):
        """
Martin Reinecke's avatar
Martin Reinecke committed
103
        float : L2-norm of the gradient at given `position`.
Martin Reinecke's avatar
Martin Reinecke committed
104
105
106
        """
        return self.gradient.norm()

107
108
    @property
    def curvature(self):
109
        """
Martin Reinecke's avatar
Martin Reinecke committed
110
        LinearOperator : implicitly defined curvature.
Martin Reinecke's avatar
Martin Reinecke committed
111
112
            A positive semi-definite operator or function describing the
            curvature of the potential at the given `position`.
113
        """
114
        raise NotImplementedError
Martin Reinecke's avatar
stage 1    
Martin Reinecke committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

    def longest_step(self, dir):
        """Returns the longest allowed step size along `dir`

        Parameters
        ----------
        dir : Field
            the search direction

        Returns
        -------
        float or None
            the longest allowed step when starting from `self.position` along
            `dir`. If None, the step size is not limited.
        """
        return None
Philipp Arras's avatar
Philipp Arras committed
131

132
133
    def __mul__(self, factor):
        from .energy_sum import EnergySum
Philipp Arras's avatar
Philipp Arras committed
134
135
136
        if isinstance(factor, (float, int)):
            return EnergySum.make([self], [factor])
        return NotImplemented
Philipp Arras's avatar
Philipp Arras committed
137

138
139
140
141
142
    def __rmul__(self, factor):
        return self.__mul__(factor)

    def __add__(self, other):
        from .energy_sum import EnergySum
Philipp Arras's avatar
Philipp Arras committed
143
144
145
        if isinstance(other, Energy):
            return EnergySum.make([self, other])
        return NotImplemented
146
147
148

    def __sub__(self, other):
        from .energy_sum import EnergySum
Philipp Arras's avatar
Philipp Arras committed
149
150
151
        if isinstance(other, Energy):
            return EnergySum.make([self, other], [1., -1.])
        return NotImplemented
152
153
154
155

    def __neg__(self):
        from .energy_sum import EnergySum
        return EnergySum.make([self], [-1.])