跳转到内容

并行谱数值方法/非线性常微分方程和迭代

来自维基教科书,开放世界中的开放书籍

非线性常微分方程和迭代

[编辑 | 编辑源代码]

隐式显式方法避免了直接求解非线性问题。这对某些问题可能是有利的,但在其他问题中可能导致嚴重的步长限制。此外,由此产生的数值方案有时可能具有不良的定性特性。出于这个原因,我们需要描述允许我们求解完全隐式数值方案中产生的非线性方程的方法。

我们考虑一个常微分方程 ,其中 ,其中 不一定是关于 的线性函数。我们希望使用隐式数值方法来获得该问题的近似解 - 例如向后欧拉方法。如果我们想要证明数值方案的收敛性,我们需要证明我们用来在使用向后欧拉方法时找到非线性方程项的解的函数迭代的收敛性。

以下结果主要来自 Iserles[1],虽然这些材料也经常出现在微积分教材中,例如 Lax, Burstein 和 Lax[2],以及 Hughes 等人[3]。我们将令 表示时间步长 时的时刻, 表示时间步长 时的近似解, 表示时间步长。我们将假设 是 Lipschitz 连续的,这是一个比可微更弱但比连续更强的条件,我们将在后面给出它的精确定义。有两种经典的迭代方法

  • 不动点迭代
  • 牛顿 (牛顿-拉夫森) 法。

我们将证明这两种方法的收敛性(修正牛顿-拉夫森方法的收敛性证明见 Iserles[4])。我们将分析特定问题 ,其中初始数据为 .

非线性常微分方程示例的精确解

[编辑 | 编辑源代码]

我们考虑 以及初始条件 。只要解 存在,它始终为正,因为初始值为正,且 为正。

为了显式地积分这个方程,我们使用变量分离法,发现 ,这意味着 ,其中 是积分常数。使用我们的初始条件,我们得到 ,所以 是这个问题的精确解。我们将使用这个精确解来比较不同迭代方法获得的数值解。请注意,当 时,这个精确解变为无穷大。

证明收敛所需的定义

[编辑 | 编辑源代码]

定义函数 被称为利普希茨函数,如果对于所有 在定义域 内满足

利普希茨条件有两个具体的定义。

定义 函数 被称为局部利普希茨函数,如果对于每个 ,都存在一个 ,使得 在以 为中心、半径为 的开球上是利普希茨函数。

定义 如果 在整个空间 上是利普希茨函数(即上面的定义中开球是 ),那么 被称为全局利普希茨函数。

请注意局部利普希茨条件和全局利普希茨条件之间的根本区别。在局部版本中,利普希茨“常数”()和开球都取决于每个点 ,而在全局版本中,“常数”()是固定的,开球是 。特别是,全局利普希茨函数是局部利普希茨连续的,但反之则不成立。

常微分方程解的存在性和唯一性

[编辑 | 编辑源代码]

Peano 定理指出,如果 是连续的,那么常微分方程 至少在时间 的某个邻域内存在解,但该解不一定是唯一的。Picard 定理指出,如果 是局部 Lipschitz 连续的,那么常微分方程 的解在存在时是唯一的,初始条件为 。这些定理的详细陈述可以在 Iserles[5] 中找到,许多关于常微分方程的书籍中都有这些定理的证明(例如 Birkhoff 和 Rota[6])。

后向欧拉方法

[edit | edit source]

我们回忆一下后向欧拉方法由 给出。注意,如果 是非线性的,我们需要在每一步推进解的过程中求解一个非线性方程(数值)。使用解析方法精确地求解非线性方程通常很困难,因此我们也使用数值方法。对于我们的示例方程,我们得到 。这个例子有一个优点,我们可以用代数方法找到它的解,所以我们可以检查数值方案的行为。

函数迭代的收敛性

[edit | edit source]

我们经常使用函数迭代来求解非线性方程。我们回忆一下,有两种常用的方法:不动点迭代和牛顿法。

不动点法的收敛性

[edit | edit source]

我们想要找到一个方程 的根。我们尝试使用不动点法,构建一个序列 ,其中 .

定理 有一个不动点 ,对于 是 Lipschitz 连续的,其 Lipschitz 常数为 ,并且 上是连续的。那么不动点法 会收敛到 ,它是在 的唯一不动点。

证明 由于 是 Lipschitz 连续的,我们发现, 对于 。因此,通过归纳法,我们得出结论 由于 ,因此我们得到一个解 ,其中 是不动点。我们可以通过假设存在两个不同的极限并得出矛盾来证明该极限是唯一的。

有关在该定理中使用的假设下不动点存在的证明,请参阅数值分析方面的书籍,例如 Bradie[7] 或 Iserles[8]

关于我们的问题,我们应用不动点迭代,我们想要找到以下形式方程的根

 

 

 

 

( 1)

当时间步长 足够小时,则 。因此,只要时间步长足够小,不动点迭代就是收敛的。我们注意到方程式 1 具有两个根,因此初始迭代的域在确定选择哪个根方面起着重要作用。

牛顿法收敛性

[edit | edit source]

现在我们考虑牛顿法。我们想要找到一个根, 使得 牛顿法是一种不动点法,其中迭代由以下公式构造:

 

 

 

 

( 2)

其中 . 如果函数 行为良好,则牛顿法具有二次收敛速度。

定理 假设 是二次连续可微的,并且它的二阶导数是有界的。还假设存在 使得 . 假设 在区间 中, 在同一区间内是有限的,并且 很小。那么,牛顿法具有二次收敛速度。

Proof by Taylor expansion with Lagrange form remainder. In the above . Since , we have so Plug in the formula for , from eq. 2 we have Let We have and by our assumption, we know there is a constant such that Hence we have for some finite constant . So Newton's method is convergent provided is sufficiently small.

关于我们的问题,我们考虑 . 因此 并且 是有限的,所以如果我们适当地选择初始数据和初始迭代,我们的问题满足所有假设。因此,牛顿迭代将收敛并给出后向欧拉法的非线性项的近似值。

Theta 法的收敛性

[编辑 | 编辑源代码]

向后欧拉法、向前欧拉法和克朗尼克森法是 Theta 方法的特殊情况,因此我们将首先证明 Theta 方法的收敛性以包含这三种方法。Theta 方法是以下算法: 其中 。需要注意的是,当 时,我们得到克朗尼克森法或梯形法则。

首先,代入精确解 并使用泰勒展开,我们有

从以下表达式中减去最后一个表达式:

足够小时,我们有

其中

其中

其中 。使用三角不等式和 的 Lipschitz 连续性,存在常数 使得

如果

如果

时,theta 方法简化为梯形法则。可以证明 Crank-Nicolson 方法具有二阶收敛性,例如,参见 Iserles[9]。现在让我们考虑

我们断言 。我们用数学归纳法来证明这个结论。当 时,,因为初始条件是精确计算的。现在假设这个结论对 成立,其中 且为整数。我们需要证明这个结论对 也成立。考虑

然后代入

我们有

所以我们的断言对所有 成立。注意

根据指数函数的泰勒展开,我们有

根据我们的条件, 因此 因此,我们有 。 因此当 时,theta 方法是一阶收敛的。

需要注意的是,当 时,theta 方法的特殊情况是后向欧拉法,所以后向欧拉法是一阶收敛的。我们得到了定理结论。

定理 后向欧拉法是一阶收敛的。

备注 如果 是全局利普希茨的,那么我们可以对任何时间区间应用上述论证。如果 仅仅是局部利普希茨的,那么我们需要更仔细地分析情况。首先,根据皮卡定理,这个常微分方程在很短的时间内存在唯一的解。实际上,我们只需要知道利普希茨常数是有限的,而不需要知道它的确切值。

备注 如果不知道皮卡定理,可以通过时间离散化推导出常微分方程解的存在性和唯一性。

现在我们考虑 。该问题的精确解为 。因此 。在我们这个问题中, 显然是解析的,并且在局部上是 Lipschitz 连续的。很容易证明 不是全局 Lipschitz 连续的。如果一个函数 满足全局 Lipschitz 条件,那么存在一个有限常数 使得对于所有 都有 。在我们这个问题中,令 ,很容易验证

现在我们讨论如何找到局部 Lipschitz 常数 。当 可微时,我们通常只需对 求导,并在感兴趣的域中找到其导数的最大值。在我们的例子中, 很简单,我们只需要知道 Lipschitz 常数是有限的。因此,我们使用一种更粗略的方法来证明 Lipschitz 常数是有限的。

因此,找到 在这个问题中的最大值就足够了。在我们这个问题中, 是连续的。此外, 将始终为正,因为初始值为正,而 为正。连续函数在闭合有界集合中具有有限最大值。请注意,我们问题的精确解是 ,因此 。因此,我们知道我们问题中的 Lipschitz 常数是有限的。

最后,我们得到了函数迭代和我们问题的后向欧拉方法的收敛性。因此,我们针对 以及初始数据 的数值方案是收敛的。

推论 根据常微分方程解的存在性和唯一性定理以及本页中的定理,我们得出最终目标,即后向欧拉方法与函数迭代生成的数值解在时间步长 趋于零时存在且唯一。

备注 这需要在进行函数迭代时仔细选择初始迭代值。

备注 通常,ODE 的精确解是未知的,尽管可以推断出局部 Lipschitz 连续性。如果解变为无穷大,数值方法将无法收敛,或者如果近似解接近精确解,则会显示非常大的值。在这些情况下解释此类数值模拟时,需要谨慎。

使用迭代求解非线性常微分方程的示例程序

[编辑 | 编辑源代码]

以下两个 Matlab 和 Python 程序演示了示例方程的后向欧拉法。第一个程序使用不动点迭代来求解非线性项,第二个程序使用牛顿法来求解非线性项。

 

 

 

 

( A)
一个演示不动点迭代的 Matlab 程序 代码下载
% A program to solve y'=y^2 using the backward Euler
% method and fixed point iteration
% This is not optimized and is very simple

clear all; format compact; format short;
set(0,'defaultaxesfontsize',25,'defaultaxeslinewidth',.7,...
'defaultlinelinewidth',6,'defaultpatchlinewidth',3.7,...
'defaultaxesfontweight','bold')

n=10000; % Number of timesteps
Tmax=0.99; % Maximum time
y0=1; % Initial value
tol=0.1^10; % Tolerance for fixed point iterations
dt=Tmax/n; % Time step
y=zeros(1,n); % vector for discrete solution
t=zeros(1,n); % vector for times of discrete solution
y(1)=y0;
t(1)=0;
tic, % start timing
for i=1:n
    yold=y(i); ynew=y(i); err=1;
    while err>tol
        ynew=dt*yold^2+y(i);
        err=abs(ynew-yold);
        yold=ynew;
    end
    y(i+1)=ynew;
    t(i+1)=t(i)+dt;
end
toc, % stop timing
yexact=1./(1-t); max(abs(y-yexact)), % print the maximum error
figure(1); clf; plot(t,y,'r+',t,yexact,'b-.');
xlabel Time; ylabel Solution; legend('Backward Euler','Exact solution');
title('Numerical solution of dy/dt=y^2');

 

 

 

 

( Ap)
一个演示不动点迭代的 Python 程序 代码下载
#!/usr/bin/env python
"""
A program to solve y'=y^2 using the backward Euler
method and fixed point iteration
This is not optimized and is very simple
"""

import time
import matplotlib.pyplot as plt

N = 1000	# Number of timesteps
tmax = 0.99	# Maximum time
y0 = 1
t0 = 0	# Initial value
tol = pow(0.1,10)	# Tolerance for fixed point iterations
h = tmax/N	# Time step

y = [y0]	# Variables holding the values of iterations
t = [t0]	# Times of discrete solutions



T0 = time.clock()
for i in xrange(N):
yold = y[i]
ynew = y[i]
err = 1
while err > tol:
ynew = h*pow(yold,2)+y[i]
err = abs(ynew-yold)
yold = ynew
y.append(ynew)
t.append(t[i]+h)

T = time.clock() - T0	
yexact = [1.0/(1.0-x) for x in t]

print
print "Exact value: y(%d)=%f" % (tmax, 1/(1-tmax))
print "Value given by aproximation: y(%d)=%f" % (tmax, y[-1])
maxerr=(max([abs(y[i] - yexact[i]) for i in xrange(len(y))]))
print "Maximum error: %f" % maxerr
print "Elapsed time is %f" % (T)

plt.figure()
plt.plot(t,y,'r+',t,yexact,'b-.')
plt.xlabel('Time')
plt.ylabel('Solution')
plt.legend(('Backward Euler', 'Exact solution'))
plt.title('Numerical solution of dy/dt=y^2')
plt.show()


 

 

 

 

( B)
一个演示牛顿迭代的 Matlab 程序 代码下载
% A program to solve y'=y^2 using the backward Euler
% method and Newton iteration
% This is not optimized and is very simple

set(0,'defaultaxesfontsize',25,'defaultaxeslinewidth',.7,...
'defaultlinelinewidth',6,'defaultpatchlinewidth',3.7,...
    'defaultaxesfontweight','bold')

n=100000; % Number of timesteps
Tmax=0.99; % Maximum time
y0=1; % Initial value
tol=0.1^10; % Tolerance for fixed point iterations
dt=Tmax/n; % Time step
y=zeros(1,n); % vector for discrete solution
t=zeros(1,n); % vector for times of discrete solution
y(1)=y0;
t(1)=0;
tic, % start timing
for i=1:n
    yold=y(i); ynew=y(i); err=1;
    while err>tol
        ynew=yold-(yold-y(i)-dt*yold^2)/(1-2*dt*yold);
        err=abs(ynew-yold);
        yold=ynew;
    end
    y(i+1)=ynew;
    t(i+1)=t(i)+dt;
end
toc, % stop timing
yexact=1./(1-t); max(abs(y-yexact)), % print maximum error
figure(1); clf; plot(t,y,'r+',t,yexact,'b-.');
xlabel Time; ylabel Solution;
legend('Backward Euler','Exact solution');
title('Numerical solution of dy/dt=y^2');

 

 

 

 

( Bp)
一个演示牛顿迭代的 Python 程序。 代码下载
#!/usr/bin/env python
"""
A program to solve y'=y^2 using the backward Euler
method and Newton iteration
This is not optimized and is very simple
"""

import time
import matplotlib.pyplot as plt

N = 1000 # Number of timesteps
tmax = 0.99 # Maximum value
t0 = 0 # Initial t value
y0 = 1 # Initial value y(t0) = y0
tol = 0.1**10 # Tolerance for fixed point iterations
h = (tmax - t0)/N # Time step

y = [y0] # List for discrete solutions
t = [t0] # List with grid of discrete values of t

T0 = time.clock() #Start timing

for i in xrange(N):
    yold = y[i]
    ynew = y[i]
    err =1
    while err > tol:
        ynew = yold-(yold-y[i]-h*(yold**2))/(1-2*h*yold)
        err = abs(ynew-yold)
        yold = ynew
    y.append(ynew)
    t.append(t[-1]+h)

T = time.clock() - T0 # Stop timing


print "Exact value y(%f) = %f " % (t[N], 1/(1-t[N]))
print "Value given by approx y_n(%f) = %f" % (t[N], y[N])
print "The error = y-y_n = %f " % (abs(1/(1-t[N]) - y[N]))
print "Time taken = %f " % (T)

yexact = [1.0/(1.0-x) for x in t]

plt.figure();
plt.plot(t,y,'r+',t,yexact,'b-.');
plt.xlabel('Time')
plt.ylabel('Solution')
plt.legend(('Backward Euler', 'Exact Solution'))
plt.title('Numerical solution of dy/dt=y^2')
plt.show()
  1. 运行 Matlab 中的不动点迭代程序,并检查结果是否合理。现在,研究将时间步数从 0 到 0.99 的变化以及不动点迭代的容差对最大误差的影响。特别是,尝试 1,000 到 1,000,000(以 10 的幂表示)的时间步数范围,以及 (以 的幂表示)的容差范围。您应该观察到,细分数和容差的“理想”组合可以最小化误差。这些组合是什么?使用牛顿迭代重复整个过程。答案如何变化?
  2. 编写一个 Matlab 程序,使用 Crank-Nicolson 方法和不动点迭代来求解 ,其中 。解释为什么不动点迭代可以收敛到两个不动点。哪一个不动点给出了微分方程解的正确近似值?评论不动点迭代的初始迭代的选择如何决定方法收敛到的不动点。
    1. 证明微分方程 ,其中 不是 Lipschitz 连续的。
    2. 找到该微分方程的至少两个解析解。
    3. 使用前向欧拉法计算该微分方程的数值解。
    4. 使用后向欧拉法计算该微分方程的数值解。请务必尝试不动点迭代的不同初始猜测,而不仅仅是前一步的值;您应该能够计算出初始迭代的选择对数值方法选择的解的影响。对此发表评论。
    5. 使用隐式中点规则计算该微分方程的数值解。请务必尝试不动点迭代的不同初始猜测,而不仅仅是前一步的值;您应该能够计算出初始迭代的选择对数值方法选择的“解”的影响。对此发表评论。
    6. 使用牛顿迭代重复 (d) 和 (e)。
    7. 评论数值方法对求解没有唯一解的微分方程的适用性。
  1. 修改一维 Allen-Cahn 方程的程序,使其使用 Crank-Nicolson 方法和非线性项的定点迭代。您需要在实空间中计算非线性项,以便您的最终方案为 其中 表示时间步长,而 表示迭代次数。当连续迭代之间的最大差异足够小时,停止迭代。
  2. 修改二维 Allen-Cahn 方程的程序,使其使用 Crank-Nicolson 方法和非线性项的定点迭代。您需要在实空间中计算非线性项。
  1. Iserles (2009)
  2. Lax, Burstein 和 Lax (1979)
  3. Hughes 等人 (2008)
  4. Iserles (2009)
  5. Iserles (2009)
  6. Birkhoff 和 Rota (1989)
  7. Bradie (2006)
  8. Iserles (2009)
  9. Iserles (2009)

参考文献

[编辑 | 编辑源代码]

Birkhoff, G; Rota, G.C. (1989). 常微分方程 (第 4 版). 约翰·威立。

Bradie, B. (2006). 数值分析友好入门. 皮尔森。

Hughes-Hallett, D. (2008). 微积分,单变量和多变量 (第 5 版). 约翰·威立。 {{cite book}}: 未知参数 |coauthors= 被忽略 (|author= 建议) (帮助)

Iserles, A. (2009). 微分方程数值分析入门. 剑桥大学出版社。

Lax, A. (1976). 应用和计算微积分. 第 1 卷. 施普林格。

华夏公益教科书