Topic 6d: Symbolic Computing
Contents
Topic 6d: Symbolic Computing#
import sympy
sympy.init_printing()
import numpy as np
The emphasis in this course has been the use of computers for manipulting data or using numerical techniques to solve problems. These are central problems in scientific computing and are good windows into how computers work.
Of course, computers can be designed to do much more complex tasks and we should use computers when they are available to simplify/speed up/check our work. Symbolic computing is an excellent example of a computer resource that can assist in solving problems that we might usually associate with a human and a piece of paper. Fundamentally, the computer can do a lot of our math for us, so we should use it to check our results at the very least.
Sympy is a python library that can do a lot of math for us, in this way. It is similar to mathematica in both function and design, but is freely available. One of the most basic sources of confusion is that these symbolic tools try to avoid making any assumptions:
x=sympy.Symbol('x')
sympy.sqrt(x**2)
Sympy does not know how to simplify this expression. What if \(x\) is a complex number? We will get different answers depending on our assumptions:
y=sympy.Symbol('y',real=True)
sympy.sqrt(y**2)
y=sympy.Symbol('y',positive=True)
sympy.sqrt(y**2)
n1=sympy.Symbol('n1',integer=True)
n2=sympy.Symbol('n2',odd=True)
sympy.cos(sympy.pi*n1)
sympy.cos(sympy.pi*n2)
Manipulating Expressions#
We can define experessions you might want to work with
exp=x**2+x*(x*2+x*2)+x*(x+1)+3
exp
We can simplify these expressions two ways:
sympy.simplify(exp)
exp.simplify()
Similarly we can factor expressions
exp2=x**2+2*x+1
exp2
sympy.factor(exp2)
exp2.factor()
or expand
((x+2)**5).expand()
sympy.sin(x+y).expand(trig=True)
Evaluating Expressions#
In a lot of situations, we need to combine our symbolic work with something numerical. Sometimes, this means we just want to force the computer to return a demical instead of a symbolic expression for the number:
sympy.N(sympy.pi)
sympy.N(sympy.pi,50) # tell it you want 50 decimal places
sympy.cos(1)
sympy.N(sympy.cos(1))
In other situations, we have found a function that we want to be able to evaluate numerically:
exp
We can just substitute \(x\) with a number (or another variable) if we like
exp.subs(x,10)
But we can also define an actual function we can use as normal with lambdify
exp_fnc=sympy.lambdify(x,exp)
exp_fnc(10)
x_array=np.linspace(1,10,10)
exp_fnc(x_array)
array([ 10., 29., 60., 103., 158., 225., 304., 395., 498., 613.])
exp3=sympy.sin(x**2)
exp_fnc3=sympy.lambdify(x,exp3)
exp_fnc3(x_array)
array([ 0.84147098, -0.7568025 , 0.41211849, -0.28790332, -0.13235175,
-0.99177885, -0.95375265, 0.92002604, -0.62988799, -0.50636564])
Solving Equations#
Not suprisingly, sympy is pretty good at solving equations.
sympy.solve(x**2-1)
sympy.solve(sympy.sin(x))
sympy.solve([x+y+1,x+2*y],[x,y])
Calculus#
Calculus is one of the symbolic tools that tends to be very powerful and reliable. In some cases it would be enormously difficult to do it yourself yet the computer seems to find a nice answer quickly.
Derivatives#
exp4=sympy.sin(x*sympy.cos(x**2 +x+2))
exp4
sympy.diff(exp4)
exp4.diff(x)
exp4.diff(x,x).simplify()
exp5=x**2*y+y**3*x+x+3*y
exp5.diff(y)
exp5.diff(x)
exp5.diff(x,y)
Series#
An extremely useful tool when trying to understand functions is the Taylor series around a given point
exp4.series(x,0,3) # this means: series wrt x, at x=0 to order x^3.
This becomes much more useful when you start dealing with functions you don’t konw a lot about
sympy.besselj(2,x).series(x,0,3)
Importantly, series is not really a Taylor series. In includes inverse powers as well:
sympy.gamma(x).series(x,0,3)
To see why this is useful consider
(sympy.gamma(x)*sympy.sin(x)).subs(x,0)
(sympy.gamma(x)*sympy.sin(x)).series(x,0,2)
The function \(\Gamma[x]\sin(x)\) is perfectly well behaved at \(x=0\) but you need to look at the series as \(x\to 0\) to see that. There is also a limit option but in my experience series is always better than limit.
Integration#
Integration is where it is really obvious how much better a computer is than a person. Even just a minor change to an integral can make it faily challenging
sympy.integrate(sympy.sin(x),x)
sympy.integrate(sympy.sin(x**2),x)
sympy.integrate(x**2*sympy.exp(-x),(x,0,1))
The notation for \(\infty\) is a bit unusual
sympy.integrate(sympy.exp(-x**2),(x,0,sympy.oo))
We can also perform a integration that produces a function of some other variable:
a=sympy.Symbol('a')
sympy.integrate(sympy.exp(-a*x**2),(x,0,sympy.oo))
Notice again that it didn’t know what to do with our variable \(a\) (it could be real, imaginary, complex, negative, postive. Fortunately, we can tell it what to assume to avoid this problem (sometimes it can’t figure it out on its own):
c=sympy.Symbol('c',positive=True)
sympy.integrate(sympy.exp(-c*x**2),(x,0,sympy.oo))
Summary#
Symbolic computation is extremely powerful and useful. The functionality is really quite endless. However, one often does not appreciate all that it can do until you really need it. At the very least, it will keep you from making stupid mistakes on your homework.