/[escript]/trunk/downunder/py_src/costfunctions.py
ViewVC logotype

Contents of /trunk/downunder/py_src/costfunctions.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4397 - (show annotations)
Thu May 9 06:17:15 2013 UTC (6 years, 5 months ago) by jfenwick
File MIME type: text/x-python
File size: 11512 byte(s)
Added some doco to make it a little easier to work out what is going on.
Cleaned up some reST ugliness

1
2 ##############################################################################
3 #
4 # Copyright (c) 2003-2013 by University of Queensland
5 # http://www.uq.edu.au
6 #
7 # Primary Business: Queensland, Australia
8 # Licensed under the Open Software License version 3.0
9 # http://www.opensource.org/licenses/osl-3.0.php
10 #
11 # Development until 2012 by Earth Systems Science Computational Center (ESSCC)
12 # Development since 2012 by School of Earth Sciences
13 #
14 ##############################################################################
15
16 """General cost functions for minimization"""
17
18 __copyright__="""Copyright (c) 2003-2013 by University of Queensland
19 http://www.uq.edu.au
20 Primary Business: Queensland, Australia"""
21 __license__="""Licensed under the Open Software License version 3.0
22 http://www.opensource.org/licenses/osl-3.0.php"""
23 __url__="https://launchpad.net/escript-finley"
24
25 __all__ = [ 'CostFunction', 'MeteredCostFunction' ]
26
27 import logging
28
29 class CostFunction(object):
30 """
31 A function *f(x)* that can be minimized (base class).
32
33 Example of usage::
34
35 cf=DerivedCostFunction()
36 # ... calculate x ...
37 args=cf.getArguments(x) # this could be potentially expensive!
38 f=cf.getValue(x, *args)
39 # ... it could be required to update x without using the gradient...
40 # ... but then ...
41 gf=cf.getGradient(x, *args)
42
43 The class distinguishes between the representation of the solution
44 x (x-type) and the gradients (r-type).
45
46 :cvar provides_inverse_Hessian_approximation: This member should be set
47 to ``True`` in subclasses that provide a valid implementation of
48 `getInverseHessianApproximation()`
49 """
50
51 provides_inverse_Hessian_approximation=False
52
53 def __init__(self):
54 """
55 Constructor. Initializes logger.
56 """
57 self.logger = logging.getLogger('inv.%s'%self.__class__.__name__)
58
59 def __call__(self, x, *args):
60 """
61 short for `getValue(x, *args)`.
62 """
63 return self.getValue(x, *args)
64
65 def getArguments(self, x):
66 """
67 returns precalculated values that are shared in the calculation of
68 *f(x)* and *grad f(x)* and the Hessian operator. The default
69 implementation returns an empty tuple.
70
71 .. note:: The tuple returned by this call will be passed back to this `CostFunction` in other
72 calls(eg: `getGradient`). Its contents are not specified at this level because no code,
73 other than the `CostFunction`
74 which created it, will be interacting with it.
75 That is, the implementor can put whatever information they find useful in it.
76
77 :param x: location of derivative
78 :type x: x-type
79 :rtype: ``tuple``
80 """
81 return ()
82
83 def getDualProduct(self, x, r):
84 """
85 returns the dual product of ``x`` and ``r``
86
87 :type x: x-type
88 :type r: r-type
89 :rtype: ``float``
90 """
91 raise NotImplementedError
92
93 def getGradient(self, x, *args):
94 """
95 returns the gradient of *f* at *x* using the precalculated values for
96 *x*.
97
98 :param x: location of derivative
99 :type x: x-type
100 :param args: pre-calculated values for ``x`` from `getArguments()`
101 :rtype: r-type
102 """
103 raise NotImplementedError
104
105 def getInverseHessianApproximation(self, x, r, *args):
106 """
107 returns an approximative evaluation *p* of the inverse of the Hessian
108 operator of the cost function for a given gradient *r* at a given
109 location *x*: *H(x) p = r*
110
111 :param x: location of Hessian operator to be evaluated
112 :type x: x-type
113 :param r: a given gradient
114 :type r: r-type
115 :param args: pre-calculated values for ``x`` from `getArguments()`
116 :rtype: x-type
117 :note: In general it is assumed that the Hessian *H(x)* needs to be
118 calculated in each call for a new location *x*. However, the
119 solver may suggest that this is not required, typically when
120 the iteration is close to completeness.
121 :note: Subclasses that implement this method should set the class
122 variable `provides_inverse_Hessian_approximation` to ``True`` to
123 enable the solver to call this method.
124 """
125 raise NotImplementedError
126
127 def getValue(self, x, *args):
128 """
129 returns the value *f(x)* using the precalculated values for *x*.
130
131 :param x: a solution approximation
132 :type x: x-type
133 :rtype: ``float``
134 """
135 raise NotImplementedError
136
137 def updateHessian(self):
138 """
139 notifies the class that the Hessian operator needs to be updated.
140 This method is called by the solver class.
141 """
142 pass
143
144 def getNorm(self, x):
145 """
146 returns the norm of ``x``
147
148 :type x: x-type
149 :rtype: ``float``
150 """
151 raise NotImplementedError
152
153
154 class MeteredCostFunction(CostFunction):
155 """
156 This an intrumented version of the `CostFunction` class. The function
157 calls update statistical information.
158 The actual work is done by the methods with corresponding name and a
159 leading underscore. These functions need to be overwritten for a particular
160 cost function implementation.
161 """
162
163 def __init__(self):
164 """
165 the base constructor initializes the counters so subclasses should
166 ensure the super class constructor is called.
167 """
168 super(MeteredCostFunction, self).__init__()
169 self.resetCounters()
170
171 def resetCounters(self):
172 """
173 resets all statistical counters
174 """
175 self.DualProduct_calls=0
176 self.Value_calls=0
177 self.Gradient_calls=0
178 self.Arguments_calls=0
179 self.InverseHessianApproximation_calls=0
180 self.Norm_calls=0
181
182 def getDualProduct(self, x, r):
183 """
184 returns the dual product of ``x`` and ``r``
185
186 :type x: x-type
187 :type r: r-type
188 :rtype: ``float``
189 """
190 self.DualProduct_calls+=1
191 return self._getDualProduct(x, r)
192
193 def _getDualProduct(self, x, r):
194 """
195 returns the dual product of ``x`` and ``r``
196
197 :type x: x-type
198 :type r: r-type
199 :rtype: ``float``
200 :note: This is the worker for `getDualProduct()`, needs to be overwritten.
201 """
202 raise NotImplementedError
203
204 def getNorm(self, x):
205 """
206 returns the norm of ``x``
207
208 :type x: x-type
209 :rtype: ``float``
210 """
211 self.Norm_calls+=1
212 return self._getNorm(x)
213
214 def _getNorm(self, x):
215 """
216 returns the norm of ``x``
217
218 :type x: x-type
219 :rtype: ``float``
220 :note: This is the worker for `getNorm()`, needs to be overwritten.
221 """
222 raise NotImplementedError
223
224 def getValue(self, x, *args):
225 """
226 returns the value *f(x)* using the precalculated values for *x*.
227
228 :param x: a solution approximation
229 :type x: x-type
230 :rtype: ``float``
231 """
232 self.Value_calls+=1
233 return self._getValue(x, *args)
234
235 def _getValue(self, x, *args):
236 """
237 returns the value *f(x)* using the precalculated values for *x*.
238
239 :param x: a solution approximation
240 :type x: x-type
241 :rtype: ``float``
242 :note: This is the worker for ``getValue()``, needs to be overwritten.
243 """
244 raise NotImplementedError
245
246 def getGradient(self, x, *args):
247 """
248 returns the gradient of *f* at *x* using the precalculated values for
249 *x*.
250
251 :param x: location of derivative
252 :type x: x-type
253 :param args: pre-calculated values for ``x`` from `getArguments()`
254 :rtype: r-type
255 """
256 self.Gradient_calls+=1
257 return self._getGradient(x, *args)
258
259 def _getGradient(self, x, *args):
260 """
261 returns the gradient of *f* at *x* using the precalculated values for
262 *x*.
263
264 :param x: location of derivative
265 :type x: x-type
266 :param args: pre-calculated values for ``x`` from `getArguments()`
267 :rtype: r-type
268 :note: This is the worker for `getGradient()`, needs to be overwritten.
269 """
270 raise NotImplementedError
271
272
273 def getArguments(self, x):
274 """
275 returns precalculated values that are shared in the calculation of
276 *f(x)* and *grad f(x)* and the Hessian operator
277
278 .. note:: The tuple returned by this call will be passed back to this `CostFunction` in other
279 calls(eg: ``getGradient``). Its contents are not specified at this level because no code, other than the `CostFunction`
280 which created it, will be interacting with it.
281 That is, the implementor can put whatever information they find useful in it.
282
283 :param x: location of derivative
284 :type x: x-type
285 :rtype: ``tuple``
286 """
287 self.Arguments_calls+=1
288 return self._getArguments(x)
289
290 def _getArguments(self, x):
291 """
292 returns precalculated values that are shared in the calculation of
293 *f(x)* and *grad f(x)* and the Hessian operator.
294
295
296
297 :param x: location of derivative
298 :type x: x-type
299 """
300 return ()
301
302 def getInverseHessianApproximation(self, x, r,*args):
303 """
304 returns an approximative evaluation *p* of the inverse of the Hessian
305 operator of the cost function for a given gradient *r* at a given
306 location *x*: *H(x) p = r*
307
308 .. note:: In general it is assumed that the Hessian *H(x)* needs to be
309 calculate in each call for a new location *x*. However, the
310 solver may suggest that this is not required, typically when
311 the iteration is close to completeness.
312
313 :param x: location of Hessian operator to be evaluated.
314 :type x: x-type
315 :param r: a given gradient
316 :type r: r-type
317 :param args: pre-calculated values for ``x`` from `getArguments()`
318 :rtype: x-type
319
320 """
321 self.InverseHessianApproximation_calls+=1
322 return self._getInverseHessianApproximation(x, r, *args)
323
324 def _getInverseHessianApproximation(self, x, r, *args):
325 """
326 returns an approximative evaluation *p* of the inverse of the Hessian
327 operator of the cost function for a given gradient *r* at a given
328 location *x*: *H(x) p = r*
329
330 :param x: location of Hessian operator to be evaluated
331 :type x: x-type
332 :param r: a given gradient
333 :type r: r-type
334 :param args: pre-calculated values for ``x`` from `getArguments()`
335 :rtype: x-type
336 :note: In general it is assumed that the Hessian *H(x)* needs to be
337 calculate in each call for a new location *x*. However, the
338 solver may suggest that this is not required, typically when
339 the iteration is close to completeness.
340 :note: This is the worker for getInverseHessianApproximation()`, needs
341 to be overwritten.
342 :note: Subclasses that implement this method should set the class
343 variable `provides_inverse_Hessian_approximation` to ``True`` to
344 enable the solver to call this method.
345 """
346 raise NotImplementedError
347

  ViewVC Help
Powered by ViewVC 1.1.26