sympy : Symbolic Mathematics in Python#

Author: Fabian Pedregosa

Objectives

  1. Evaluate expressions with arbitrary precision.

  2. Perform algebraic manipulations on symbolic expressions.

  3. Perform basic calculus tasks (limits, differentiation and : integration) with symbolic expressions.

  4. Solve polynomial and transcendental equations.

  5. Solve some differential equations.

What is SymPy? SymPy is a Python library for symbolic mathematics. It aims to be an alternative to systems such as Mathematica or Maple while keeping the code as simple as possible and easily extensible. SymPy is written entirely in Python and does not require any external libraries.

Sympy documentation and packages for installation can be found on https://www.sympy.org/

First Steps with SymPy#

Using SymPy as a calculator#

SymPy defines three numerical types: Real, Rational and Integer.

The Rational class represents a rational number as a pair of two Integers: the numerator and the denominator, so Rational(1, 2) represents 1/2, Rational(5, 2) 5/2 and so on:

import sympy as sym
a = sym.Rational(1, 2)
a
\[\displaystyle \frac{1}{2}\]
a*2
\[\displaystyle 1\]

SymPy uses mpmath in the background, which makes it possible to perform computations using arbitrary-precision arithmetic. That way, some special constants, like \(e\), \(pi\), \(oo\) (Infinity), are treated as symbols and can be evaluated with arbitrary precision:

sym.pi**2
\[\displaystyle \pi^{2}\]
sym.pi.evalf()
\[\displaystyle 3.14159265358979\]
(sym.pi + sym.exp(1)).evalf()
\[\displaystyle 5.85987448204884\]

as you see, evalf evaluates the expression to a floating-point number.

There is also a class representing mathematical infinity, called oo:

sym.oo > 99999
\[\displaystyle \text{True}\]
sym.oo + 1
\[\displaystyle \infty\]

Symbols#

In contrast to other Computer Algebra Systems, in SymPy you have to declare symbolic variables explicitly:

x = sym.Symbol('x')
y = sym.Symbol('y')

Then you can manipulate them:

x + y + x - y
\[\displaystyle 2 x\]
(x + y) ** 2
\[\displaystyle \left(x + y\right)^{2}\]

Symbols can now be manipulated using some of python operators: +, -, *, ** (arithmetic), &, |, ~, >>, << (boolean).

Printing

Sympy allows for control of the display of the output. From here we use the following setting for printing:

sym.init_printing(use_unicode=False, wrap_line=True)

Algebraic manipulations

SymPy is capable of performing powerful algebraic manipulations. We’ll take a look into some of the most frequently used: expand and simplify.

Expand

Use this to expand an algebraic expression. It will try to denest powers and multiplications:

sym.expand((x + y) ** 3)
../_images/800a512503edc7f3e6c5dde3e9536a8680a33d7829bf94aa05b0a5bfd199648d.png
3 * x * y ** 2 + 3 * y * x ** 2 + x ** 3 + y ** 3
../_images/800a512503edc7f3e6c5dde3e9536a8680a33d7829bf94aa05b0a5bfd199648d.png

Further options can be given in form on keywords:

sym.expand(x + y, complex=True)
../_images/b097e0cef26ac97000bc80d417d0ce02bff60c7ed80126a30d533059d9f71f3d.png
sym.I * sym.im(x) + sym.I * sym.im(y) + sym.re(x) + sym.re(y)
../_images/b097e0cef26ac97000bc80d417d0ce02bff60c7ed80126a30d533059d9f71f3d.png
sym.expand(sym.cos(x + y), trig=True)
../_images/6749f5a0933638ad6213282fd63f008897632e6e21982767b53fa9bfccb7c622.png
sym.cos(x) * sym.cos(y) - sym.sin(x) * sym.sin(y)
../_images/6749f5a0933638ad6213282fd63f008897632e6e21982767b53fa9bfccb7c622.png

Simplify#

Use simplify if you would like to transform an expression into a simpler form:

sym.simplify((x + x * y) / x)
../_images/fb4fa7864131d76e11ad3b82133ab84a839d92140eb752c4842caae86e07f4d2.png

Simplification is a somewhat vague term, and more precises alternatives to simplify exists: powsimp (simplification of exponents), trigsimp (for trigonometric expressions) , logcombine, radsimp, together.

Calculus#

Limits#

Limits are easy to use in SymPy, they follow the syntax limit(function, variable, point), so to compute the limit of \(f(x)\) as \(x \rightarrow 0\), you would issue limit(f, x, 0):

sym.limit(sym.sin(x) / x, x, 0)
../_images/d81096050bd44ce57b5d5fe4208dfd494a47c011aecee7a2c422785cd87b6ef4.png

you can also calculate the limit at infinity:

sym.limit(x, x, sym.oo)
../_images/c3d7c349d9ed33bd6d3cd8565aa29fdac9b1b61ba635338c0dc3640e23bfb227.png
sym.limit(1 / x, x, sym.oo)
../_images/702ba12f4bf2cef7092842f0bdd4dc2b8bfdc07d13bc79cc481075cd1cc7c88c.png
sym.limit(x ** x, x, 0)
../_images/d81096050bd44ce57b5d5fe4208dfd494a47c011aecee7a2c422785cd87b6ef4.png

Differentiation#

You can differentiate any SymPy expression using diff(func, var). Examples:

sym.diff(sym.sin(x), x)
../_images/477e1b0b05f1059a71a2db2d97ba8d28f59c6235c0ffe8c629e15dd77f6b1067.png
sym.diff(sym.sin(2 * x), x)
../_images/98076f8647ed7d9cf989de76709ef578bfa0aa0cdd0027ca6bf1829d3fd93b00.png
sym.diff(sym.tan(x), x)
../_images/791b2a690b8f15b3170db55bf34ff145ae144dfe6d0ce49cec3cfaa1e7cec3c2.png

You can check that it is correct by:

sym.limit((sym.tan(x + y) - sym.tan(x)) / y, y, 0)
../_images/1d65d8430ae6832a634388d2aa201c6abd706b4c217f7932971a194ad64f2189.png

Which is equivalent since

\[ \sec(x) = \frac{1}{\cos(x)} and \sec^2(x) = \tan^2(x) + 1. \]

You can check this as well:

sym.trigsimp(sym.diff(sym.tan(x), x))
../_images/1d65d8430ae6832a634388d2aa201c6abd706b4c217f7932971a194ad64f2189.png

Higher derivatives can be calculated using the diff(func, var, n) method:

sym.diff(sym.sin(2 * x), x, 1)
../_images/98076f8647ed7d9cf989de76709ef578bfa0aa0cdd0027ca6bf1829d3fd93b00.png
sym.diff(sym.sin(2 * x), x, 2)
../_images/188e000356e13b8802d6ff5c3432ce75cb546aa8cfe0bd62faffa6b868c7dd48.png
sym.diff(sym.sin(2 * x), x, 3)
../_images/e1227860ac82b4a37754bf66be3c66c002c961185898e1127777e93f56f56525.png

Series expansion#

SymPy also knows how to compute the Taylor series of an expression at a point. Use series(expr, var):

sym.series(sym.cos(x), x)
../_images/e295a1a55266d29eaaf5b1ad1f351e5b8ade0b9fbd04f500af1f9b2c7a76477c.png
sym.series(1/sym.cos(x), x)
../_images/546d763059fe60640ecbefa4cfbda32975b8f3d238fdd3a04a4a363aed0b32d4.png

Integration#

SymPy has support for indefinite and definite integration of transcendental elementary and special functions via integrate() facility, which uses the powerful extended Risch-Norman algorithm and some heuristics and pattern matching. You can integrate elementary functions:

sym.integrate(6 * x ** 5, x)
../_images/ec2296971a5e0de9af212c8bc6b6d41a475f9a6eea8eb11d1983db377e6cc113.png
sym.integrate(sym.sin(x), x)
../_images/8794a4f333c3b588125eff55ef0422f971ed09674bccd007c9acfd331e0eb631.png
sym.integrate(sym.log(x), x)
../_images/9917bffce7555f82d536b334d9f6e2818a02c846061ba7ad5599329ed291babc.png
sym.integrate(2 * x + sym.sinh(x), x)
../_images/db7bc805ceb17ec1749250895d951df9d76cce5353eaac55ad2451d50f76ac2e.png

Also special functions are handled easily:

sym.integrate(sym.exp(-x ** 2) * sym.erf(x), x)
../_images/7b7c7cb5bd9d1f51a4f444369885f383abb37820cb055f197e19f2362ab6136d.png

It is possible to compute definite integral:

sym.integrate(x**3, (x, -1, 1))
../_images/702ba12f4bf2cef7092842f0bdd4dc2b8bfdc07d13bc79cc481075cd1cc7c88c.png
sym.integrate(sym.sin(x), (x, 0, sym.pi / 2))
../_images/d81096050bd44ce57b5d5fe4208dfd494a47c011aecee7a2c422785cd87b6ef4.png
sym.integrate(sym.cos(x), (x, -sym.pi / 2, sym.pi / 2))
../_images/d09c16c60c1bec6d87b5a6ea36a28d98601be002bd4b459592b55e0896ad9754.png

Also improper integrals are supported as well:

sym.integrate(sym.exp(-x), (x, 0, sym.oo))
../_images/d81096050bd44ce57b5d5fe4208dfd494a47c011aecee7a2c422785cd87b6ef4.png
sym.integrate(sym.exp(-x ** 2), (x, -sym.oo, sym.oo))
../_images/ccef02a8d83a3c43a6ef7751e0c9d76bac908e2bb2411907f1c600908ecb5eff.png

Equation solving#

SymPy is able to solve algebraic equations, in one and several variables using solveset():

sym.solveset(x ** 4 - 1, x)
../_images/bd633248cdd437ec14c31d564d169ca124168c2ebf74e4f0076bc202f80db13c.png

As you can see it takes as first argument an expression that is supposed to be equaled to 0. It also has (limited) support for transcendental equations:

sym.solveset(sym.exp(x) + 1, x)
../_images/87a42e6be235a5d6e536d97c66e4c6bb5f2223f5142bd9dd88a33c209d614bd4.png

Systems of linear equations

Sympy is able to solve a large part of polynomial equations, and is also capable of solving multiple equations with respect to multiple variables giving a tuple as second argument. To do this you use the solve() command:

solution = sym.solve((x + 5 * y - 2, -3 * x + 6 * y - 15), (x, y))
solution[x], solution[y]
../_images/21a841ecbc2e426d1bcf1285deeb3a1dc6e8fe21aa009b4bd3fd4fa2e34204e5.png

Another alternative in the case of polynomial equations is factor. factor returns the polynomial factorized into irreducible terms, and is capable of computing the factorization over various domains:

f = x ** 4 - 3 * x ** 2 + 1
sym.factor(f)
../_images/94e178936bdfd9f09bc6bdd297bbba3409308f1f636b930fc1acabbee76a54de.png
sym.factor(f, modulus=5)
../_images/646c14c63fc0b8026c24c6cb3062f4b4edb61f7dd30abb9ae80dcea90d67d8ea.png

SymPy is also able to solve boolean equations, that is, to decide if a certain boolean expression is satisfiable or not. For this, we use the function satisfiable:

sym.satisfiable(x & y)
{y: True, x: True}

This tells us that (x & y) is True whenever x and y are both True. If an expression cannot be true, i.e. no values of its arguments can make the expression True, it will return False:

sym.satisfiable(x & ~x)
False

Linear Algebra#

Matrices#

Matrices are created as instances from the Matrix class:

sym.Matrix([[1, 0], [0, 1]])
../_images/3a403c711c9ecfce96798b36ce6bc090e6f902c4f0af87a494c3ad13d0de3dfd.png

unlike a NumPy array, you can also put Symbols in it:

x, y = sym.symbols('x, y')
A = sym.Matrix([[1, x], [y, 1]])
A
../_images/b90ba21f38f65cadc1fe432c95ff0f08ef967df8eb93be06d69b6cd74d76446b.png
A**2
../_images/2465698f2942f3ba868b640cfc0f4fd9416c8b089d5b2c04aa45d684c27fd801.png

Differential Equations#

SymPy is capable of solving (some) Ordinary Differential. To solve differential equations, use dsolve. First, create an undefined function by passing cls=Function to the symbols function:

f, g = sym.symbols('f g', cls=sym.Function)

f and g are now undefined functions. We can call f(x), and it will represent an unknown function:

f(x)
../_images/dbb73e9960c57a831ff2035b302a104ea7d8d4fb13d4908dcb1ecccabffce514.png
f(x).diff(x, x) + f(x)
../_images/90ceb49f5cce764be0384ce5d03d4788471caa1e23d3c79c4f6b31bbcb7d8911.png
sym.dsolve(f(x).diff(x, x) + f(x), f(x))
../_images/fea0df958a31714f82a9f12b6a765d85df41b80fae91916f839a2dd6adf62c39.png

Keyword arguments can be given to this function in order to help if find the best possible resolution system. For example, if you know that it is a separable equations, you can use keyword hint='separable' to force dsolve to resolve it as a separable equation:

sym.dsolve(sym.sin(x) * sym.cos(f(x)) + sym.cos(x) * sym.sin(f(x)) * f(x).diff(x), f(x), hint='separable')
../_images/be9f43442b29a22de242604d476b2b3b334ab54ec467768415204a5a9ab050fb.png