Source code for numdifftools.nd_scipy

from __future__ import absolute_import, division, print_function
from scipy.optimize._numdiff import approx_derivative
from scipy.optimize import approx_fprime
import numpy as np


class _Common(object):
    def __init__(self, fun, step=None, method='central', order=2,
                 bounds=(-np.inf, np.inf), sparsity=None):
        self.fun = fun
        self.step = step
        self.method = method
        self.bounds = bounds
        self.sparsity = sparsity


[docs]class Jacobian(_Common): """ Calculate Jacobian with finite difference approximation Parameters ---------- fun : function function of one array fun(x, `*args`, `**kwds`) step : float, optional Stepsize, if None, optimal stepsize is used, i.e., x * _EPS for method==`complex` x * _EPS**(1/2) for method==`forward` x * _EPS**(1/3) for method==`central`. method : {'central', 'complex', 'forward'} defines the method used in the approximation. Examples -------- >>> import numpy as np >>> import numdifftools.nd_scipy as nd #(nonlinear least squares) >>> xdata = np.arange(0,1,0.1) >>> ydata = 1+2*np.exp(0.75*xdata) >>> fun = lambda c: (c[0]+c[1]*np.exp(c[2]*xdata) - ydata)**2 >>> np.allclose(fun([1, 2, 0.75]).shape, (10,)) True >>> dfun = nd.Jacobian(fun) >>> np.allclose(dfun([1, 2, 0.75]), np.zeros((10,3))) True >>> fun2 = lambda x : x[0]*x[1]*x[2]**2 >>> dfun2 = nd.Jacobian(fun2) >>> np.allclose(dfun2([1.,2.,3.]), [[18., 9., 12.]]) True >>> fun3 = lambda x : np.vstack((x[0]*x[1]*x[2]**2, x[0]*x[1]*x[2])) TODO: The following does not work: der3 = nd.Jacobian(fun3)([1., 2., 3.]) np.allclose(der3, ... [[18., 9., 12.], [6., 3., 2.]]) True np.allclose(nd.Jacobian(fun3)([4., 5., 6.]), ... [[180., 144., 240.], [30., 24., 20.]]) True np.allclose(nd.Jacobian(fun3)(np.array([[1.,2.,3.], [4., 5., 6.]]).T), ... [[[ 18., 180.], ... [ 9., 144.], ... [ 12., 240.]], ... [[ 6., 30.], ... [ 3., 24.], ... [ 2., 20.]]]) True """ def __call__(self, x, *args, **kwds): x = np.atleast_1d(x) method = dict(complex='cs', central='3-point', forward='2-point', backward='2-point')[self.method] options = dict(method=method, rel_step=self.step, args=args, kwargs=kwds, bounds=self.bounds, sparsity=self.sparsity) grad = approx_derivative(self.fun, x, **options) return grad
[docs]class Gradient(Jacobian): """ Calculate Gradient with finite difference approximation Parameters ---------- fun : function function of one array fun(x, `*args`, `**kwds`) step : float, optional Stepsize, if None, optimal stepsize is used, i.e., x * _EPS for method==`complex` x * _EPS**(1/2) for method==`forward` x * _EPS**(1/3) for method==`central`. method : {'central', 'complex', 'forward'} defines the method used in the approximation. Examples -------- >>> import numpy as np >>> import numdifftools.nd_scipy as nd >>> fun = lambda x: np.sum(x**2) >>> dfun = nd.Gradient(fun) >>> np.allclose(dfun([1,2,3]), [ 2., 4., 6.]) True # At [x,y] = [1,1], compute the numerical gradient # of the function sin(x-y) + y*exp(x) >>> sin = np.sin; exp = np.exp >>> z = lambda xy: sin(xy[0]-xy[1]) + xy[1]*exp(xy[0]) >>> dz = nd.Gradient(z) >>> grad2 = dz([1, 1]) >>> np.allclose(grad2, [ 3.71828183, 1.71828183]) True # At the global minimizer (1,1) of the Rosenbrock function, # compute the gradient. It should be essentially zero. >>> rosen = lambda x : (1-x[0])**2 + 105.*(x[1]-x[0]**2)**2 >>> rd = nd.Gradient(rosen) >>> grad3 = rd([1,1]) >>> np.allclose(grad3,[0, 0], atol=1e-7) True See also -------- Hessian, Jacobian """ def __call__(self, x, *args, **kwds): return super(Gradient, self).__call__(np.atleast_1d(x).ravel(), *args, **kwds).squeeze()
if __name__ == '__main__': from numdifftools.testing import test_docstrings test_docstrings(__file__)