DerApproximatorDoc
From OpenOpt
Made by Dmitrey |
Contents |
Introduction
DerApproximator is a small yet important package for getting/checking derivatives (currently only 1st ones), extracted from OpenOpt framework to be standalone Python module. It is required by FuncDesigner (for obtaining derivatives of oofuns beyond standard set without routines to yield them directly) and some OpenOpt solvers (when there are some functions without user-supplied derivatives). Maybe some parallel calculations will be involved in future.
Requirements for the package (as well as for OpenOpt and FuncDesigner) are NumPy and python-setuptools; OS - any where Python and numpy work (Linux, Windows, Mac OS X etc). See Install for more details.
Hint: if your architecture has type float128 (you can check it via 'float128' in dir(numpy) or hasattr(numpy,'float128')), then you can involve this type (convert your point where derivatives have to be obtained) and get more precise answer (by default float64 is used). Also, to improve precision all stencils should be set to maximum value (that is 3 for now).
Obtaining first-order derivatives
To perform this you should use function get_d1.
Usage: get_d1(fun, x, diffInt=1.5e-8, pointVal = None, args=(), stencil = 3, varForDifferentiation = None, exactShape = False)
Parameters:
fun: R^n -> R^m, x0 from R^n: function and point where derivatives should be obtained diffInt - step for stencil pointVal - fun(x) if known (it is used from OpenOpt and FuncDesigner) args - additional args for fun, if not equalk to () then fun(x, *args) will be involved stencil = 1: (f(x+diffInt) - f(x)) / diffInt stencil = 2: (f(x+diffInt) - f(x-diffInt)) / (2*diffInt) stencil = 3: (-f(x+2*diffInt) + 8*f(x+diffInt) - 8*f(x-diffInt) + f(x-2*diffInt)) / (12*diffInt) varForDifferentiation - the parameter is used from FuncDesigner exactShape - set True to forbid possible flattering for 1D arrays
Example:
from DerApproximator import * print(get_d1(lambda x: (x**2).sum(), [1,2,3])) print(get_d1(lambda x: x**2, [1,2,3])) """ Expected output: [ 1.99999993 3.99999998 5.99999996] [[ 2. 0. 0. ] [ 0. 3.99999996 0. ] [ 0. 0. 5.99999996]] """
Obtaining second-order derivatives
To perform this you should use function get_d2. Please pay attention: currently this function is optimized for avoiding NaNs and (lesser) for more exact result, but not for speed.
Usage: get_d2(fun, vars, fun_d = None, diffInt = 1.5e-4, pointVal = None, args=(), stencil = 3, varForDifferentiation = None, exactShape = True, pointD1 = None)
Parameters:
fun: R^n -> R^m, x0 from R^n: function and point where derivatives should be obtained currently implemented for m=1 only! diffInt - step for stencil pointVal - fun(x) if known (it is used from OpenOpt and FuncDesigner) args - additional args for fun, if not equalk to () then fun(x, *args) will be involved stencil - parameter for lower-level routine get_d1 that is currently used in get_d2, default stencil=3 stencil = 1: (f(x+diffInt) - f(x)) / diffInt stencil = 2: (f(x+diffInt) - f(x-diffInt)) / (2*diffInt) stencil = 3: (-f(x+2*diffInt) + 8*f(x+diffInt) - 8*f(x-diffInt) + f(x-2*diffInt)) / (12*diffInt) varForDifferentiation - the parameter is used from FuncDesigner exactShape - set True to forbid possible flattering for 1D arrays pointD1 - value of 1st derivatives in the point involved (if known)
Example:
from DerApproximator import * from numpy import * ff=lambda x: sum(x**2) + x[0]*x[2] x = [1, 2, 3] print(get_d2(ff, x))
[[ 2.00000008e+00 7.01739901e-08 9.99999692e-01] [ 7.01774441e-08 1.99999976e+00 -2.80707803e-07] [ 9.99999692e-01 -2.80703855e-07 1.99999994e+00]]
Check a routine that provides first-order derivatives
To perform this you should use function check_d1.
Usage: check_d1(fun, fun_d, x, func_name='func', diffInt=1.5e-8, pointVal = None, args=(), stencil = 3, maxViolation=0.01, varForCheck = None)
Parameters:
fun: R^n -> R^m, x0 from R^n: function and point where derivatives should be obtained fun_d - user-provided routine for derivatives evaluation to be checked diffInt - step for stencil pointVal - fun(x) if known (it is used from OpenOpt and FuncDesigner) args - additional args for fun, if not equalk to () then fun(x, *args) will be involved stencil = 1: (f(x+diffInt) - f(x)) / diffInt stencil = 2: (f(x+diffInt) - f(x-diffInt)) / (2*diffInt) stencil = 3: (-f(x+2*diffInt) + 8*f(x+diffInt) - 8*f(x-diffInt) + f(x-2*diffInt)) / (12*diffInt) maxViolation - threshold for reporting of incorrect derivatives varForCheck - the parameter is used from FuncDesigner
""" Note that one of output values RD (relative difference) is defined as int(ceil(log10(abs(Diff) / maxViolation + 1e-150))) where Diff = 1 - (info_user+1e-8)/(info_numerical + 1e-8) """ from numpy import * from DerApproximator import * func = lambda x: (x**4).sum() func_d = lambda x: 40 * x**3 x = arange(1.0, 6.0) r = check_d1(func, func_d, x) func = lambda x: x**4 func_d = lambda x: 40 * diag(x**3) x = arange(1.0, 6.0) r = check_d1(func, func_d, x)
Expected output:
func num user-supplied numerical RD 0 +4.000e+01 +4.000e+00 3 1 +3.200e+02 +3.200e+01 3 2 +1.080e+03 +1.080e+02 3 3 +2.560e+03 +2.560e+02 3 4 +5.000e+03 +5.000e+02 3 max(abs(d_user - d_numerical)) = 4500.00002147 (is registered in func number 4) *************************************************************************** func num i,j: dfunc[i]/dx[j] user-supplied numerical RD 0 0 / 0 +4.000e+01 +4.000e+00 3 6 1 / 1 +3.200e+02 +3.200e+01 3 12 2 / 2 +1.080e+03 +1.080e+02 3 18 3 / 3 +2.560e+03 +2.560e+02 3 24 4 / 4 +5.000e+03 +5.000e+02 3 max(abs(d_user - d_numerical)) = 4500.00002147 (is registered in func number 24) ***************************************************************************
- (500) improve get_d2 speed
- involve parallel calculations where it's possible
- write function check_d2
- make get_d2 working on general f: R^n -> R^m (currently it was tested for m=1 only)
- write higher-order derivatives get_d3, maybe more