文章摘要:微分方程的Python实现。
参考书籍:数学建模算法与应用(第3版)司守奎 孙玺菁。
PS1:只涉及了具体实现并不涉及底层理论。没有给出底层理论参考书籍的原因是不想做这个方向吧。所以对我只要掌握基本模型有个概念那就好了。
PS2:这里跳过两个章节直接来到微分方程那是因为:第四章节我想划归到算法学习里,因为图领域感觉挺大的并且我挺有兴趣的想好好学习下。第五章节归属数值分析范畴,我已经从底层理论完成这部分的内容,可以参考这篇文章。
文章声明:如有发现错误,还望批评指正。
文章目录
- 微分方程的符号解
- 参考书籍例6.6
- 参考书籍例6.7
- 参考书籍例6.8
- 微分方程的数值解
- 病毒传播模型
- 指数传播模型
- SI模型
- SIS模型
- SIR模型
- Logistic模型
由于微分方程不在博主兴趣范畴之内,我们针对几个常见模型进行Python的实现。
微分方程的符号解
符号解就是解析解,该解十分精确。有些方程没符号解。我们这里只讨论有符号解的微分方程。
参考书籍例6.6
求解如右柯西问题 { d x d t = A x x ( 0 ) = [ 1 , 1 , 1 ] T 解,其中 x ( t ) = [ x 1 ( t ) , x 2 ( t ) , x 3 ( t ) ] T , A = [ 3 − 1 1 2 0 − 1 1 − 1 2 ] . 求解如右柯西问题\left\{\begin{matrix}\frac{d\mathbf{x}}{dt}=\mathbf{Ax}\\\mathbf{x}(0)=[1,1,1]^T\end{matrix}\right.解,其中\mathbf{x}(t)=[x_1(t),x_2(t),x_3(t)]^T,A=\begin{bmatrix}3&-1&1\\2&0&-1\\1&-1&2\end{bmatrix}. 求解如右柯西问题{dtdx=Axx(0)=[1,1,1]T解,其中x(t)=[x1(t),x2(t),x3(t)]T,A= 321−10−11−12 .
import sympy as sp
sp.var('t')
sp.var('x1:4',cls=sp.Function)
x=sp.Matrix([x1(t),x2(t),x3(t)])
A=sp.Matrix([[3,-1,1],[2,0,-1],[1,-1,2]])
eq=x.diff(t)-A@x
print(sp.dsolve(eq,ics={x1(0):1,x2(0):1,x3(0):1}))
PS1:代码在编译器内会显示异常,这是因为没有找到变量声明。但是能够顺利运行,因为代码底层已经声明变量。
PS2:虽然正确但是强迫症很难受。所以下面不会采用这种方法。
参考书籍例6.7
[ x 1 ′ ( t ) x 2 ′ ( t ) x 3 ′ ( t ) ] = [ 1 0 0 2 1 − 2 3 2 1 ] [ x 1 ( t ) x 2 ( t ) x 3 ( t ) ] + [ 0 0 e t c o s ( 2 t ) ] , [ x 1 ( 0 ) x 2 ( 0 ) x 3 ( 0 ) ] = [ 0 1 1 ] 。 \begin{bmatrix}x_1'(t)\\x_2'(t)\\x_3'(t)\end{bmatrix}=\begin{bmatrix}1&0&0\\2&1&-2\\3&2&1\end{bmatrix}\begin{bmatrix}x_1(t)\\x_2(t)\\x_3(t)\end{bmatrix}+\begin{bmatrix}0\\0\\e^tcos(2t)\end{bmatrix},\begin{bmatrix}x_1(0)\\x_2(0)\\x_3(0)\end{bmatrix}=\begin{bmatrix}0\\1\\1\end{bmatrix}。 x1′(t)x2′(t)x3′(t) = 1230120−21 x1(t)x2(t)x3(t) + 00etcos(2t) , x1(0)x2(0)x3(0) = 011 。
import sympy as sp
t=sp.var('t')
x1=sp.Function('x1')(t);x2=sp.Function('x2')(t);x3=sp.Function('x3')(t)
con1=sp.Eq(x1.diff(t),x1);con2=sp.Eq(x2.diff(t),2*x1+x2-2*x3);con3=sp.Eq(x3.diff(t),3*x1+2*x2+x3+sp.exp(t)*sp.cos(2*t))
con_initial={x1.subs(t,0):0,x2.subs(t,0):0,x3.subs(t,0):0}
print(sp.dsolve((con1,con2,con3),[x1,x2,x3],ics=con_initial))
参考书籍例6.8
求常微分方程组 { f ′ ′ + 3 g ′ + f ′ = 1 ,边值条件 f ′ ( 1 ) = 0 , f ( 0 ) = 0 , g ( 0 ) = 0 时的解 求常微分方程组\left\{\begin{matrix}f''+3\\g'+f'=1\end{matrix}\right.,边值条件f'(1)=0,f(0)=0,g(0)=0时的解 求常微分方程组{f′′+3g′+f′=1,边值条件f′(1)=0,f(0)=0,g(0)=0时的解
import sympy as sp
x=sp.var('x')
f=sp.Function('f')(x);g=sp.Function('g')(x)
con1=sp.Eq(f.diff(x,2)+g,3);con2=sp.Eq(f.diff(x)+g.diff(x),1)
con_initial={f.diff(x).subs(x,0):0,f.subs(x,0):0,g.subs(x,0):0}
print(sp.dsolve((con1,con2),[f,g],ics=con_initial))
微分方程的数值解
没有什么兴趣,所以不想去做。但是最近正在手搓数值分析。或许可以放到那里。
病毒传播模型
指数传播模型
基本假设:
1)问题研究区域封闭,一个时期人口总量基本不变。2)
t
t
t时刻染病人数
N
(
t
)
N(t)
N(t)连续变化并且可微。3)每个病人单位时间,有效使人致病人数为
λ
\lambda
λ 4)模型期间不会死亡
数学模型:
{
d
N
(
t
)
d
t
=
λ
N
(
t
)
,
t
>
0
N
(
0
)
=
N
0
\left\{\begin{matrix}\frac{dN(t)}{dt}=\lambda N(t),t>0\\N(0)=N_0\end{matrix}\right.
{dtdN(t)=λN(t),t>0N(0)=N0
模型解得:
N
(
t
)
=
N
0
e
λ
t
N(t)=N_0e^{\lambda t}
N(t)=N0eλt
import matplotlib.pyplot as plt
import math
N0=100;T=30;la=5
lt=[N0*pow(math.e,la*i) for i in range(1,T+1)]
plt.figure(figsize=(16,9));plt.grid();plt.rcParams['font.sans-serif']=['SimHei']
plt.plot([i for i in range(1,T+1)],lt,ms=10,marker="o",linewidth=5,color="black")
plt.xlabel("时间",size=15);plt.ylabel("人数",size=15);plt.show()
模型补充:
这样算的是第T天感染人数,不是总的感染人数,所以应该把前面的全加起来(小声:感觉书上错了)
结果分析:
显然指数增长那是不正确的。
SI模型
基本假设:
1)问题研究区域封闭,一个时期人口总量基本不变,总人口
N
N
N。2)人群分为两种健康人群患病人群,设置两种人群占全人群分别为
s
(
t
)
s(t)
s(t)和
i
(
t
)
i(t)
i(t),易
s
(
t
)
+
i
(
t
)
=
1
s(t)+i(t)=1
s(t)+i(t)=1 3)日感染率为
λ
\lambda
λ
数学模型:
{
d
i
(
t
)
d
t
=
λ
i
(
t
)
(
1
−
i
(
t
)
)
,
t
>
0
i
(
0
)
=
i
0
\left\{\begin{matrix}\frac{di(t)}{dt}=\lambda i(t)(1-i(t)),t>0\\i(0)=i_0\end{matrix}\right.
{dtdi(t)=λi(t)(1−i(t)),t>0i(0)=i0
模型解得:
i
(
t
)
=
1
1
+
(
1
i
0
−
1
)
e
−
λ
t
i(t)=\frac{1}{1+(\frac{1}{i_0}-1)e^{-\lambda t}}
i(t)=1+(i01−1)e−λt1
import matplotlib.pyplot as plt
import math
i0=0.1;la=0.01;T=365*3+366
lt=[1/(1+(1/i0-1)*pow(math.e,-la*i)) for i in range(1,T+1)]
plt.figure(figsize=(16,9));plt.grid();plt.rcParams['font.sans-serif']=['SimHei']
plt.plot([i for i in range(1,T+1)],lt,marker="o",linewidth=5,color="black")
plt.xlabel("时间",size=15);plt.ylabel("比例",size=15);plt.show()
SIS模型
模型假设:
1)同SI模型2)每天治愈人数占总人数比例为u
数学模型:
{
d
i
(
t
)
d
t
=
λ
i
(
t
)
(
1
−
i
(
t
)
)
−
u
i
(
t
)
,
t
>
0
i
(
0
)
=
i
0
\left\{\begin{matrix}\frac{di(t)}{dt}=\lambda i(t)(1-i(t))-ui(t),t>0\\i(0)=i_0\end{matrix}\right.
{dtdi(t)=λi(t)(1−i(t))−ui(t),t>0i(0)=i0
模型解得:
i
(
t
)
=
{
[
λ
λ
−
u
+
(
1
i
0
−
λ
λ
−
u
)
e
−
(
λ
−
u
)
t
]
−
1
,
λ
≠
u
i
(
0
)
=
i
0
,
λ
=
u
i(t)=\left\{\begin{matrix}[\frac{\lambda}{\lambda-u}+(\frac{1}{i_0}-\frac{\lambda}{\lambda-u})e^{-(\lambda-u)t}]^{-1},\lambda \neq u\\i(0)=i_0,\lambda=u\end{matrix}\right.
i(t)={[λ−uλ+(i01−λ−uλ)e−(λ−u)t]−1,λ=ui(0)=i0,λ=u
import matplotlib.pyplot as plt
import math
def func(i):
global la,u,i0
if la==u:
return pow(la*i+1/i0,-1)
return pow(la/(la-u)+(1/i0-la/(la-u))*pow(math.e,-(la-u)*i),-1)
la=0.05;u=0.05;i0=0.5;T=365*3+366
lt=[func(i) for i in range(1,T+1)]
plt.figure(figsize=(16,9));plt.grid();plt.rcParams['font.sans-serif']=['SimHei']
plt.plot([i for i in range(1,T+1)],lt,marker="o",linewidth=5,color="black")
plt.xlabel("时间",size=15);plt.ylabel("比例",size=15);plt.show()
结果分析:
我这里是
λ
\lambda
λ等于
u
u
u。可自己调。当
λ
≤
u
\lambda\leq u
λ≤u所有人最后都会被治愈。当
λ
>
u
\lambda>u
λ>u最后总有一小部分的人保持健康。
SIR模型
基本假设:
1)人群分为3类A:健康人士(没有患过)B:患病人士C:健康人士(曾经患过)分别记:
s
(
t
)
,
i
(
t
)
,
r
(
t
)
s(t),i(t),r(t)
s(t),i(t),r(t) 2)日感染率,日治愈率记:
λ
,
u
\lambda,u
λ,u 3)总人口
N
N
N。
数学模型:
i
(
t
)
=
{
d
i
(
t
)
d
t
=
λ
s
(
t
)
i
(
t
)
−
u
i
(
t
)
d
s
(
t
)
d
t
=
−
λ
s
(
t
)
i
(
t
)
d
r
(
t
)
d
t
=
u
i
(
t
)
i
(
0
)
=
i
0
,
s
(
0
)
=
s
0
,
r
(
0
)
−
0
i(t)=\left\{\begin{matrix}\frac{di(t)}{dt}=\lambda s(t)i(t)-ui(t)\\\frac{ds(t)}{dt}=-\lambda s(t)i(t)\\\frac{dr(t)}{dt}=ui(t)\\i(0)=i_0,s(0)=s_0,r(0)-0\end{matrix}\right.
i(t)=⎩
⎨
⎧dtdi(t)=λs(t)i(t)−ui(t)dtds(t)=−λs(t)i(t)dtdr(t)=ui(t)i(0)=i0,s(0)=s0,r(0)−0
模型求解:
这是一个常微分方程组,难以求解析解。可以用Python求数值解。
def sir_model(t,y,la,u):
S,I,R=y[0],y[1],y[2]
dSdt=-la*S*I;dIdt=la*S*I-u*I;dRdt=u*I
return [dSdt,dIdt,dRdt]
S0=0.99;I0=0.01;R0=0.0;la=0.2;u=0.1;t_start=0;t_end=365*3+366;y0=(S0,I0,R0);t_span=[i for i in range(t_end+1)]
from scipy.integrate import solve_ivp
solution=solve_ivp(sir_model,[t_start,t_end],y0,args=(la,u),t_eval=t_span)
S=solution.y[0];I=solution.y[1];R=solution.y[2]
import matplotlib.pyplot as plt
plt.figure(figsize=(16,9));plt.grid();plt.rcParams['font.sans-serif']=['SimHei']
plt.plot(solution.t,S,label='A类人士')
plt.plot(solution.t,I,label='B类人士')
plt.plot(solution.t,R,label='C类人士')
plt.xlabel('时间');plt.ylabel('比例');plt.legend();plt.show()
Logistic模型
模型假设:
1)设
r
(
x
)
r(x)
r(x)为
x
x
x线性函数,所以
r
(
x
)
=
r
−
s
x
r(x)=r-sx
r(x)=r−sx。2)地球容纳最大人数为
x
m
x_m
xm。
PS:这里我们可以化
r
(
x
)
r(x)
r(x)为
r
(
1
−
x
x
m
)
r(1-\frac{x}{x_m})
r(1−xmx).仔细想想,不难理解
模型建立:
{
d
x
d
t
=
r
(
1
−
x
x
m
)
x
,
x
(
t
0
)
=
x
0
.
\left\{\begin{matrix}\frac{dx}{dt}=r(1-\frac{x}{x_m})x,\\x(t_0)=x_0.\end{matrix}\right.
{dtdx=r(1−xmx)x,x(t0)=x0.
PS:这里是一个可以用分离变量方法解的方程,应该不难。
模型解得:
x
(
t
)
=
x
m
1
+
(
x
m
x
0
−
1
)
e
−
r
(
t
−
t
0
)
x(t)=\frac{x_m}{1+(\frac{x_m}{x_0}-1)e^{-r(t-t_0)}}
x(t)=1+(x0xm−1)e−r(t−t0)xm
这个有解析解就不写代码了。