Symbolic Computation with SymPy¶
This Notebook closely follows the SymPy tutorial.
import sympy as sym
import math
Basic Symbolic Manipulation¶
print(math.sqrt(2)**2)
2.0000000000000004
print(sym.sqrt(2)**2)
2
print(sym.sqrt(8)**2)
8
We can do symbolic math not just on numbers, but we can tell SymPy what to treat as a variable.
x, y, z = sym.symbols("x y z")
expr = x + 2*y
expr
expr - 1
expr - y
f = x*expr
f
g = sym.expand(f)
g
sym.simplify(g**2)
Substitution¶
expr = sym.sin(x*2*sym.pi)
expr
expr.subs(x,1)
a = expr.subs(x,0.125)
a
type(a)
sympy.core.mul.Mul
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.
sym.pi.evalf(100)
Want regular python types?
c = float(b)
print(c, type(c))
0.7071067811865476 <class 'float'>
Using SymPy Interactively¶
For convenience, we will import everything from sympy and use it interatively in a calculator-like environment.
from sympy import *
The following statements in SymPy tutorials are meant to make output look pretty in Jupyter Notebook. However, they are not needed for the latest versions of iPython and Jupyter Notebook, so we omit them.
from sympy.interactive import printing
printing.init_printing()
Python and SymPy¶
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 now we need to be careful when doing fractions. For instance doing x + 1/3 will first compute 1/3 in python (giving 0 or 0.333... depending on the division operator) 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
x + 1 == 4
False
Eq(x + 1, 4)
solve(Eq(x+1, 4))
[3]
a = (x + 1)**2
b = x**2 + 2*x + 1 # these are algebraically equal
a == b
False
simplify(a - b) # this will test equality algebraically
a = cos(x) + sym.I*sin(x)
a
simplify(a)
More Substitution¶
Note that substitution returns a new expression: SymPy objects are immutable.
expr = cos(x)
expr.subs(x, 0)
expr
x
Multiple substitutions by passing a list of tuples.
expr = x**3 + 4*x*y - z
expr
expr.subs([(x, 2), (y, 4)])
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))
However, 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)
(1, [(z, 1), (x + 2*y, 2)])
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¶
Derivatives.
x = symbols('x')
diff(cos(x), x)
diff(exp(x**2), x, 2).subs(x, 5).evalf()
Third derivative:
diff(x**4, x, 3)
diff?
Signature: diff(f, *symbols, **kwargs) Docstring: Differentiate f with respect to symbols. Explanation =========== This is just a wrapper to unify .diff() and the Derivative class; its interface is similar to that of integrate(). You can use the same shortcuts for multiple variables as with Derivative. For example, diff(f(x), x, x, x) and diff(f(x), x, 3) both return the third derivative of f(x). You can pass evaluate=False to get an unevaluated Derivative class. Note that if there are 0 symbols (such as diff(f(x), x, 0), then the result will be the function (the zeroth derivative), even if evaluate=False. Examples ======== >>> from sympy import sin, cos, Function, diff >>> from sympy.abc import x, y >>> f = Function('f') >>> diff(sin(x), x) cos(x) >>> diff(f(x), x, x, x) Derivative(f(x), (x, 3)) >>> diff(f(x), x, 3) Derivative(f(x), (x, 3)) >>> diff(sin(x)*cos(y), x, 2, y, 2) sin(x)*cos(y) >>> type(diff(sin(x), x)) cos >>> type(diff(sin(x), x, evaluate=False)) <class 'sympy.core.function.Derivative'> >>> type(diff(sin(x), x, 0)) sin >>> type(diff(sin(x), x, 0, evaluate=False)) sin >>> diff(sin(x)) cos(x) >>> diff(sin(x*y)) Traceback (most recent call last): ... ValueError: specify differentiation variables to differentiate sin(x*y) Note that ``diff(sin(x))`` syntax is meant only for convenience in interactive sessions and should be avoided in library code. References ========== .. [1] http://reference.wolfram.com/legacy/v5_2/Built-inFunctions/AlgebraicComputation/Calculus/D.html See Also ======== Derivative idiff: computes the derivative implicitly File: c:\users\win10hx64\appdata\local\programs\python\python310\lib\site-packages\sympy\core\function.py Type: function
Differentiate different variables:
expr = exp(x*y*z)
diff(expr, y, x, z)
Unevaluated derivatied:
deriv = Derivative(expr, x, y, z)
deriv
deriv.doit()
Integrals:
integrate(cos(x), x)
Definite integral:
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
f = cos(x*2*pi)
f
integrate(f,(x,0,1))
sym.printing.python(a)
"x = Symbol('x')\ne = 1 + x + x**2/2 - x**4/8 - x**5/15 - x**6/240 + x**7/90 + 31*x**8/5760 + x**9/5670 + O(x**10)"
integrate(a, (x, -2, -1))
# 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) # expansion about x=0 up to 10th order
Note: For SymPy 0.7.5 and earlier, the order term O() is only supported for expansions about 0 or oo. So when you compute the series about a point other than 0 or oo, the result will be shifted to 0. You need to shift back by first removing the O() term.
print(a)
1 + x + x**2/2 - x**4/8 - x**5/15 - x**6/240 + x**7/90 + 31*x**8/5760 + x**9/5670 + O(x**10)
For SymPy 0.7.6, this is not an issue:
c = log(x).series(x, x0=1, n=6)
c
sym.printing.ccode(simplify(c.removeO()))
'(1.0/5.0)*pow(x, 5) - 5.0/4.0*pow(x, 4) + (10.0/3.0)*pow(x, 3) - 5*pow(x, 2) + 5*x - 137.0/60.0'
Solvers¶
If no Eq() is done, then it is assumed to be equal to 0.
solve(Eq(x**2, 1), x)
[-1, 1]
solve(x**2 - 1, x)
[-1, 1]
solve([x - y + 2, x + y - 3], [x, y])
{x: 1/2, y: 5/2}
Roots will report if a solution is multiple by listing it multiple times.
roots(x**3 - 6*x**2 + 9*x, x)
{3: 2, 0: 1}
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))
'Python' 카테고리의 다른 글
| 13. Linear Algebra (0) | 2024.03.14 |
|---|---|
| 12. matplotlib-basics (0) | 2024.03.14 |
| 10. NumPy tutorial (1) | 2024.03.14 |
| 9. Regular Expression (0) | 2024.03.14 |
| 8. Text File I/O (0) | 2024.03.14 |
