MATLABによる遅延微分方程式の数値計算
高安亮紀(筑波大学システム情報系)
今日の前半部分は、
- Robert M. Corless , Nicolas Fillion, A Graduate Introduction to Numerical Methods, Springer New York, NY, 2016.
の15章Numerical Solution of Delay DEsを元に作った資料です。
1. 定数の遅延をもつ遅延微分方程式
遅延微分方程式は、特に数理生物学などの応用分野で非常に頻繁に登場する。遅延微分方程式(DDE)の数値解法は常微分方程式(ODE)の初期値問題の数値解法とよく似ているが、いくつかの重要な違いもある。簡単な例で説明する。
この式は
で成り立つので、もしも
を知るためには
の値を知る必要があり、
で
を知るためには
の値が必要になる。 すなわち
で
をみたす履歴関数
を与える必要がある。 この履歴関数は初期条件というが、(ODEでいう)初期値以上のものである。つまり区間上で定義される一般的な関数であるため、DDEの解は無限次元であり、ODEの初期値問題よりもかなり複雑である。
MATLABを用いるとdde23やddesdという関数を呼び出すだけで、数値計算ができる。まず、
(
)とし、次のように呼び出す。 dde = @(t,y,Z) -0.2*Z(:,1);
lambda = -0.259171101819074;
ddehist = @(t) exp(lambda*t);
opts = ddeset('AbsTol', 1.0e-8) ;
sol = dde23( dde, delay, ddehist, tspan, opts )
sol =
solver: 'dde23'
history: @(t)exp(lambda*t)
discont: [0 1 2 3]
x: [0 0.3087 0.6543 1 1.4000 1.7000 2 2.4000 2.7000 3 3.4000 3.7000 4]
y: [1 0.9231 0.8440 0.7717 0.6957 0.6437 0.5955 0.5369 0.4967 0.4595 0.4143 0.3833 0.3546]
stats: [1×1 struct]
yp: [-0.2592 -0.2392 -0.2187 -0.2000 -0.1803 -0.1668 -0.1543 -0.1391 -0.1287 -0.1191 -0.1074 -0.0993 -0.0919]
このコードは許容誤差
で問題を数値的に解く。変数 y は
の近似値を指し、Z は
の近似値を指す。構文Z(:,1)はZの最初の列を選んでいるが、この問題ではZは実際1列しかない。そしてdeval(IVPやBVPの解を評価する関数)によって評価点で上の関数値を得ることができる。 plot(sol.x, sol.y, LineWidth=1.6)
plot(sol.x, sol.yp, '--', LineWidth=1.4)
xlabel('$t$','interpreter','latex')
ylabel('$y$ and $y''$','interpreter', 'latex')
解の精度はどの程度なのか?ここでは残差を計算し、プロットしてみる。
for t = linspace(0,4,divN)
res = [res; dy - dde(t,y,z)];
plot(linspace(0,4,divN),res,LineWidth=1.4)
xlabel('$t$','interpreter','latex')
上の履歴関数
は、パラメータλを巧みに選び、
が実際にはDDEの厳密解となるようにした。特に、初期点
における履歴関数と解の間が非常に滑らかである(丸め誤差がなければ、解析的である)。これは非常に珍しい例で、通常はそうはならない。なぜなら、一般にはDDEの解の右微分
と、履歴関数の左微分
が一致しない。実際、
は存在しないかもしれないし、 履歴関数が不連続かもしれない。この初期不連続性は、高次数値計算手法にとって問題となるため、取り扱いに注意が必要であり、ODEに対する初期値問題の数値解法とDDEの数値解法のもう一つの重要な違いである。 さらに悪いことに、この不連続性は伝播する。すなわち
は
で不連続を持ち、3次導関数が
で不連続を持つ。この単純なDDEでは、定数遅延が1つしかないので、どこに不連続点があるかを特定するのが簡単である。さらに、tが大きくなるにつれて不連続性が弱まり、微分階数が大きくなっていくので、解
はどんどん滑らかになる。これは "遅れ型 " (retarded) 遅延微分方程式と呼ばれる遅延微分方程式の特徴である。 dde23は定数遅延しか扱わないので、不連続性がどこで発生するかを前もって計算することができる。複数の遅延がある場合、これは厄介な作業となる。その詳細を説明するために定数遅延が2つある場合を考えてみる。
この場合、
における不連続性は
で現れ、
で再び現れる。そして
,
,
,…,
の各々で現れる。 この例はMATLABにある例で、遅延微分方程式の連立系
を
で初期履歴
(
)から計算している。定数遅延はベクトル[1, 0.2]で指定され、遅延微分方程式はddex1deという関数で記述され、履歴はddex1histという関数で記述されている。以下のように実行すると
における不連続性が見られる。 sol = dde23(@ddex1de,[1, 0.2],@ddex1hist,[0, 2]);
plot(sol.x,sol.y,LineWidth=1.4)
title('An example of Wille'' and Baker.');
% function s = ddex1hist(t)
% % Constant history function for DDEX1.
% function dydt = ddex1de(t,y,Z)
% % Differential equations function for DDEX1.
さらに初期履歴に
における不連続性だけでなく、他のより強力な不連続性が存在する場合も計算できる。すなわち最初の例で初期履歴を
のような矩形波にとると
で不連続なジャンプが起こる。この初期履歴からDDEを計算すると dde = @(t,y,Z) -0.2*Z(:,1);
ddehist = @(t) (-1).^floor(-4*t);
opts = ddeset('AbsTol',1.0e-8,'Jumps',[-1,-0.75,-0.5,-0.25,0]);
sol = dde23( dde, delay, ddehist, tspan, opts )
dde23には、Jumpsオプションで初期履歴の不連続点の位置を知らせることもできる。そして予測された不連続点は格納されている。
sol.discont
-1.0000 -0.7500 -0.5000 -0.2500 0 0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000 2.2500 2.5000 2.7500 3.0000 3.2500 3.5000 3.7500 4.0000
解をプロットしてみる。
fplot(ddehist,[-1,0],LineWidth=1.4)
plot(sol.x,sol.y,LineWidth=1.4)
plot(t,dy,'--',LineWidth=1.4)
解
のグラフは
のグラフよりも滑らかである。この解の残差を見てみると不連続点付近で残差は悪く、解の計算が難しいことがわかる。しかし、計算を繰り返すことで残差は少しずつ小さくなっていく様子が見られる。これは遅れ型遅延微分方程式のおかげで段々と解の滑らかさが増していくことで、数値計算も安定してくるからである。 for t = linspace(j_prev,j,divN)
res = [res; dy - dde(t,y,z)];
semilogy(linspace(j_prev,j,divN),abs(res),LineWidth=1.4)
2. 状態依存の遅延をもつ遅延微分方程式
遅延微分方程式を一般的に書くと
と表され、
(
) を遅延関数と呼ぶ。ODEでは様々な形で非線形性が現れますが、DDEで新しいのは、遅延関数
が時間依存(定数遅延はこれ)、あるいは状態依存になる可能性があることである。つまり、
ではなく、
と遅延関数が未知関数自体に依存することがある。このとき遅延微分方程式は状態依存の遅延をもつという。次のような単純な問題を考えてみる。 初期条件は
とする。遅延関数は
で
では遅延はないが、
で遅延が発生する。dde23は定数遅延しか扱えなかったので、この場合はddesdという関数で数値計算する。時間
までの解を以下のコードでプロットする。呼び出し方はdde23と似ていて、t、y(t)、y(t/2)をzと指定し、遅延関数t/2を指定する。 % z'(t) = -0.25*z(t) + z(t/2)*(1-z(t/2)),
% z(0)=0.5, on 0 <= t <= 10ˆ3
dde = @(t,y,z) -0.25*y+z.*(1-z);
sol = ddesd( dde, dely, hist, [0,tend]);
t = linspace(0,tend,3*tend+1);
xlabel('t','FontSize',16)
ylabel('y','FontSize',16)
その残差はおおむね一様に
程度であることがわかる。 r2 = yp - (-0.25*y + y2.*(1-y2));
xlabel('t','FontSize',16)
ylabel('residual','FontSize',16)
この方程式はパンタグラフ方程式 (pantograph equation)といい。遅延微分方程式だが、初期履歴がいらない方程式である。
もう一つMATLABのodeexamplesのddex3 を実行してみる。
この例では次の方程式を考えている。
遅延関数は
であり、2式目に現れる。初期履歴は
(
)で与えられる。この遅延関数が「遅延」になっているかはこのままでは分からないが、もしも遅延関数が未知関数の未来の時刻の状態を必要とするなら、この問題は解けない。実はこの問題は解が
であり、
で
となるが、
で遅延が消失する。 dde = @(t,y,Z)[y(2); -Z(2,1).*y(2)^2.*exp(1 - y(2))];
dely = @(t,y) exp(1 - y(2));
hist = @(t) [log(t); 1./t];
sol = ddesd(dde, dely, hist, tspan);
plot(ta,ya,sol.x,sol.y,'o',LineWidth=1.4)
legend('y_1 exact','y_2 exact','y_1 ddesd','y_2 ddesd')
title('D1 Problem of Enright and Hayashi')
3. 中立型遅延微分方程式
これまでは遅延関数はyのみだったが、遅延関数がyの導関数を含む場合、すなわち
という形の場合、中立型遅延微分方程式という。この場合、不連続性は伝播するにつれて弱まることはなく、解の数値計算(と解析)はより難しくなる。次の中立型遅延微分方程式を考える。
初期履歴は
とする。MATLABでこの方程式を数値計算するには、遅延微分方程式ソルバー ddensd を使うが、ソルバーを呼び出す前に、方程式、遅延、および履歴をコード化する必要がある。 dde = @(t,y,ydel,ypdel) y + ypdel;
hist = ddensd(@(t,y,ydel,ypdel) 0, [], [], 1, [-1,0]); % ddesd( dde, dely, hist, [0,tend]);
sol = ddensd( dde, dely, delyp, hist, tspan);
t = linspace(0.0001,2.5,2001);
xlabel('t','FontSize',16)
ylabel('y','FontSize',16)
[~, zp] = deval(sol,t-1);
semilogy(t,abs(res./y),LineWidth=1.4)
4. Newton法
遅延微分方程式
の特性方程式
の根を数値計算するのにはニュートン法が効果的。 A = 0.1; B = -0.03; tau=1;
F = @(x) x - A - B*exp(-tau*x);
DF = @(x) 1 + B*tau*exp(-tau*x);
display(['Before step #1, ||F||_1 = ',num2str(norm(Fx,1))])
Before step #1, ||F||_1 = 650.694
while (itercount<=100) && (norm(Fx,1) > tol)
display(['After step # ',num2str(itercount+1),', ||F||_1 = ',num2str(norm(Fx,1))])
end
After step # 1, ||F||_1 = 237.3547
After step # 2, ||F||_1 = 85.571
After step # 3, ||F||_1 = 30.0156
After step # 4, ||F||_1 = 9.8709
After step # 5, ||F||_1 = 2.772
After step # 6, ||F||_1 = 0.51374
After step # 7, ||F||_1 = 0.031365
After step # 8, ||F||_1 = 0.00014038
After step # 9, ||F||_1 = 2.8493e-09
After step # 10, ||F||_1 = 1.7764e-15
5. スペクトル選点法(時間があれば)
まずはODEの初期値問題
をスペクトル選点法で解く。解は
以下のコードはChebfunというパッケージを使う。 a = 1; x0 = 1; % Problem parameters
dom = [0 1]; % Solution interval
n = 16; % Discretisation size
t = chebpts(n, dom); % Chebyshev grid
D = diffmat(n, dom); % Differentiation matrix
I = eye(n); % Identity matrix
z = zeros(1,n-1); % Zero vector
A = D - a*I; rhs = 0*t; % Discretised operator and RHS
% Enforce boundary condition via boundary bordering:
A(1,:) = [1, z]; rhs(1) = x0;
sol = exp(a*t)*x0; % Exact solution
err = norm(y - sol) % Error
plot(t, sol, '-', t, y, '.', MS, 15,LineWidth=1.4)
xlabel('t','FontSize',16)
ylabel('y','FontSize',16)
状態依存の遅延をもつ遅延微分方程式(パンタグラフ方程式)
解は
となる。 a = 1; b = -8; q = 0.5; x0 = 1; % Problem parameters
tau = q*t; % Pantograph-type delay
E = barymat(tau, t); % Barycentric interpolation matrix
A = D - a*I - b*E; rhs = 0*t; % Discretised operator
A(1,:) = [1, z]; rhs(1) = x0; % Boundary conditions
sol = @(t) -7/2*t.^3 + 21/2*t.^2 - 7*t + 1;
err = norm(y - sol(t)) % Error
tt = linspace(0, 1, 1001);
plot(tt, sol(tt), '-', t, y, '.', MS, 15, LineWidth=1.4)
xlabel('t','FontSize',16)
ylabel('y','FontSize',16)
定数の遅延をもつ遅延微分方程式
n = 10; a = 1; x0 = 1; p = 0.5;
% Left discretisation Right discretisation
domL = [0, p]; domR = [p, 2*p];
tL = chebpts(n, domL); tR = chebpts(n, domR); t = [tL ; tR];
DL = diffmat(n, domL); DR = diffmat(n, domR);
I = eye(n); Z = zeros(n,n);
AL = [DL - a*I, Z]; AR = [Z, DR - a*I];
rhsL = 0*tL; rhsR = 0*tR;
% Boundary and continuity conditions:
A = [B ; AL(2:n,:) ; C ; AR(2:n,:)];
rhs = [x0 ; rhsL(2:n) ; 0 ; rhsR(2:n)];
plot(tt, sol(tt), '-', t, y, '.', MS, 15, LineWidth=1.4)
xlabel('t','FontSize',16)
ylabel('y','FontSize',16)
tauL = max(tL - p,0); tauR = tR - p; % Discrete delay
EL = barymat(tauL, tL); ER = barymat(tauR, tL); % Interpolation matrices
AL = [DL - a*EL, Z]; AR = [-ER, DR]; % Discrete operators
A = [B ; AL(2:n,:) ; C ; AR(2:n,:)];
rhs = [x0 ; rhsL(2:n) ; 0 ; rhsR(2:n)];
sol = [a*tL + 1 ; (a*p+1)+a*(tR-p).*(.5*a*(tR-p)+1)];
plot(t, sol, '-', t, y, '.', MS, 15, LineWidth=1.4)
分布型の遅延をもつ遅延微分方程式
解は
(
). n = 16; dom = [0 1]; a = 1/2;
t = chebpts(n, dom); I = eye(n); z = zeros(1,n-1);
D = diffmat(n, dom); % Differentiation matrix
V = f(t,t').*cumsummat(n, dom); % Volterra operator
A = D - V + a*I; rhs = 0*t; % Discrete operator and RHS
A(1,:) = [1, z]; rhs(1) = x0; % Boundary conditions
sol = @(t) exp(-(a+1)/2*t).*(cosh(b*t) + .5*(1-a)/b*sinh(b*t));
plot(tt, sol(tt), '-', t, y, '.', MS, 15, LineWidth=1.4), shg
xlabel('t','FontSize',16)
ylabel('y','FontSize',16)