Python SciPy RK45(solve_ivp)是否准确计算功能评估的数量?

Python SciPy RK45(solve_ivp)是否准确计算功能评估的数量?,python,scipy,runge-kutta,ode45,Python,Scipy,Runge Kutta,Ode45,我想用SciPy来衡量我自己的ODE积分器的性能。因此,我需要确切地知道RK45使用的右侧函数求值的数量 是否有人知道sol.nfev的数字是否准确,即无需重复?例如,如果RK45拒绝一个步长并重复该步长,则该步长的初始计算f(t,x)是否计数多次? 此外,RK45使用的有7个阶段,但实际上每个步骤仅使用6个评估,因为“第一个与最后一个相同”属性(最后一个阶段与下一个步骤的第一个阶段在同一点进行评估)。这在sol.nfev中得到了解释吗?经过一些实验后,我可以确认RK45计数准确,即未对重复进行

我想用SciPy来衡量我自己的ODE积分器的性能。因此,我需要确切地知道RK45使用的右侧函数求值的数量

是否有人知道sol.nfev的数字是否准确,即无需重复?例如,如果RK45拒绝一个步长并重复该步长,则该步长的初始计算f(t,x)是否计数多次?

此外,RK45使用的有7个阶段,但实际上每个步骤仅使用6个评估,因为“第一个与最后一个相同”属性(最后一个阶段与下一个步骤的第一个阶段在同一点进行评估)。这在sol.nfev中得到了解释吗?

经过一些实验后,我可以确认RK45计数准确,即未对重复进行评估和计数。对于想知道如何解释sol.nfev这个数字的人:
表示RK45报告为
num_steps=len(sol.t)-1的RK步数,以及
num_rej
报告的被拒绝步数。那么它就成立了

sol.nfev = (num_steps + num_rej) * 6 + 2
因为每个步骤需要6个功能评估,除了第一个需要7个。另外,在开始时有一个Euler步长来生成初始步长(因此
+2
)。感谢@LutzLehmann指出这一点

以下是一个例子:

class Fun:
def __init__(self):
    self.t = []
    self.x = []

def __call__(self, t, x):
    self.t.append(t)
    self.x.append(x)
    if t <= 1:
        return - x ** 2
    return 10  # discontinuity to provoke step rejection

t0 = 0
t1 = 1.01
x0 = [1]
sol = solve_ivp(Fun(), (t0, t1), x0)

print(sol.nfev)
print(len(f.t))
num_steps = len(sol.t) - 1
print(num_steps)
print(num_steps * 6 + 2)

我们可以看到,最终解决方案中有7个RK步骤
sol
,但由于函数的不连续性,也有2个被拒绝的步骤(44+2*6=56)。

您可以在右侧函数之外创建一个列表,并将所有计算的t附加到该列表中。集成后,您可以检查该列表是否与set(list)具有相同的长度。在我的零星测试中,我从未遇到过失败的步骤。我不确定Shampine或Haier的代码引用中是否包含失败的步骤机制在第一步中执行一个额外的Euler步骤,可能是为了计算合理的初始步长。看见
56
56
7
44