我正在使用SymPy 1.0和Python 2.7。我想计算前100个整数的总和:
此代码成功运行
import sympy as sy
from sympy.tensor import IndexedBase, Idx
import numpy as np
x = sy.IndexedBase('x')
i = sy.symbols('i', cls=Idx)
s = sy.Sum(x[i], (i, 0, 100))
s_lambda = sy.lambdify(sy.DeferredVector('x'), s, 'numpy')
s_lambda(np.arange(101))
按预期给出5050
。但是,当我尝试使用Product
代替Sum
:
import sympy as sy
from sympy.tensor import IndexedBase, Idx
import numpy as np
x = sy.IndexedBase('x')
i = sy.symbols('i', cls=Idx)
s = sy.Product(x[i], (i, 0, 100))
s_lambda = sy.lambdify(sy.DeferredVector('x'), s, 'numpy')
s_lambda(np.arange(101))
我得到了NameError: global name 'Product' is not defined
我究竟做错了什么?是否有解决方法来获得我想要的东西?
编辑1:
如果我事先不知道Product
的限制怎么办?让我们来说像
import sympy as sy
from sympy.tensor import IndexedBase, Idx
import numpy as np
x = sy.IndexedBase('x')
i = sy.symbols('i', cls=Idx)
n = sy.symbols('n', integer=True, positive=True)
s = sy.Product(x[i], (i, 0, n))
s_lambda = sy.lambdify((sy.DeferredVector('x'), n) s.doit(), 'numpy')
s_lambda(np.arange(101), 5)
编辑2:
我试图找到一种解决方法。由于这个原因,我发现了NameError: global name 'Product' is not defined
错误:
lambdastr((sy.DeferredVector('x'), n), p)
这给出了:
lambda x,n: (Product(x[i], (i, 0, n)))
虽然Sum
我们得到了一个有效的lambda函数:
lambda x,n: ((builtins.sum(x[i] for i in range(0, n+1))))
此时问题围绕Product
函数的定义。根据手册,我可以通过dict
我的函数定义来注入
def my_prod(a, b):
# my implementation
pass
my_fun = {"Product" : my_prod}
f = sy.lambdify((sy.DeferredVector('x'), n), p, modules=['numpy', my_fun])
f([1,2,3,4,5], 2)
问题是,当我尝试使用lambdified函数list indices must be integers, not Symbol
时,会出现f
错误。我想这是因为i
是一个符号,而它应该是一个整数。我无法理解为什么在尝试致电integer
之前未通过实际的my_prod
,而是Sum
案例。
答案 0 :(得分:4)
Product
的限制您可以通过调用.doit()
将Product
扩展为其组成部分来解决此问题:
In [104]: s = sy.Product(x[i], (i, 1, 10)); s
Out[104]: Product(x[i], (i, 1, 10))
In [105]: s.doit()
Out[105]: x[1]*x[2]*x[3]*x[4]*x[5]*x[6]*x[7]*x[8]*x[9]*x[10]
例如,
import sympy as sy
from sympy.tensor import IndexedBase, Idx
import numpy as np
x = sy.IndexedBase('x')
i = sy.symbols('i', cls=Idx)
s = sy.Product(x[i], (i, 1, 10))
s_lambda = sy.lambdify(sy.DeferredVector('x'), s.doit(), 'numpy')
print(s_lambda(np.arange(11)))
打印
3628800
但是,如果您将.doit()
与sy.Product(x[i], (i, 1, 100))
一起使用,那么您将获得算术溢出,因为np.arange(101)
具有dtype int32
或int64
(取决于您的OS)和产品100!
In [109]: math.factorial(100)
Out[109]: 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
太大,无法存储在int32
或int64
数组值中。
In [118]: np.iinfo('int64').max
Out[118]: 9223372036854775807
In [119]: np.iinfo('int64').max < math.factorial(100)
Out[119]: True
因此,
s = sy.Product(x[i], (i, 1, 100))
s_lambda = sy.lambdify(sy.DeferredVector('x'), s.doit(), 'numpy')
print(s_lambda(np.arange(101)))
提出
RuntimeWarning: overflow encountered in long_scalars
并错误地打印0
。
如果您将dtype int64
数组的输入更改为Python int
的列表,那么
产品可以正确计算:
import sympy as sy
from sympy.tensor import IndexedBase, Idx
import numpy as np
x = sy.IndexedBase('x')
i = sy.symbols('i', cls=Idx)
s = sy.Product(x[i], (i, 1, 100))
s_lambda = sy.lambdify(sy.DeferredVector('x'), s.doit(), 'numpy')
print(s_lambda(np.arange(101).tolist()))
打印
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Product
的限制 >
解决方法
(AFAICS)变得更加复杂。如果使用调试器来跟踪代码路径
当Sum
被使用时你会发现它
LambdaPrinter._print_Sum
被调用以将Sum(x[i], (i, 0, n))
转换为表达式builtins.sum(x[i] for
i in range(0, n+1))
。
如果我们向_print_Product
(NumPyPrinter
的子类)添加LambdaPrinter
方法,
然后我们可以lambdify
成功将Product
转换为NumPy可以评估的表达式:
import sympy as sy
from sympy.tensor import IndexedBase, Idx
import numpy as np
import sympy.printing.lambdarepr as SPL
def _print_Product(self, expr):
loops = (
'for {i} in range({a}, {b}+1)'.format(
i=self._print(i),
a=self._print(a),
b=self._print(b))
for i, a, b in expr.limits)
return '(prod([{function} {loops}]))'.format(
function=self._print(expr.function),
loops=' '.join(loops))
SPL.NumPyPrinter._print_Product = _print_Product
x = sy.IndexedBase('x')
i = sy.symbols('i', cls=Idx)
n = sy.symbols('n', integer=True, positive=True)
s = sy.Product(x[i], (i, 1, n))
s_lambda = sy.lambdify((sy.DeferredVector('x'), n), s, 'numpy')
print(s_lambda(np.arange(101), 5))
打印
120