Differentiating and integrating symbolically using SymPy
At some point, you may have to differentiate a function that is not a simple polynomial, and you may need to do this in some kind of automated fashion, for example, if you are writing software for education. The Python scientific stack includes a package called SymPy, which allows us to create and manipulate symbolic mathematical expressions within Python. In particular, SymPy can perform differentiation and integration of symbolic functions, just like a mathematician.
In this recipe, we will create a symbolic function, and then differentiate and integrate this function using the SymPy library.
Getting ready
Unlike some of the other scientific Python packages, there does not seem to be a standard alias under which SymPy is imported in the literature. Instead the documentation uses a star import at several points, which is not in line with the PEP8 style guide. This is possibly to make the mathematical expressions more natural. We will simply import the module under its name sympy, to avoid any confusion with the scipy package's standard abbreviation, sp (which is the natural choice for sympy too):
import sympy
In this recipe, we will define a symbolic expression that represents the function
How to do it...
Differentiating and integrating symbolically (as you would do by hand) is very easy using the SymPy package. Follow these steps to see how it is done:
- Once SymPy is imported, we define the symbols that will appear in our expressions. This is a Python object that has no particular value, just like a mathematical variable, but can be used in formulas and expressions to represent many different values simultaneously. For this recipe, we need only define a symbol for x, since we will only require constant (literal) symbols and functions in addition to this. We use the symbols routine from sympy to define a new symbol. To keep the notation simple, we will name this new symbol x:
x = sympy.symbols('x')
- The symbols defined using the symbols function support all of the arithmetic operations, so we can construct the expression directly using the symbol x we just defined:
f = (x**2 - 2*x)*sympy.exp(3 - x)
- Now we can use the symbolic calculus capabilities of SymPy to compute the derivative of f, that is, differentiate f. We do this using the diff routine in sympy, which differentiates a symbolic expression with respect to a specified symbol, and returns an expression for the derivative. This is often not expressed in its simplest form, so we use the sympy.simplify routine to simplify the result:
fp = sympy.simplify(sympy.diff(f)) # (x*(2 - x) + 2*x - 2)
*exp(3 - x)
- We can check whether the result of the symbolic differentiation using SymPy is correct, compared to the derivative computed by hand, defined as a SymPy expression, as follows:
fp2 = (2*x - 2)*sympy.exp(3 - x) - (x**2 - 2*x)*sympy.exp(3 - x)
- SymPy equality tests whether two expressions are equal, but not whether they are symbolically equivalent. Therefore, we must first simplify the difference of the two statements we wish to test and test for equality to 0:
sympy.simplify(fp2 - fp) == 0 # True
- We can integrate the function fusing SymPy by using the integratefunction. It is a good idea to also provide the symbol with which the integration is to be performed by providing it as the second optional argument:
F = sympy.integrate(f, x) # -x**2*exp(3 - x)
How it works...
SymPy defines various classes to represent certain kinds of expressions. For example, symbols, represented by the Symbol class, are examples of atomic expressions. Expressions are built up in a similar way to how Python builds an abstract syntax tree from source code. These expression objects can then be manipulated using methods and the standard arithmetic operations.
SymPy also defines standard mathematical functions that can operate on the Symbol objects to create symbolic expressions. The most important feature is the ability to perform symbolic calculus – rather than the numerical calculus that we explore in the remainder of this chapter – and give exact (sometimes called analytic) solutions to calculus problems.
The diff routine from the SymPy package performs differentiation on these symbolic expressions. The result of this routine is usually not in its simplest form, which is why we used the simplify routine to simplify the derivative in the recipe. The integrate routine symbolically integrates a scipy expression with respect to a given symbol. (The diff routine also accepts a symbol argument that specifies the symbol for differentiating against.) This returns an expression whose derivative is the original expression. This routine does not add a constant of integration, which is good practice when doing integrals by hand.
There's more...
SymPy can do much more than simple algebra and calculus. There are submodules for various areas of mathematics, such as number theory, geometry, and other discrete mathematics (such as combinatorics).
SymPy expressions (and functions) can be built into Python functions that can be applied to NumPy arrays. This is done using the lambdify routine from the sympy.utilities module. This converts a SymPy expression to a numerical expression that uses the NumPy equivalents of the SymPy standard functions to evaluate the expressions numerically. The result is similar to defining a Python Lambda, hence the name. For example, we could convert the function and derivative from this recipe into Python functions using this routine:
from sympy.utilities import lambdify
lam_f = lambdify(x, f)
lam_fp = lambdify(x, fp)
The lambdify routine takes two arguments. The first is the variables to be provided, x in the previous code block, and the second is the expression to be evaluated when this function is called. For example, we can evaluate the lambdified SymPy expressions defined previously as if they were ordinary Python functions:
lam_f(4) # 2.9430355293715387
lam_fp(7) # -0.4212596944408861
We can even evaluate these lambdified expressions on NumPy arrays:
lam_f(np.array([0, 1, 2])) # array([ 0. , -7.3890561, 0. ])