Symbolic computation deals with symbols, representing them exactly, instead of numerical approximations (floating point).
We will start with the following borrowed tutorial to introduce the concepts of SymPy. Devito uses SymPy heavily and builds upon it in its DSL.
In [2]:
import math
math.sqrt(3)
Out[2]:
In [3]:
math.sqrt(8)
Out[3]:
$\sqrt(8) = 2\sqrt(2)$, but it's hard to see that here
In [4]:
import sympy
sympy.sqrt(3)
Out[4]:
SymPy can even simplify symbolic computations
In [5]:
sympy.sqrt(8)
Out[5]:
In [6]:
from sympy import symbols
x, y = symbols('x y')
expr = x + 2*y
expr
Out[6]:
Note that simply adding two symbols creates an expression. Now let's play around with it.
In [7]:
expr + 1
Out[7]:
In [8]:
expr - x
Out[8]:
Note that expr - x was not x + 2y -x
In [9]:
x*expr
Out[9]:
In [10]:
from sympy import expand, factor
expanded_expr = expand(x*expr)
expanded_expr
Out[10]:
In [11]:
factor(expanded_expr)
Out[11]:
In [12]:
from sympy import diff, sin, exp
diff(sin(x)*exp(x), x)
Out[12]:
In [13]:
from sympy import limit
limit(sin(x)/x, x, 0)
Out[13]:
In [13]:
# Type solution here
from sympy import solve
In [14]:
from sympy import init_printing, Integral, sqrt
init_printing(use_latex='mathjax')
In [15]:
Integral(sqrt(1/x), x)
Out[15]:
In [16]:
from sympy import latex
latex(Integral(sqrt(1/x), x))
Out[16]:
More symbols. Exercise: fix the following piece of code
In [18]:
# NBVAL_SKIP
# The following piece of code is supposed to fail as it is
# The exercise is to fix the code
expr2 = x + 2*y +3*z
In [19]:
# Solution here
from sympy import solve
Difference between symbol name and python variable name
In [20]:
x, y = symbols("y z")
In [21]:
x
Out[21]:
In [22]:
y
Out[22]:
In [23]:
# NBVAL_SKIP
# The following code will error until the code in cell 16 above is
# fixed
z
Symbol names can be more than one character long
In [24]:
crazy = symbols('unrelated')
crazy + 1
Out[24]:
In [25]:
x = symbols("x")
expr = x + 1
x = 2
What happens when I print expr now? Does it print 3?
In [26]:
print(expr)
How do we get 3?
In [27]:
x = symbols("x")
expr = x + 1
expr.subs(x, 2)
Out[27]:
In [28]:
x + 1 == 4
Out[28]:
In [29]:
from sympy import Eq
Eq(x + 1, 4)
Out[29]:
Suppose we want to ask whether $(x + 1)^2 = x^2 + 2x + 1$
In [30]:
(x + 1)**2 == x**2 + 2*x + 1
Out[30]:
In [31]:
from sympy import simplify
a = (x + 1)**2
b = x**2 + 2*x + 1
simplify(a-b)
Out[31]:
In [32]:
z = symbols("z")
expr = x**3 + 4*x*y - z
expr.subs([(x, 2), (y, 4), (z, 0)])
Out[32]:
In [33]:
from sympy import sympify
str_expr = "x**2 + 3*x - 1/2"
expr = sympify(str_expr)
expr
Out[33]:
In [34]:
expr.subs(x, 2)
Out[34]:
In [35]:
expr = sqrt(8)
In [36]:
expr
Out[36]:
In [37]:
expr.evalf()
Out[37]:
In [38]:
from sympy import pi
pi.evalf(100)
Out[38]:
In [39]:
from sympy import cos
expr = cos(2*x)
expr.evalf(subs={x: 2.4})
Out[39]:
In [41]:
from IPython.core.display import Image
Image(filename='figures/comic.png')
Out[41]:
Write a function that takes a symbolic expression (like pi), and determines the first place where 789 appears. Tip: Use the string representation of the number. Python starts counting at 0, but the decimal point offsets this
In [42]:
from sympy import Function
f, g = symbols('f g', cls=Function)
f(x)
Out[42]:
In [43]:
f(x).diff()
Out[43]:
In [44]:
diffeq = Eq(f(x).diff(x, x) - 2*f(x).diff(x) + f(x), sin(x))
diffeq
Out[44]:
In [45]:
from sympy import dsolve
dsolve(diffeq, f(x))
Out[45]:
In [48]:
f = Function('f')
dfdx = f(x).diff(x)
dfdx.as_finite_difference()
Out[48]:
In [49]:
from sympy import Symbol
d2fdx2 = f(x).diff(x, 2)
h = Symbol('h')
d2fdx2.as_finite_difference(h)
Out[49]:
Now that we have seen some relevant features of vanilla SymPy, let's move on to Devito, which could be seen as SymPy finite differences on steroids!