SymPy Examples#
sources: http://docs.sympy.org/latest/tutorial/ http://nbviewer.ipython.org/github/ipython/ipython/blob/master/examples/notebooks/SymPy Examples.ipynb
SymPy provides support for symbolic math to python, similar to what you would do with Mathematica or Maple. The major difference is that it acts just like any other python module, so you can use the symbolic math together in your own python projects with the rest of python functionality.
The following import and function (init_session()
) sets up a nice environment for us when working in Jupyter
from sympy import init_session
init_session(use_latex="mathjax")
IPython console for SymPy 1.13.1 (Python 3.11.9-64-bit) (ground types: python)
These commands were executed:
>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)
>>> init_printing()
Documentation can be found at https://docs.sympy.org/1.13.1/
import math
SymPy types and basic symbolic manipulation#
Sympy defines its own types, you can convert them to python types, but you don’t always want to (and will probably lose accuracy when you do).
print(math.sqrt(2))
1.4142135623730951
print(sqrt(2))
sqrt(2)
print(sqrt(8))
2*sqrt(2)
#help(sqrt(8))
We can do symbolic math not just on numbers, but we can tell SymPy what to treat as a symbol, using symbols()
from sympy import symbols
x, y, z = symbols("x y z")
expr = x + 2*y
expr
expr - 1
expr - y
f = x*expr
f
g = expand(f)
g
factor(g)
substitution#
SymPy provides methods to substitute values for symbols in symbolic expressions. Note, the follow likely does not do what you expect:
expr = sin(z*2*pi)
z = 0
expr
We’ve now redefined z
to be a python type
type(z)
int
to do substitution, we use the subs()
method
expr = sin(x*2*pi)
expr
a = expr.subs(x, 0.125)
a
Note that this is not a floating point number – it is still a SymPy object. To make it floating point, we can use evalf()
b = a.evalf()
print(b, type(b))
0.707106781186548 <class 'sympy.core.numbers.Float'>
This is still a SymPy object, because SymPy can do arbitrary precision
a.evalf(50)
want regular python types?
c = float(b)
print(c, type(c))
0.7071067811865476 <class 'float'>
Python and SymPy#
x, y, z, t = symbols('x y z t')
SymPy symbols are just objects and when you do operations on two sympy objects the result is a sympy object.
When you combine a sympy and python object, the result is also a sympy object.
But we need to be careful when doing fractions. For instance doing x + 1/3
will first compute 1/3
in python (giving 0.333...
) and then add it to the sympy x
symbol. The Rational()
function makes this all happen in sympy
f = expr + Rational(1,3)
f
expr + 1/3
equality#
=
is still the assignment operator of python (it does not mean symbolic equality), and ==
is still the logical test (exact structural equality). There is a separate object, Eq()
to specify symbolic equality.
And testing for algebraic equality is not always accomplished using ==
, since that tests for structural equality.
x + 1 == 4
False
Eq(x + 1, 4)
a = (x + 1)**2
b = x**2 + 2*x + 1 # these are algebraically equal
a == b
False
We can use simplify()
to test for algebraic equality
simplify(a - b)
a = cos(x) + I*sin(x)
a
simplify(a)
More substitution#
note that substitution returns a new expression: SymPy expressions are immutable
expr = cos(x)
expr.subs(x, 0)
expr
x
multiple substitutions, pass a list of tuples
expr = x**3 + 4*x*y - z
expr
expr.subs([(x, 2), (y, 4), (z, 0)])
simplifying#
There is not unique definition of what the simplest form of an expression is.
simplify()
tries lots of methods for simplification
simplify(sin(x)**2 + cos(x)**2)
simplify( (x**3 + x**2 - x - 1)/(x**2 + 2*x + 1) )
simplify(gamma(x)/gamma(x - 2))
but sometimes it doesn’t have your idea of what the simplest form is
simplify(x**2 + 2*x + 1)
instead factor may be what you want
factor(x**2 + 2*x + 1)
polynomial simplification#
expand((x + 1)**2)
expand((x + 2)*(x - 3))
expand( (x + 1)*(x - 2) - (x - 1)*x)
factor(x**2*z + 4*x*y*z + 4*y**2*z)
factor_list(x**2*z + 4*x*y*z + 4*y**2*z)
collect collects common powers
expr = x*y + x - 3 + 2*x**2 - z*x**2 + x**3
expr
collected_expr = collect(expr, x)
collected_expr
cancel cancels
a = (x**2 + 2*x + 1)/(x**2 + x)
a
cancel(a)
trigsimp simplifies trigonometric identities
trigsimp(sin(x)**4 - 2*cos(x)**2*sin(x)**2 + cos(x)**4)
trigsimp(sin(x)*tan(x)/sec(x))
the tutorial discusses some of the nuances of simplification of powers and special functions
Calculus#
Calculus operations are simple in SymPy
derivatives#
diff(cos(x), x)
diff(exp(x**2), x)
third derivative
diff(x**4, x, 3)
differentiate different variables
expr = exp(x*y*z)
diff(expr, x, y, z)
unevaluated derivatives can be useful for building up ODEs and PDEs
deriv = Derivative(expr, x, y, z)
deriv
deriv.doit()
integrals#
definite and indefinite integrals are supported
integrate(cos(x), x)
definite integral – note the construction of the infinity
integrate(exp(-x), (x, 0, oo))
double integral
integrate(exp(-x**2 - y**2), (x, -oo, oo), (y, -oo, oo))
if it is unable to do the integral, it returns an Integral object
expr = integrate(x**x, x)
print(expr)
expr
Integral(x**x, x)
a = x / sqrt(x**4 + 10*x**2 - 96*x - 71) # example from Wikipedia Risch algorithm page)
a
integrate(a, x) # this has a known solution, but SymPy fails to find it
limits#
limit(sin(x)/x, x, 0)
series expansions#
expr = exp(sin(x))
a = expr.series(x, 0, 10)
a
c = log(x).series(x, x0=1, n=6)
c
simplify(c.removeO())
solvers#
solveset()
is the main interface to solvers in SymPy. Note that it used to be solve()
, but this has been replaced (see http://docs.sympy.org/latest/modules/solvers/solveset.html)
If no Eq() is done, then it is assumed to be equal to 0
solveset(x**2 - x, x)
you can restrict the domain of the solution (e.g. to reals). Recall that Z is the set of integers
solveset(sin(x) - 1, x, domain=S.Reals)
linear systems#
linsolve()
is the interface to linear systems
linsolve([x - y + 2, x + y - 3], [x, y])
linsolve([x + y + z - 1, x + y + 2*z - 3 ], (x, y, z))
roots will report if a solution is multiple by listing it multiple times
roots(x**3 - 6*x**2 + 9*x, x)
0 is 1 root, and 3 is 2 more roots
Differential equations#
you need an undefined function (f and g already are by our init_session() above, but we’ve probably reset these
f, g = symbols('f g', cls=Function)
f(x)
f(x).diff(x)
diffeq = Eq(f(x).diff(x, 2) - 2*f(x).diff(x) + f(x), sin(x))
diffeq
dsolve(diffeq, f(x))
Matrices#
consider the Euler equations:
where
from sympy.abc import rho
rho, u, c = symbols('rho u c')
A = Matrix([[u, rho, 0], [0, u, rho**-1], [0, c**2 * rho, u]])
A
A.row(0)
The eigenvalues of the system are the speeds at which information propagates
A.eigenvals()
You can diagonalize it, such that $\( A = PDP^{-1}\)$
P, D = A.diagonalize()
\(D\) will be a matrix of the eigenvalues
D
\(P\) will be the matrix of right eigenvectors
P
Inverse
A**-1
Units#
Sympy can attach units to numbers and propagate them through
from sympy.physics.units import newton, kilogram, meter, second, convert_to
F = 1 * kilogram * 9.81 * meter / second**2
convert_to(F, newton)