1 """ Finite difference module. """ 2 from __future__
import division
6 from forcebalance.output
import getLogger
7 logger = getLogger(__name__)
9 def f1d2p(f, h, f0 = None):
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. 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. 23 f = The one-variable function f(x) that we're differentiating 24 h = The finite difference step size, usually a small number 27 fp = The finite difference derivative of the function f(x) around x=0. 30 f0, f1 = [f(i*h)
for i
in [0, 1]]
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. 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/ 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. 53 f = The one-variable function f(x) that we're differentiating 54 h = The finite difference step size, usually a small number 57 fp = The finite difference derivative of the function f(x) around x=0. 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)
65 A highly accurate seven-point finite difference stencil 66 for computing derivatives of a function. 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)
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)
78 def f12d3p(f, h, f0 = None):
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 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. 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. 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. 100 f = The one-variable function f(x) that we're differentiating 101 h = The finite difference step size, usually a small number 104 fp = The finite difference derivative of the function f(x) around x=0. 107 fm1, f0, f1 = [f(i*h)
for i
in [-1, 0, 1]]
109 fm1, f1 = [f(i*h)
for i
in [-1, 1]]
111 fpp = (fm1-2*f0+f1)/(h*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)
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. """ 123 return any([i
in [j[2]
for j
in traceback.extract_stack()]
for i
in [
'f1d2p',
'f12d3p',
'f1d5p',
'f12d7p',
'f1d7p']])
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']])
131 def fdwrap(func,mvals0,pidx,key=None,**kwargs):
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 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) 151 func1 = Wrapped version of func, which takes a single float argument. 156 logger.info(
"\rfdwrap: " + func.__name__ +
" [%i] = % .1e " % (pidx, arg) +
' '*50 +
'\r')
158 return func(mvals,**kwargs)[key]
160 return func(mvals,**kwargs)
165 A driver to fdwrap for gradients (see documentation for fdwrap) 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 171 return fdwrap(tgt.get_X,mvals0,pidx,
'X')
175 A driver to fdwrap for Hessians (see documentation for fdwrap) 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 181 return fdwrap(tgt.get_G,mvals0,pidx,
'G')
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.