1

我开始通过编写 ODE 求解器来学习 Python。我想透明地处理单变量或多变量输入函数。这是我的欧拉方法一步的代码:

def euler(h, t, y, f):
    return (y + h*f for y,f in zip(y,f(t,y)))

现在我定义了两个函数,f1就像f2这样:

def f1(t,y):
    return -2*t*y

def f2(t,y):
    x, y = y #is rebinding usually ok, or confusing?
    return (x - t*y, y + x/t)

当我测试它们时,这就是(显然)发生的事情

>>> list(euler(0.01, 1, (1,2), f2))
[0.99, 2.03]
>>> list(euler(0.01, 1, 1, f1))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in euler
TypeError: zip argument #1 must support iteration

如果给定的函数适用于一个或多个变量,我希望求解器能够透明地处理,但还没有找到一种很酷的方法。我发现的一种方法是

import operator as op
def euler(h, t, y, f):
    if op.isNumberType(y):
        return (y + h*f(t,y),)
    return (y + h*f for y,f in zip(y,f(t,y)))

但是现在我传递了一个浮点数并返回了一个可迭代的,所以list(euler(...))可以成功。但是,例如,我不能调用f(t,euler(...)).

有没有办法将单例序列作为原始类型处理,或者将原始序列作为单例序列处理而无需无休止的检查?我所说的“无休止的检查”是指只需要检查几个地方,而不是检查我的代码。或者我应该把它吸起来,然后f(t,y)期待一个序列而不是一个数字?

感谢您的帮助,也欢迎有关我的编码的提示!

4

3 回答 3

1

在您的 euler 函数中,您可以捕获 TypeError 并通过封装在列表中并重试来恢复。

于 2012-04-29T21:45:10.217 回答
1

一种可能的解决方案是以下列方式编写你的欧拉函数

def euler(h, t, y, f):
    if isinstance(y,collections.Iterable):
        return (y + h*f for y,f in zip(y,f(t,y)))
    else:
        return (y+h*f(t,y),)

另一种解决方案是将您的一维函数编写为

def f1(t,y):
    return (-2*t*y[0],)

然后按以下方式调用euler

list(euler(0.01, 1, (1,), f1))
于 2012-04-29T21:57:55.550 回答
1

使 f(t, y) 仅使用序列非常容易:

def euler(h, t, y, f):
    return (y + h*v for y,v in zip(y,f(t,y)))

def f1(t,status):
    x, = status
    return -2*t*x,

def f2(t,status):
    x, y = status
    return x - t*y, y + x/t


print list(euler(0.01, 1, (1,2), f2))
print list(euler(0.01, 1, (1,), f1))
于 2012-04-29T22:12:51.367 回答