我试图理解我一起屠杀的代码有什么问题。下面的代码是我今天为解决Lotka Volterra微分方程(2系统)所做的许多实现之一,它是我最接近期望结果的那个。
import matplotlib.pyplot as plt
import numpy as np
from pylab import *
def rk4( f, x0, t ):
"""
4th order Runge-Kutta method implementation to solve x' = f(x,t) with x(t[0]) = x0.
USE:
x = rk4(f, x0, t)
INPUT:
f - function of x and t equal to dx/dt.
x0 - the initial condition(s).
Specifies the value of x @ t = t[0] (initial).
Can be a scalar of a vector (NumPy Array)
Example: [x0, y0] = [500, 20]
t - a time vector (array) at which the values of the solution are computed at.
t[0] is considered as the initial time point
h = t[i+1] - t[i] determines the step size h as suggested by the algorithm
Example: t = np.linspace( 0, 500, 200 ), creates 200 time points between 0 and 500
increasing the number of points in the intervall automatically decreases the step size
OUTPUT:
x - An array containing the solution evaluated at each point in the t array.
"""
n = len( t )
x = np.array( [ x0 ] * n ) # creating an array of length n
for i in xrange( n - 1 ):
h = t[i+1] - t[i] # step size, dependent on the time vector.
# starting below - the implementation of the RK4 algorithm:
# for further informations visit http://en.wikipedia.org/wiki/Runge-Kutta_methods
# k1 is the increment based on the slope at the beginning of the interval (same as Euler)
# k2 is the increment based on the slope at the midpoint of the interval (with x + 0.5 * k1)
# k3 is AGAIN the increment based on the slope at the midpoint (with x + 0.5 * k2)
# k4 is the increment based on the slope at the end of the interval
k1 = f( x[i], t[i] )
k2 = f( x[i] + 0.5 * k1, t[i] + 0.5 * h )
k3 = f( x[i] + 0.5 * k2, t[i] + 0.5 * h )
k4 = f( x[i] + h * k3, t[i] + h )
# finally computing the weighted average and storing it in the x-array
x[i+1] = x[i] + h * ( ( k1 + 2.0 * ( k2 + k3 ) + k4 ) / 6.0 )
return x
# model
def model(state,t):
"""
A function that creates an array containing the Lotka Volterra Differential equation
Parameter assignement convention:
a natural growth rate of the preys
b chance of being eaten by a predator
c dying rate of the predators per week
d chance of catching a prey
"""
x,y = state # will corresponding to initial conditions
# consider it as a vector too
a = 0.08
b = 0.002
c = 0.2
d = 0.0004
return np.array([ x*(a-b*y) , -y*(c - d*x) ]) # corresponds to [dx/dt, dy/dt]
################################################################
# initial conditions for the system
x0 = 500
y0 = 20
# vector of times
t = np.linspace( 0, 500, 1000 )
result = rk4( model, [x0,y0], t )
print result
plt.plot(t,result)
plt.xlabel('Time')
plt.ylabel('Population Size')
plt.legend(('x (prey)','y (predator)'))
plt.title('Lotka-Volterra Model')
plt.show()
上面的代码产生以下输出
但是,如果我将from pylab import *
代码移到正确的初始条件之上,我会得到正确的输出
为什么会发生这种情况,我该如何解决这个问题?
答案 0 :(得分:1)
pylab
定义了自己rk4
的实现,它从matplotlib
开始:
In [1]: import pylab
In [2]: pylab.rk4
Out[2]: <function matplotlib.mlab.rk4>
当您执行from pylab import *
之类的通配符导入时,您将覆盖任何具有相同名称的本地函数。
特别是,您在这里重新定义了自己的rk4
实现(即,您编写的代码从未使用过)。
这就是为什么你应该从不做那样的通配符导入。 pylab
特别成问题,因为它定义了几个函数(例如any
和all
),它们与某些输入的python内置函数具有完全不同的输出。
无论如何,问题的根本原因似乎是您的RK4实现不正确。
您需要在计算k_n
时使用步长。
例如,这里是我自己的RK4实现的一小部分(我承认,它是针对速度而非可读性而调整的):
while not target(xs):
...
# Do RK4
self.f(xs, self.k1)
self.f(xs + halfh*self.k1, self.k2)
self.f(xs + halfh*self.k2, self.k3)
self.f(xs + self.h*self.k3, self.k4)
xs += sixthh*(self.k1 + self.k2 + self.k2 + self.k3 + self.k3 \
+ self.k4)
您会注意到整个状态向量乘以h
,而不仅仅是时间分量。
尝试在您自己的代码中修复它,看看结果是否相同。
(在我看来,维基等习惯将时间视为特殊情况是造成很多这些问题的原因。你的时间向量ts
只是一个特殊的衍生物{{1} }。)
因此,对于您自己的代码,我相信,但尚未经过测试,这样的事情应该有效:
t' = 1
答案 1 :(得分:0)
尝试
import pylab
help(pylab.rk4)
你会找到pylab.rk4命令的详细解释。
这就是使用from x import *
不是一个好主意的原因。做import pylab as py
要好得多,然后这不会成为问题。
请注意,即使移动了导入命令,您可能必须rk4
的任何后续调用都将失败。