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

  ViewVC Help
Powered by ViewVC 1.1.26