Basic Operations#
Here we discuss some of the most basic operations needed for expression manipulation in SymPy. Some more advanced operations will be discussed later in the advanced expression manipulation section.
>>> from sympy import * >>> x, y, z = symbols("x y z")
Substitution#
One of the most common things you might want to do with a mathematical expression is substitution. Substitution replaces all instances of something in an expression with something else. It is done using the subs method. For example
>>> expr = cos(x) + 1 >>> expr.subs(x, y) cos(y) + 1
Substitution is usually done for one of two reasons:
- Evaluating an expression at a point. For example, if our expression is cos(x) + 1 and we want to evaluate it at the point x = 0 , so that we get cos(0) + 1 , which is 2.
>>> expr = x**y >>> expr x**y >>> expr = expr.subs(y, x**y) >>> expr x**(x**y) >>> expr = expr.subs(y, x**x) >>> expr x**(x**(x**x))
The second is if we want to perform a very controlled simplification, or perhaps a simplification that SymPy is otherwise unable to do. For example, say we have \(\sin(2x) + \cos(2x)\) , and we want to replace \(\sin(2x)\) with \(2\sin(x)\cos(x)\) . As we will learn later, the function expand_trig does this. However, this function will also expand \(\cos(2x)\) , which we may not want. While there are ways to perform such precise simplification, and we will learn some of them in the advanced expression manipulation section, an easy way is to just replace \(\sin(2x)\) with \(2\sin(x)\cos(x)\) .
>>> expr = sin(2*x) + cos(2*x) >>> expand_trig(expr) 2*sin(x)*cos(x) + 2*cos(x)**2 - 1 >>> expr.subs(sin(2*x), 2*sin(x)*cos(x)) 2*sin(x)*cos(x) + cos(2*x)
There are two important things to note about subs . First, it returns a new expression. SymPy objects are immutable. That means that subs does not modify it in-place. For example
>>> expr = cos(x) >>> expr.subs(x, 0) 1 >>> expr cos(x) >>> x x
SymPy expressions are immutable. No function will change them in-place.
Here, we see that performing expr.subs(x, 0) leaves expr unchanged. In fact, since SymPy expressions are immutable, no function will change them in-place. All functions will return new expressions.
To perform multiple substitutions at once, pass a list of (old, new) pairs to subs .
>>> expr = x**3 + 4*x*y - z >>> expr.subs([(x, 2), (y, 4), (z, 0)]) 40
It is often useful to combine this with a list comprehension to do a large set of similar replacements all at once. For example, say we had \(x^4 — 4x^3 + 4x^2 — 2x + 3\) and we wanted to replace all instances of \(x\) that have an even power with \(y\) , to get \(y^4 — 4x^3 + 4y^2 — 2x + 3\) .
>>> expr = x**4 - 4*x**3 + 4*x**2 - 2*x + 3 >>> replacements = [(x**i, y**i) for i in range(5) if i % 2 == 0] >>> expr.subs(replacements) -4*x**3 - 2*x + y**4 + 4*y**2 + 3
Converting Strings to SymPy Expressions#
The sympify function (that’s sympify , not to be confused with simplify ) can be used to convert strings into SymPy expressions.
>>> str_expr = "x**2 + 3*x - 1/2" >>> expr = sympify(str_expr) >>> expr x**2 + 3*x - 1/2 >>> expr.subs(x, 2) 19/2
sympify uses eval . Don’t use it on unsanitized input.
evalf #
To evaluate a numerical expression into a floating point number, use evalf .
>>> expr = sqrt(8) >>> expr.evalf() 2.82842712474619
SymPy can evaluate floating point expressions to arbitrary precision. By default, 15 digits of precision are used, but you can pass any number as the argument to evalf . Let’s compute the first 100 digits of \(\pi\) .
>>> pi.evalf(100) 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
To numerically evaluate an expression with a Symbol at a point, we might use subs followed by evalf , but it is more efficient and numerically stable to pass the substitution to evalf using the subs flag, which takes a dictionary of Symbol: point pairs.
>>> expr = cos(2*x) >>> expr.evalf(subs=x: 2.4>) 0.0874989834394464
Sometimes there are roundoff errors smaller than the desired precision that remain after an expression is evaluated. Such numbers can be removed at the user’s discretion by setting the chop flag to True.
>>> one = cos(1)**2 + sin(1)**2 >>> (one - 1).evalf() -0.e-124 >>> (one - 1).evalf(chop=True) 0
lambdify #
subs and evalf are good if you want to do simple evaluation, but if you intend to evaluate an expression at many points, there are more efficient ways. For example, if you wanted to evaluate an expression at a thousand points, using SymPy would be far slower than it needs to be, especially if you only care about machine precision. Instead, you should use libraries like NumPy and SciPy.
The easiest way to convert a SymPy expression to an expression that can be numerically evaluated is to use the lambdify function. lambdify acts like a lambda function, except it converts the SymPy names to the names of the given numerical library, usually NumPy. For example
>>> import numpy >>> a = numpy.arange(10) >>> expr = sin(x) >>> f = lambdify(x, expr, "numpy") >>> f(a) [ 0. 0.84147098 0.90929743 0.14112001 -0.7568025 -0.95892427 -0.2794155 0.6569866 0.98935825 0.41211849]
lambdify uses eval . Don’t use it on unsanitized input.
You can use other libraries than NumPy. For example, to use the standard library math module, use «math» .
>>> f = lambdify(x, expr, "math") >>> f(0.1) 0.0998334166468
To use lambdify with numerical libraries that it does not know about, pass a dictionary of sympy_name:numerical_function pairs. For example
>>> def mysin(x): . """ . My sine. Note that this is only accurate for small x. . """ . return x >>> f = lambdify(x, expr, "sin":mysin>) >>> f(0.1) 0.1
Introduction#
Symbolic computation deals with the computation of mathematical objects symbolically. This means that the mathematical objects are represented exactly, not approximately, and mathematical expressions with unevaluated variables are left in symbolic form.
Let’s take an example. Say we wanted to use the built-in Python functions to compute square roots. We might do something like this
>>> import math >>> math.sqrt(9) 3.0
9 is a perfect square, so we got the exact answer, 3. But suppose we computed the square root of a number that isn’t a perfect square
Here we got an approximate result. 2.82842712475 is not the exact square root of 8 (indeed, the actual square root of 8 cannot be represented by a finite decimal, since it is an irrational number). If all we cared about was the decimal form of the square root of 8, we would be done.
But suppose we want to go further. Recall that \(\sqrt = \sqrt = 2\sqrt\) . We would have a hard time deducing this from the above result. This is where symbolic computation comes in. With a symbolic computation system like SymPy, square roots of numbers that are not perfect squares are left unevaluated by default
>>> import sympy >>> sympy.sqrt(3) sqrt(3)
Furthermore—and this is where we start to see the real power of symbolic computation—symbolic results can be symbolically simplified.
A More Interesting Example#
The above example starts to show how we can manipulate irrational numbers exactly using SymPy. But it is much more powerful than that. Symbolic computation systems (which by the way, are also often called computer algebra systems, or just CASs) such as SymPy are capable of computing symbolic expressions with variables.
As we will see later, in SymPy, variables are defined using symbols . Unlike many symbolic manipulation systems, variables in SymPy must be defined before they are used (the reason for this will be discussed in the next section ).
Let us define a symbolic expression, representing the mathematical expression \(x + 2y\) .
>>> from sympy import symbols >>> x, y = symbols('x y') >>> expr = x + 2*y >>> expr x + 2*y
Note that we wrote x + 2*y just as we would if x and y were ordinary Python variables. But in this case, instead of evaluating to something, the expression remains as just x + 2*y . Now let us play around with it:
>>> expr + 1 x + 2*y + 1 >>> expr - x 2*y
Notice something in the above example. When we typed expr — x , we did not get x + 2*y — x , but rather just 2*y . The x and the -x automatically canceled one another. This is similar to how sqrt(8) automatically turned into 2*sqrt(2) above. This isn’t always the case in SymPy, however:
Here, we might have expected \(x(x + 2y)\) to transform into \(x^2 + 2xy\) , but instead we see that the expression was left alone. This is a common theme in SymPy. Aside from obvious simplifications like \(x — x = 0\) and \(\sqrt = 2\sqrt\) , most simplifications are not performed automatically. This is because we might prefer the factored form \(x(x + 2y)\) , or we might prefer the expanded form \(x^2 + 2xy\) . Both forms are useful in different circumstances. In SymPy, there are functions to go from one form to the other
>>> from sympy import expand, factor >>> expanded_expr = expand(x*expr) >>> expanded_expr x**2 + 2*x*y >>> factor(expanded_expr) x*(x + 2*y)
The Power of Symbolic Computation#
The real power of a symbolic computation system such as SymPy is the ability to do all sorts of computations symbolically. SymPy can simplify expressions, compute derivatives, integrals, and limits, solve equations, work with matrices, and much, much more, and do it all symbolically. It includes modules for plotting, printing (like 2D pretty printed output of math formulas, or \(\mathrm<\LaTeX>\) ), code generation, physics, statistics, combinatorics, number theory, geometry, logic, and more. Here is a small sampling of the sort of symbolic power SymPy is capable of, to whet your appetite.
>>> from sympy import * >>> x, t, z, nu = symbols('x t z nu')
This will make all further examples pretty print with unicode characters.
>>> init_printing(use_unicode=True)
Take the derivative of \(\sine^x\) .
>>> diff(sin(x)*exp(x), x) x x ℯ ⋅sin(x) + ℯ ⋅cos(x)
>>> integrate(exp(x)*sin(x) + exp(x)*cos(x), x) x ℯ ⋅sin(x)
>>> integrate(sin(x**2), (x, -oo, oo)) √2⋅√π ───── 2
Solve the differential equation \(y» — y = e^t\) .
>>> y = Function('y') >>> dsolve(Eq(y(t).diff(t, t) - y(t), exp(t)), y(t)) -t ⎛ t⎞ t y(t) = C₂⋅ℯ + ⎜C₁ + ─⎟⋅ℯ ⎝ 2⎠
Find the eigenvalues of \(\left[\begin1 & 2\\2 & 2\end\right]\) .
>>> Matrix([[1, 2], [2, 2]]).eigenvals() ⎧3 √17 3 √17 ⎫ ⎨─ - ───: 1, ─ + ───: 1⎬ ⎩2 2 2 2 ⎭
Rewrite the Bessel function \(J_\left(z\right)\) in terms of the spherical Bessel function \(j_\nu(z)\) .
>>> besselj(nu, z).rewrite(jn) √2⋅√z⋅jn(ν - 1/2, z) ──────────────────── √π
>>> latex(Integral(cos(x)**2, (x, 0, pi))) \int\limits_^ <\pi>\cos^<\left(x \right)>\, dx
Why SymPy?#
There are many computer algebra systems out there. This Wikipedia article lists many of them. What makes SymPy a better choice than the alternatives?
First off, SymPy is completely free. It is open source, and licensed under the liberal BSD license, so you can modify the source code and even sell it if you want to. This contrasts with popular commercial systems like Maple or Mathematica that cost hundreds of dollars in licenses.
Second, SymPy uses Python. Most computer algebra systems invent their own language. Not SymPy. SymPy is written entirely in Python, and is executed entirely in Python. This means that if you already know Python, it is much easier to get started with SymPy, because you already know the syntax (and if you don’t know Python, it is really easy to learn). We already know that Python is a well-designed, battle-tested language. The SymPy developers are confident in their abilities in writing mathematical software, but programming language design is a completely different thing. By reusing an existing language, we are able to focus on those things that matter: the mathematics.
Another computer algebra system, Sage also uses Python as its language. But Sage is large, with a download of over a gigabyte. An advantage of SymPy is that it is lightweight. In addition to being relatively small, it has no dependencies other than Python, so it can be used almost anywhere easily. Furthermore, the goals of Sage and the goals of SymPy are different. Sage aims to be a full featured system for mathematics, and aims to do so by compiling all the major open source mathematical systems together into one. When you call some function in Sage, such as integrate , it calls out to one of the open source packages that it includes. In fact, SymPy is included in Sage. SymPy on the other hand aims to be an independent system, with all the features implemented in SymPy itself.
A final important feature of SymPy is that it can be used as a library. Many computer algebra systems focus on being usable in interactive environments, but if you wish to automate or extend them, it is difficult to do. With SymPy, you can just as easily use it in an interactive Python environment or import it in your own Python application. SymPy also provides APIs to make it easy to extend it with your own custom functions.