Lambdify参数积分

时间:2018-07-04 12:41:53

标签: python-3.x sympy

我遇到以下问题:我想lambdify一个sympy表达式,其中包含像Integral(tanh(a*x),(x,0,1))这样的参数积分。我尝试进行手动实施like here.

本质上我们想要的是将积分转换为类似的东西:

lambda theta: quad(lambda x: g(x,theta), a,b)[0]

其中

g = sp.lambdify((x,param), f, modules='numpy'))

请考虑以下MWE:

import sympy as sp
import numpy as np
from scipy.integrate import quad

def integral_as_quad(function, limits):
    x, a, b = limits
    param = function.free_symbols - {x}
    f = sp.lambdify( (x,*param), function, modules='numpy')
    return lambda y: quad(lambda x: f(x,y), a,b)[0]

a, x = sp.symbols('a,x')
I = sp.Integral(sp.tanh(a*x),(x,0,1))
K = integral_as_quad(sp.tanh(a*x),(x,0,1))
L = sp.lambdify(a, I, modules=['numpy', {'Integral':integral_as_quad}] )

然后调用例如K(1)返回正确的值。但是L(1)给出了

AttributeError: 'Mul' object has no attribute 'tanh'

有人知道如何解决此问题吗?

注意:手动执行操作是不可行的,因为我处理的表达式要复杂得多,并且可能包含多个不同的整数。所以我真的需要让lambdify工作。

2 个答案:

答案 0 :(得分:2)

我认为从integral_as_quad返回一个lambda是行不通的,因为将不会调用该lambda,因为SymPy中的Integral对象是不可调用的。相反,可以通过参数元组的quad参数将其传递给args。我进行的另一项更改是在外部Lambdification中取代了

modules=['numpy', {'Integral':integral_as_quad}] 

modules=[{'Integral': integral_as_quad}, 'sympy'] 

这个想法是,在这个阶段我们还不需要NumPy函数,我们只想用我们的callable代替Integral。 modules列表的顺序很重要:该字典排在第一位,以防止SymPy将积分保持为积分。

现在L(1)返回正确的金额。

import sympy as sp
import numpy as np
from scipy.integrate import quad

def integral_as_quad(function, limits):
    x, a, b = limits
    param = tuple(function.free_symbols - {x})
    f = sp.lambdify((x, *param), function, modules=['numpy'])
    return quad(f, a, b, args=param)[0]

a, x = sp.symbols('a,x')
I = sp.Integral(sp.tanh(a*x), (x,0,1))
L = sp.lambdify(a, I, modules=[{'Integral': integral_as_quad}, 'sympy'])

答案 1 :(得分:0)

因此,我发现了一种可能的解决方法,但由于它对我的应用程序太慢而令我不满意,它是:

def to_lambda(expr, param):
    # Preprocessing
    expr = expr.evalf()
    f = sp.lambdify([param], expr, modules='sympy')
    fun = lambda x: np.array(np.array(f(x).evalf()), dtype='float64')
    return fun

因此,首先,expr使用sympy函数转换为lambda函数,例如我们有

f = lambda a: Integral(tanh(a*x),(x,0,1))

然后我们通过sympy使用evalf()的内部积分器(慢!)。

也不要问我为什么会有双np.array,如果将dtype='float64'放入第一个,则返回TypeError: __array__() takes 1 positional argument but 2 were given