Engineering systems are often represented as differential equations. sympy
has robust support for the following types of ordinary differential equations (ODEs):
In addition to ODE support, sympy can even solve separable (either multiplicative or additive) partial differential equations (PDEs).
The main functionality for ODE solving in sympy is the sympy.dsolve
function. The call signature for this function is sympy.dsolve(eq, goal, **kwargs)
, where eq
is the differential equation, goal
is the function you want to end up with, and **kwargs
is a placeholder for other arguments that could be passed to the function to help it out a bit. For more detail on what **kwargs
could be, see the documentation.
In [1]:
from sympy import *
In [2]:
init_session()
plt.style.use(u"seaborn-notebook")
To solve differential equations, use dsolve. First, create an undefined function by passing cls=Function to the symbols function.
In [3]:
f, g = symbols('f g', cls=Function)
Derivatives of f(x) are unevaluated.
In [4]:
f(x).diff(x)
Out[4]:
To represent the differential equation $f′′(x)−2f′(x)+f(x)=sin(x)$, we would use
In [5]:
ode = Eq(f(x).diff(x, x) - 2*f(x).diff(x) + f(x), sin(x))
In [6]:
ode
Out[6]:
To solve the ODE, pass it and the function to solve for to dsolve
.
In [7]:
sol = dsolve(ode, f(x))
display(sol)
dsolve
returns an instance of Eq
. This is because in general, solutions to differential equations cannot be solved explicitly for the function.
In [8]:
dsolve(f(x).diff(x)*(1 - sin(f(x))), f(x))
Out[8]:
The arbitrary constants in the solutions from dsolve
are symbols of the form $C_1, C_2, C_3$, and so on.
In [9]:
constants = solve([sol.rhs.subs(x,0) - 1, sol.rhs.diff(x,1).subs(x,0)- 0])
constants
Out[9]:
In [10]:
C1, C2 = symbols('C1,C2')
sol = sol.subs(constants)
sol
Out[10]:
In [11]:
g1, g2 = symbols('g1 g2', cls=Function)
In [12]:
eq1 = g1(x).diff(x) - 2*g1(x) - g2(x)
eq2 = g2(x).diff(x) - 3*g1(x) - 4*g2(x)
In [13]:
dsolve((eq1, eq2), fun=(g1(x), g2(x)))
Out[13]:
In [ ]:
In [14]:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
The '''Lotka–Volterra equations''', also known as the '''predator–prey equations''', are a pair of first-order, nonlinear, differential equations frequently used to describe the dynamics of biological systems in which two species interact, one as a predator and the other as prey. The populations change through time according to the pair of equations:
\begin{align} \frac{dx}{dt} & = \alpha x - \beta x y \\[6pt] \frac{dy}{dt} & = \delta x y - \gamma y \end{align}where
In [15]:
y, x = np.mgrid[0:2.5:100j, 0:4:100j]
In [16]:
alpha = 2/3
beta = 4/3
gamma = 1
delta = 1
dxdt = alpha*x - beta*x*y
dydt = delta*x*y - gamma*y
speed = np.sqrt(dxdt**2 + dydt**2)
In the first case we just plot the velocity field.
In [17]:
fig0 = plt.figure(figsize=(8,5))
strm = plt.streamplot(x, y, dxdt, dydt, linewidth=2)
plt.xlabel("Preys")
plt.ylabel("Predators")
plt.xlim(0,4)
plt.ylim(0,2.5)
Out[17]:
In this example we change the color of the line according to the magnitude of the speed at each point.
In [18]:
fig1 = plt.figure(figsize=(8,5))
strm = plt.streamplot(x, y, dxdt, dydt, color=speed, linewidth=2, cmap="summer")
plt.colorbar(strm.lines)
plt.xlabel("Preys")
plt.ylabel("Predators")
plt.xlim(0,4)
plt.ylim(0,2.5)
Out[18]:
In this case the densities in $x$ and $y$ directions are different.
In [19]:
fig2 = plt.figure(figsize=(8,5))
plt.streamplot(x, y, dxdt, dydt, density=[0.5, 1])
plt.xlabel("Preys")
plt.ylabel("Predators")
plt.xlim(0,4)
plt.ylim(0,2.5)
Out[19]:
In this last case we vary the width of the lines according to the magnitude of the speed at each point.
In [20]:
fig3 = plt.figure(figsize=(8,5))
lw = 5*speed / speed.max()
plt.streamplot(x, y, dxdt, dydt, density=0.6, color='k', linewidth=lw)
plt.xlabel("Preys")
plt.ylabel("Predators")
plt.xlim(0,4)
plt.ylim(0,2.5)
Out[20]:
In [21]:
def picard_iteration(f, t, y0, n):
y = y0
for cont in range(n):
y = y0 + f(t, y, n).integrate((t, 0, t))
return y
In [22]:
def fun(t, y, n):
return Matrix([y[1], t*y[0]])
In [23]:
x0, x1 = symbols("x0 x1")
y = Matrix([airyai(0), airyaiprime(0)])
y_approx = picard_iteration(fun, t, y, 10)
In [24]:
p0 = plot(airyai(t), (t, -4, 4), line_color="black");
p1 = plot(N(y_approx[0]), (t, -4, 4));
p0.extend(p1);
p0.show()
The following cell change the style of the notebook.
In [26]:
from IPython.core.display import HTML
def css_styling():
styles = open('./styles/custom_barba.css', 'r').read()
return HTML(styles)
css_styling()
Out[26]:
In [ ]: