Navigation

Source code for sympy.calculus.finite_diff

"""Finite difference weights=========================This module implements an algorithm for efficient generation of finitedifference weights for ordinary differentials of functions forderivatives from 0 (interpolation) up to arbitrary order.The core algorithm is provided in the finite difference weight generatingfunction (finite_diff_weights), and two convenience functions are providedfor:- estimating a derivative (or interpolate) directly from a series of points is also provided (``apply_finite_diff``).- making a finite difference approximation of a Derivative instance (``as_finite_diff``)."""fromsympyimportSfromsympy.core.compatibilityimportiterable,range

[docs]defas_finite_diff(derivative,points=1,x0=None,wrt=None):""" Returns an approximation of a derivative of a function in the form of a finite difference formula. The expression is a weighted sum of the function at a number of discrete values of (one of) the independent variable(s). Parameters ========== derivative: a Derivative instance (needs to have an variables and expr attribute). points: sequence or coefficient, optional If sequence: discrete values (length >= order+1) of the independent variable used for generating the finite difference weights. If it is a coefficient, it will be used as the step-size for generating an equidistant sequence of length order+1 centered around x0. default: 1 (step-size 1) x0: number or Symbol, optional the value of the independent variable (wrt) at which the derivative is to be approximated. default: same as wrt wrt: Symbol, optional "with respect to" the variable for which the (partial) derivative is to be approximated for. If not provided it is required that the Derivative is ordinary. default: None Examples ======== >>> from sympy import symbols, Function, exp, sqrt, Symbol, as_finite_diff >>> x, h = symbols('x h') >>> f = Function('f') >>> as_finite_diff(f(x).diff(x)) -f(x - 1/2) + f(x + 1/2) The default step size and number of points are 1 and ``order + 1`` respectively. We can change the step size by passing a symbol as a parameter: >>> as_finite_diff(f(x).diff(x), h) -f(-h/2 + x)/h + f(h/2 + x)/h We can also specify the discretized values to be used in a sequence: >>> as_finite_diff(f(x).diff(x), [x, x+h, x+2*h]) -3*f(x)/(2*h) + 2*f(h + x)/h - f(2*h + x)/(2*h) The algorithm is not restricted to use equidistant spacing, nor do we need to make the approximation around x0, but we can get an expression estimating the derivative at an offset: >>> e, sq2 = exp(1), sqrt(2) >>> xl = [x-h, x+h, x+e*h] >>> as_finite_diff(f(x).diff(x, 1), xl, x+h*sq2) 2*h*((h + sqrt(2)*h)/(2*h) - (-sqrt(2)*h + h)/(2*h))*f(E*h + x)/\((-h + E*h)*(h + E*h)) + (-(-sqrt(2)*h + h)/(2*h) - \(-sqrt(2)*h + E*h)/(2*h))*f(-h + x)/(h + E*h) + \(-(h + sqrt(2)*h)/(2*h) + (-sqrt(2)*h + E*h)/(2*h))*f(h + x)/(-h + E*h) Partial derivatives are also supported: >>> y = Symbol('y') >>> d2fdxdy=f(x,y).diff(x,y) >>> as_finite_diff(d2fdxdy, wrt=x) -f(x - 1/2, y) + f(x + 1/2, y) See also ======== sympy.calculus.finite_diff.apply_finite_diff sympy.calculus.finite_diff.finite_diff_weights """ifwrtisNone:wrt=derivative.variables[0]# we need Derivative to be univariate to guess wrtifany(v!=wrtforvinderivative.variables):raiseValueError('if the function is not univariate'+' then `wrt` must be given')order=derivative.variables.count(wrt)ifx0isNone:x0=wrtifnotiterable(points):# points is simply the step-size, let's make it a# equidistant sequence centered around x0iforder%2==0:# even order => odd number of points, grid point includedpoints=[x0+points*iforiinrange(-order//2,order//2+1)]else:# odd order => even number of points, half-way wrt grid pointpoints=[x0+points*i/S(2)foriinrange(-order,order+1,2)]iflen(points)<order+1:raiseValueError("Too few points for order %d"%order)returnapply_finite_diff(order,points,[derivative.expr.subs({wrt:x})forxinpoints],x0)