python-sympy: lambdify возвращает неправильный ответ, когда функция определена кусочно

Я сбит с толку тем, почему ответ на следующий код равен 10, а не 1. Может ли кто-нибудь помочь мне понять, что происходит с lambdify или что создает неправильный ответ?

import sympy
from sympy.utilities.lambdify import lambdify
from sympy import Function
from sympy.abc import x, y

def kFct(xIndex,loc,k1,k2):
...   if xIndex <= loc:
...     return k1
...   else:
...     return k2
... 
loc = 0.5
k1 = 1
k2 = 10

kfun = lambdify( (x,y), kFct(x,loc,k1,k2) )
print kfun(0,0)
>>> 10

Почему ответ не k1 или 1, поскольку x = 0 меньше loc = 0.5?

Однако он возвращает правильный ответ, если я делаю

print kfct(0,loc,k1,k2)
>>> 1

Мне нужно иметь kfun как функцию x и y, потому что позже я использую его как часть аргумента для интеграла. Это также в конечном итоге будет зависеть от y.

Я использую Python 2.6.8 на Mac 10.6.x.


person Eli    schedule 06.01.2013    source источник


Ответы (2)


Аргументы lambdify оцениваются до того, как они будут переданы, поэтому вы на самом деле не передаете свою функцию lambdify, вы передаете число 10:

>>> kFct(x, loc, k1, k2)
10

Вы получаете 10 здесь, потому что

>>> x <= loc
x <= 0.5
>>> bool(x <= loc)
False

и так вторая ветвь взята. Из-за того, как работает Python, я не думаю, что вы сможете заставить это работать — вы не можете подавить выполнение только одной ветки. (В принципе, программа может выполнять какую-то сумасшедшую самоанализ байт-кода, но я почти уверен, что sympy этого не делает.)

Однако вы можете использовать implemented_function:

>>> f = implemented_function(Function('kFct'), lambda x,y: kFct(x, loc, k1, k2))
>>> kfun = lambdify((x,y), f(x,y))
>>> kfun(0,0)
1
>>> kfun(0.5,0)
1
>>> kfun(0.51,0)
10
>>> kfun(1, 0.0)
10

Я не уверен, насколько это действительно полезно для вас, учитывая дополнительную косвенность: я бы, вероятно, просто работал с самой функцией (при условии, что вы в конечном итоге ищете числовую оценку интеграла).

person DSM    schedule 06.01.2013

Вы хотите использовать Piecewise, который символически представляет if-ветви, с которыми может работать SymPy.

Вот ваш пример со значениями loc, k1 и k2, указанными явно. Конечно, вы можете использовать их символически и позже заменить на subs, если ваш код диктует это.

>>> kFct = Piecewise((1, x < 0.5), (10, True))
>>> kfun = lambdify(x, kFct)
>>> kfun(0)
1
>>> kfun(1)
10
person asmeurer    schedule 08.01.2013