程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

暂无数据

SymPy无法对产品进行羔羊化

发布于2019-12-04 09:04     阅读(1235)     评论(0)     点赞(11)     收藏(4)


我正在使用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了预期的结果。但是当我尝试使用a Product而不是a 进行相同操作时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)

问题是,list indices must be integers, not Symbol当我尝试使用lambdified函数时会引发错误f我猜这是由于i它是一个符号,而它应该是整数。我不明白为什么integer在尝试调用之前,它没有通过实际my_prodSum情况。


解决方案


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()与with一起使用sy.Product(x[i], (i, 1, 100))则由于np.arange(101)dtype int32int64(取决于您的操作系统)和产品,您将获得算术溢出100!

In [109]: math.factorial(100)
Out[109]: 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

太大,无法存储在int32int64数组值中。

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


所属网站分类: 技术文章 > 问答

作者:黑洞官方问答小能手

链接:https://www.pythonheidong.com/blog/article/167120/207c9ae31fc410cee9da/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

11 0
收藏该文
已收藏

评论内容:(最多支持255个字符)