ForceBalance API  1.3
Automated optimization of force fields and empirical potentials
finite_difference.py
Go to the documentation of this file.
1 """ Finite difference module. """
2 from __future__ import division
3 
4 import traceback
5 from numpy import dot
6 from forcebalance.output import getLogger
7 logger = getLogger(__name__)
8 
9 def f1d2p(f, h, f0 = None):
10  """
11  A two-point finite difference stencil.
12  This function does either two computations or one,
13  depending on whether the 'center' value is supplied.
14  This is done in order to avoid recomputing the center
15  value many times when we repeat this function for each
16  index of the gradient.
17 
18  How to use: use fdwrap or something similar to generate
19  a one-variable function from the (usually) much more complicated
20  function that we wish to differentate. Then pass it to this function.
21 
22  Inputs:
23  f = The one-variable function f(x) that we're differentiating
24  h = The finite difference step size, usually a small number
25 
26  Outputs:
27  fp = The finite difference derivative of the function f(x) around x=0.
28  """
29  if f0 is None:
30  f0, f1 = [f(i*h) for i in [0, 1]]
31  else:
32  f1 = f(h)
33  fp = (f1-f0)/h
34  return fp
35 
36 def f1d5p(f, h):
37  """
38  A highly accurate five-point finite difference stencil
39  for computing derivatives of a function. It works on both
40  scalar and vector functions (i.e. functions that return arrays).
41  Since the function does four computations, it's costly but
42  recommended if we really need an accurate reference value.
43 
44  The function is evaluated at points -2h, -h, +h and +2h
45  and these values are combined to make the derivative according to:
46  http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/central-differences/
47 
48  How to use: use fdwrap or something similar to generate
49  a one-variable function from the (usually) much more complicated
50  function that we wish to differentate. Then pass it to this function.
51 
52  Inputs:
53  f = The one-variable function f(x) that we're differentiating
54  h = The finite difference step size, usually a small number
55 
56  Outputs:
57  fp = The finite difference derivative of the function f(x) around x=0.
58  """
59  fm2, fm1, f1, f2 = [f(i*h) for i in [-2, -1, 1, 2]]
60  fp = (-1*f2+8*f1-8*fm1+1*fm2)/(12*h)
61  return fp
62 
63 def f1d7p(f, h):
64  """
65  A highly accurate seven-point finite difference stencil
66  for computing derivatives of a function.
67  """
68  fm3, fm2, fm1, f1, f2, f3 = [f(i*h) for i in [-3, -2, -1, 1, 2, 3]]
69  fp = (f3-9*f2+45*f1-45*fm1+9*fm2-fm3)/(60*h)
70  return fp
71 
72 def f12d7p(f, h):
73  fm3, fm2, fm1, f0, f1, f2, f3 = [f(i*h) for i in [-3, -2, -1, 0, 1, 2, 3]]
74  fp = (f3-9*f2+45*f1-45*fm1+9*fm2-fm3)/(60*h)
75  fpp = (2*f3-27*f2+270*f1-490*f0+270*fm1-27*fm2+2*fm3)/(180*h*h)
76  return fp, fpp
77 
78 def f12d3p(f, h, f0 = None):
79  """
80  A three-point finite difference stencil.
81  This function does either two computations or three,
82  depending on whether the 'center' value is supplied.
83  This is done in order to avoid recomputing the center
84  value many times.
85 
86  The first derivative is evaluated using central difference.
87  One advantage of using central difference (as opposed to forward
88  difference) is that we get zero at the bottom of a parabola.
89 
90  Using this formula we also get an approximate second derivative, which
91  can then be inserted into the diagonal of the Hessian. This is very
92  useful for optimizations like BFGS where the diagonal determines
93  how far we step in the parameter space.
94 
95  How to use: use fdwrap or something similar to generate
96  a one-variable function from the (usually) much more complicated
97  function that we wish to differentate. Then pass it to this function.
98 
99  Inputs:
100  f = The one-variable function f(x) that we're differentiating
101  h = The finite difference step size, usually a small number
102 
103  Outputs:
104  fp = The finite difference derivative of the function f(x) around x=0.
105  """
106  if f0 is None:
107  fm1, f0, f1 = [f(i*h) for i in [-1, 0, 1]]
108  else:
109  fm1, f1 = [f(i*h) for i in [-1, 1]]
110  fp = (f1-fm1)/(2*h)
111  fpp = (fm1-2*f0+f1)/(h*h)
112  return fp, fpp
113 
114 def f2var(f, h):
115  """ A finite difference stencil for a function of two variables. """
116  fpp, fpm, fmp, fmm = [f(i*h, j*h) for i, j in [(1,1), (1,-1), (-1,1), (-1,-1)]]
117  return (fpp-fpm-fmp+fmm)/(4*h**2)
118 
119 def in_fd():
120  """ Invoking this function from anywhere will tell us whether we're being called by a finite-difference function.
121  This is mainly useful for deciding when to update the 'qualitative indicators' and when not to. """
122 
123  return any([i in [j[2] for j in traceback.extract_stack()] for i in ['f1d2p','f12d3p','f1d5p','f12d7p','f1d7p']])
124 
125 def in_fd_srch():
126  """ Invoking this function from anywhere will tell us whether we're being called by a finite-difference function.
127  This is mainly useful for deciding when to update the 'qualitative indicators' and when not to. """
129  return any([i in [j[2] for j in traceback.extract_stack()] for i in ['f1d2p','f12d3p','f1d5p','f12d7p','f1d7p','search_fun']])
130 
131 def fdwrap(func,mvals0,pidx,key=None,**kwargs):
132  """
133  A function wrapper for finite difference designed for
134  differentiating 'get'-type functions.
136  Since our finite difference stencils take single-variable functions
137  and differentiate them around zero, and our objective function is
138  quite a complicated function, we need a wrapper to serve as a
139  middleman. The alternative would be to copy the finite difference
140  formula to wherever we're taking the derivative, and that is prone
141  to mistakes.
142 
143  Inputs:
144  func = Either get_X or get_G; these functions return dictionaries. ['X'] = 1.23, ['G'] = [0.12, 3,45, ...]
145  mvals0 = The 'central' values of the mathematical parameters - i.e. the wrapped function's origin is here.
146  pidx = The index of the parameter that we're differentiating
147  key = either 'G' or 'X', the value we wish to take out of the dictionary
148  kwargs = Anything else we want to pass to the objective function (for instance, Project.Objective takes Order as an argument)
149 
150  Outputs:
151  func1 = Wrapped version of func, which takes a single float argument.
152  """
153  def func1(arg):
154  mvals = list(mvals0)
155  mvals[pidx] += arg
156  logger.info("\rfdwrap: " + func.__name__ + " [%i] = % .1e " % (pidx, arg) + ' '*50 + '\r')
157  if key is not None:
158  return func(mvals,**kwargs)[key]
159  else:
160  return func(mvals,**kwargs)
161  return func1
162 
163 def fdwrap_G(tgt,mvals0,pidx):
164  """
165  A driver to fdwrap for gradients (see documentation for fdwrap)
166  Inputs:
167  tgt = The Target containing the objective function that we want to differentiate
168  mvals0 = The 'central' values of the mathematical parameters - i.e. the wrapped function's origin is here.
169  pidx = The index of the parameter that we're differentiating
170  """
171  return fdwrap(tgt.get_X,mvals0,pidx,'X')
172 
173 def fdwrap_H(tgt,mvals0,pidx):
174  """
175  A driver to fdwrap for Hessians (see documentation for fdwrap)
176  Inputs:
177  tgt = The Target containing the objective function that we want to differentiate
178  mvals0 = The 'central' values of the mathematical parameters - i.e. the wrapped function's origin is here.
179  pidx = The index of the parameter that we're differentiating
180  """
181  return fdwrap(tgt.get_G,mvals0,pidx,'G')
182 
183 #method resolution order
184 #type.mro(type(a))
def in_fd_srch()
Invoking this function from anywhere will tell us whether we're being called by a finite-difference f...
def fdwrap_G(tgt, mvals0, pidx)
A driver to fdwrap for gradients (see documentation for fdwrap) Inputs: tgt = The Target containing t...
def f1d7p(f, h)
A highly accurate seven-point finite difference stencil for computing derivatives of a function...
def in_fd()
Invoking this function from anywhere will tell us whether we're being called by a finite-difference f...
def fdwrap(func, mvals0, pidx, key=None, kwargs)
A function wrapper for finite difference designed for differentiating 'get'-type functions.
def f1d5p(f, h)
A highly accurate five-point finite difference stencil for computing derivatives of a function...
def fdwrap_H(tgt, mvals0, pidx)
A driver to fdwrap for Hessians (see documentation for fdwrap) Inputs: tgt = The Target containing th...
def f12d3p(f, h, f0=None)
A three-point finite difference stencil.
def f2var(f, h)
A finite difference stencil for a function of two variables.
def f1d2p(f, h, f0=None)
A two-point finite difference stencil.