跳到正文
格致开物MATHWIKI

亚当斯—巴什福思法

亚当斯—巴什福思法(Adams–Bashforth method)是求解常微分方程初值问题的一族显式线性多步法。它把已经算出的几个时刻的导数连成插值多项式,再对这个多项式积分,预测下一个状态。新状态不出现在待求方程右端,因此每步不必求解隐式方程;代价是需要历史数据,并受到稳定性步长的限制。

从两个已知斜率预测下一步

考虑无量纲衰减模型 y′=−y、y(0)=1,精确解为 e−t。记等间距时刻为 tn=t0+nh,其中 h>0;数值近似为 yn,已知斜率为 fn=f(tn,yn)。

显式欧拉法只用当前斜率。若还保存前一步的斜率,就能估计斜率正在怎样变化。在本例中,随着存量降低,负斜率也逐渐接近零;把刚才的下降速度一直保持不变会忽略这一趋势。

对一般方程 y′=f(t,y),精确解满足 y(tn+1)−y(tn)=∫tntn+1f(t,y(t))dt. 令 θ=(t−tn)/h。通过 θ=0,−1 两个导数值的直线是 p(θ)=fn+θ(fn−fn−1). 将它从零积分到一,得到二阶、二步 Adams–Bashforth 格式,简称 AB2: yn+1=yn+h(32fn−12fn−1). 系数中的负号来自向未来外推,并非把前一步的状态直接减去。积分的对象是导数。Adams 方法的插值积分构造和线性多步法的记号见 Driscoll 与 Braun 的教材。[1]

两个历史导数确定一条外推直线,下一时间区间上的面积用于预测状态增量
示意取导数曲线 g(t)=−exp(−t),用 t=0、0.2 两点外推到 0.4。着色部分是导数近似的积分,不是状态曲线下的面积。

更一般地,通过 fn,fn−1,…,fn−k+1 的次数不超过 k−1 的插值多项式积分,给出固定步长的 k 步 Adams–Bashforth 法。例如三步格式是 yn+1=yn+h12(23fn−16fn−1+5fn−2). 增加历史点并不意味着任意步长都更稳定;阶数、起步误差和稳定区域要分别检查。

手算衰减过程与起步

AB2 在计算 y2 前需要 y0,y1。这里用显式梯形起步:先预测 y^1=y0+hf(t0,y0),再平均初始斜率与预测点斜率。取 h=0.2,得到 y^1=0.8,y1=1+0.1(−1−0.8)=0.82. 因此 f0=−1,f1=−0.82。下一步为 y2=0.82+0.2[−32(0.82)+12]=0.674. 再用 f2=−0.674 推进: y3=0.674+0.2[−32(0.674)+12(0.82)]=0.5538. 精确值分别为 e−0.4≈0.670320046 和 e−0.6≈0.548811636。这组结果不是将误差藏在首步:起步值也来自同一个可复算算法。

一个有解的变式是 y′=t,y(0)=0。显式梯形起步得到 y1=h2/2。由于真实导数本来就是直线,后续插值没有误差,AB2 给出 yn=tn2/2。例如 h=0.2 时,y1=0.02,y2=0.08。它说明二阶方法能够精确处理某些特殊问题,而非所有误差都必然非零。

二阶精度的误差来源

先把精确历史值放进格式,以排除已有误差。设沿精确解的导数函数 g(t)=y′(t) 有连续二阶导数,且 |g″|≤M。线性插值余项在下一段满足 g(tn+θh)−p(θ)=h22θ(θ+1)g″(ζθ),0≤θ≤1. 积分并取绝对值,单步状态缺陷因而不超过 Mh32∫01θ(θ+1)dθ=512Mh3. 这里的三次方是一步状态误差;约 1/h 步的累积通常留下二次方的全局误差。

这个累积可以证明。若 f 对状态满足常数为 L 的利普希茨条件,记状态误差为 en,上述缺陷界为 Ch3。两份递推相减得到 |en+1|≤(1+3Lh/2)|en|+(Lh/2)|en−1|+Ch3. 令 En=max0≤j≤n|ej|,便有 En+1≤(1+2Lh)En+Ch3。在固定终止时间 T 内迭代,并用 (1+2Lh)n≤e2LT,可得 En≤e2LT(E1+CTh2). 所以准确到 O(h2) 的起步值,加上足够光滑的解,保证全局二阶收敛。证明也标出了前提:历史误差会被继承,起步不能随意指定。

衰减问题中的稳定步长

对测试方程 y′=λy,令 z=hλ,格式成为 yn+1=(1+3z/2)yn−(z/2)yn−1. 试取模式 yn=rn,得到特征方程 r2−(1+3z/2)r+z/2=0. 对负实数 z,两个根都严格位于单位圆内的区间为 −1<z<0。端点 z=−1 出现根 −1,扰动可以不断换号而不衰减。若本例用 h=2,同样的起步给出 y1=1,后续值为 y2=−1,y3=3,y4=−7:真实解趋零,离散值却发散。精度阶数没有排除这种不稳定。

这也是刚性微分方程需要专门积分器的原因。软件中的变步长、变阶 Adams 算法还会重新计算系数、估计误差并选择步长;不能把固定系数 AB2 直接称为完整的自适应求解器。SUNDIALS 对实际 Adams 与 BDF 求解器的区分说明了这一点。[2]

可运行的标量实现

下列代码对标量右端使用 AB2,首步用上述显式梯形法。输入为函数、有限初值、正步长和非负整数步数;返回包含初值的时间与状态列表,不修改调用者的数据。每个常规步只需一次新的右端求值;若把一次右端求值视为常数成本,总时间为 O(N),保存全部轨迹占 O(N) 空间,滚动历史本身只需常数空间。

Python 3
import math


def ab2(f, t0, y0, h, steps):
    if not isinstance(steps, int) or steps < 0:
        raise ValueError("steps must be a nonnegative integer")
    t0, y0, h = map(float, (t0, y0, h))
    if not all(math.isfinite(v) for v in (t0, y0, h)) or h <= 0:
        raise ValueError("finite data and positive h required")

    def slope(t, y):
        value = float(f(t, y))
        if not math.isfinite(value):
            raise ArithmeticError("nonfinite derivative")
        return value

    ts, ys = [t0], [y0]
    if steps == 0:
        return ts, ys
    previous = slope(t0, y0)
    predicted = y0 + h * previous
    first_time = t0 + h
    if not math.isfinite(first_time) or not math.isfinite(predicted):
        raise OverflowError("nonfinite starting prediction")
    y = y0 + h * (previous + slope(first_time, predicted)) / 2
    if not math.isfinite(y):
        raise OverflowError("nonfinite state")
    ts.append(first_time)
    ys.append(y)
    if steps == 1:
        return ts, ys
    current = slope(ts[-1], y)
    for n in range(1, steps):
        y = ys[-1] + h * (1.5 * current - 0.5 * previous)
        t = t0 + (n + 1) * h
        if not math.isfinite(t) or not math.isfinite(y):
            raise OverflowError("nonfinite time or state")
        ts.append(t)
        ys.append(y)
        previous, current = current, slope(t, y)
    return ts, ys


ts, ys = ab2(lambda t, y: -y, 0, 1, 0.2, 3)
print([round(v, 6) for v in ys])  # [1.0, 0.82, 0.674, 0.5538]

有限输入仍不保证浮点运算永不溢出,也不保证所选步长稳定。这里检查非有限结果,但不实现误差容限或自动步长控制。对变步长数据,历史节点不再等距,必须重建相应插值权重。

参考资料

  1. ↑ Tobin A. Driscoll, Richard J. Braun. Fundamentals of Numerical Computation: Multistep methods,Adams 插值积分、起步与稳定性。
  2. ↑ SUNDIALS Development Team. CVODE: Mathematical Considerations,Adams 与 BDF 方法、误差和非线性求解。