This is to present a short introduction to symbolic mathematics in Python using SymPy
Following the flow of : http://www.cfm.brown.edu/people/dobrush/am33/SymPy/index.html
In [10]:
import sympy as sym
init_printing() # to get nice \LaTeX output
In [11]:
x = sym.Symbol('x')
In [12]:
x+1
Out[12]:
For multiple symbols one can do
In [13]:
y, z = sym.symbols('y z')
y+z+1
Out[13]:
In [14]:
x='abc'
In [16]:
expr = x + 'def' ; expr
Out[16]:
In [17]:
x = sym.symbols('x')
expr = x+1
expr
Out[17]:
In [20]:
expr.subs(x,1) # should be 2
Out[20]:
In [21]:
expr.subs(x,z)
Out[21]:
The importance of substition is the following
In [22]:
expr = cos(x)+1
In [23]:
expr.subs(x,0)
Out[23]:
In [24]:
expr.subs(x, x+y)
Out[24]:
In [27]:
expr.subs(x, x**y)
Out[27]:
N.B.
subs()
returns a new expression, i.e. the expr
is not changed!
subs
is immutable! To perform multiple substitution we use a list of tuples:
In [28]:
expr = cos(x)+2*sin(y)+z
In [31]:
expr.subs([(x,1),(y,3), (z,0)])
Out[31]:
This is very usefull because we can use list comprehension for the substitutions!
In [33]:
expr = x**4 - 4*x**3 + 4*x**2 - 2*x + 3
expr
Out[33]:
In [36]:
replacements = [(x**i, y**i) for i in range(5) if i%2==0] #replace all instances of x that
# have even powers with y
In [37]:
expr.subs(replacements)
Out[37]:
In [40]:
str_expr = "x**2+3*x+2"
In [42]:
expr = sym.sympify(str_expr)
In [44]:
expr
Out[44]:
In [45]:
expr.subs(x,2)
Out[45]:
Use evalf()
to evaluate a numerical expression into a floating point number:
In [46]:
expr= sqrt(8)
In [47]:
expr
Out[47]:
In [51]:
expr.evalf()
Out[51]:
In [53]:
expr.evalf(50) #first 50 digits
Out[53]:
To evaluate an expression with a symbol to a point we can use the subs
flag in evalf()
using a dictionary : Symbol: point
In [55]:
expr = cos(2*x)
expr
Out[55]:
In [56]:
expr.evalf(subs={x:0.2})
Out[56]:
In [58]:
cos(2*0.2) #it works
Out[58]:
There are roundoff errors smaller than the desired precision. Such numbers can be cut using the chop
flag in eval()
:
In [59]:
one = cos(1)**2 + sin(1)**2
In [60]:
(one-1).evalf()
Out[60]:
In [61]:
(one-1).evalf(chop=True)
Out[61]:
lambdify()
is used to convert a SymPy expression to another library (usually NumPy). lambdify()
acts as a lambda function but also converting the SymPy expressions to a another numerical library.
For example if we want to use the subs
flag of the evalf()
function to evaluate the function at 1000 points, then we can use numpy and lambdify...
In [62]:
import numpy as np
In [68]:
a = np.arange(100)
In [69]:
expr = sin(x)
In [74]:
f = lambdify(x, expr, "numpy") # takes an argument x=x0 and returns the expr(x0)
In [75]:
f(a)
Out[75]:
In [77]:
simplify(cos(x)**2 + sin(x)**2)
Out[77]:
In [79]:
expr = (x**3 + x**2 - x - 1)/(x**2 + 2*x + 1);
expr
Out[79]:
In [80]:
simplify(expr)
Out[80]:
In [83]:
expr = gamma(x)/gamma(x-2); expr ## gamma(x) := Gamma functions
Out[83]:
In [84]:
simplify (expr)
Out[84]:
factor
is used on polynomials with rational coefficients and factors it inot irreducible factors over the rational numbers
In [88]:
expr = x**3 - x**2 + x- 1;
expr
Out[88]:
In [89]:
factor(expr)
Out[89]:
In [90]:
expr = x**2*z + 4*x*y*z + 4*y**2*z; expr
Out[90]:
In [91]:
factor (expr)
Out[91]:
In [93]:
factor_list(expr)
Out[93]:
expand()
is used to make an expression bigger. The opposite of factor()
.
In [96]:
expr = (x+1)**2;
expr
Out[96]:
In [97]:
expand(expr)
Out[97]:
In [ ]:
collect()
is used to collect common powers of a term
In [98]:
expr = x*y +x-3+2*x**2 - z*x**2 + x**3; expr
Out[98]:
In [99]:
cl = collect(expr, x)
In [100]:
cl
Out[100]:
Very usefull when combined with the coeff()
function that fives the coefficients of a symbol in the expression:
In [101]:
expr
Out[101]:
In [102]:
expr.coeff(x,2)
Out[102]:
In [103]:
expr.coeff(y, 1)
Out[103]:
In [105]:
cl.coeff(x,3)
Out[105]:
In [106]:
cl.coeff(x,2)
Out[106]:
cancel()
is used to take any rational function and put it into standard canonical form.
In [107]:
cancel((x**2+2*x+1)/(x**2+x))
Out[107]:
In [108]:
expr = 1/x + (3*x/2 - 2)/(x - 4)
In [109]:
expr
Out[109]:
In [110]:
cancel(expr)
Out[110]:
apart()
simply performs a partial fraction decomposition on a rational function.
In [112]:
expr = (4*x**3 + 21*x**2 + 10*x + 12)/(x**4 + 5*x**3 + 5*x**2 + 4*x); expr
Out[112]:
In [113]:
apart(expr)
Out[113]:
N.B. Remember that the Python's convention for inverse trig equations is acos()
, asin()
etc..
In [114]:
acos(x)
Out[114]:
In [115]:
cos(acos(x))
Out[115]:
trigsimp()
is used to simplify expressions based on trigonometric identities.
In [116]:
expr = sin(x)**4 - 2*cos(x)**2*sin(x)**2 + cos(x)**4; expr
Out[116]:
In [117]:
trigsimp(expr)
Out[117]:
In [119]:
expr = sin(x)*tan(x)/sec(x); expr
Out[119]:
In [120]:
trigsimp(expr)
Out[120]:
In [121]:
expr = cosh(x)**2 + sinh(x)**2 ; expr
Out[121]:
In [122]:
trigsimp(expr)
Out[122]:
expand_trig() is used to expand trigonometric functions (apply the sum or double angle identities)
In [123]:
expr = sin(x+y); expr
Out[123]:
In [124]:
expand_trig(expr)
Out[124]:
In [127]:
expr = tan(2*x); expr
Out[127]:
In [128]:
expand_trig(expr)
Out[128]:
There are identities for powers that hold under constraints. For example:
$x^a x^b = x^{a+b}$ -> holds always
x^a y^a = (xy)^a -> holds when $x,y>0$ and $a\in R$
(x^a)^b = x^{ab} -> holds when b is integer
For this reason when defining symbols we can put specific requirements as their arguments. For example we define for this section:
In [129]:
x, y = symbols('x y', positive=True)
In [130]:
a,b = symbols('a b', real=True)
In [131]:
z, t, c = symbols('z t c ')
powsimp()
is used to simplify an expression with powers (using identities 1,2)
In [133]:
expr = (x**a)*(x**b); expr
Out[133]:
In [134]:
powsimp(expr)
Out[134]:
To force a simplification without messing with the assumptions, while
In [136]:
powsimp(t**c*z**c)
Out[136]:
forcing it with an argument
In [137]:
powsimp(t**c*z**c, force=True)
Out[137]:
expand_power_exp()
and expand_power_base()
applies the identities 1,2 from right to left, expanding the exponent or the base of an expression
In [138]:
expr = x**(a+b); expr
Out[138]:
In [139]:
expand_power_exp(expr)
Out[139]:
In [140]:
expr = (x*y)**a; expr
Out[140]:
In [141]:
expand_power_base(expr)
Out[141]:
This is to apply identity 3 on nested powers
In [144]:
expr = (x**a)**b; expr # automatically is simplified
Out[144]:
In [143]:
powdenest(expr)
Out[143]: