使用Sympy的“lambdify”时出错`IPython.parallel`

2024-09-27 04:11:31 发布

您现在位置:Python中文网/ 问答频道 /正文

对于我正在进行的数值计算,我需要定义一个 刘维矩阵。而不是一个元素一个元素地编程 冗长且容易出错,我用Sympy来代数地构造它,并且 然后使用lambdify生成numpy矩阵,用于数值计算。这很管用 对于小任务来说很好,但是当我使用IPython.parallel将这些函数分发到工作引擎时,会发生奇怪的错误。在

例如,在这里,我构造了一个没有任何意义的哑sympy矩阵:

import sympy as s
from sympy.abc import x,y
s.init_printing()

element = lambda n, m : m * x**n if (n+m) % 3 else y
L = s.Matrix([[element(n,m) for m in range(9)] for n in range(9)])

在这个例子中,我可以直接构造一个numpy矩阵 使用相同的嵌套循环,但这不是真的矩阵在我的实际 问题。不管怎样,很高兴看到它在以前用代数表示法写出来 插入数字。在

我使用lambdify为我的数值计算得到一个Numpy矩阵:

^{pr2}$

假设我要做一个包含这个矩阵的计算(比如行列式) 以y的多个值进行评估:

# in series
import numpy
s_result = list(map(lambda y: numpy.linalg.det(numer_L(3,y)), range(30)))

这个例子并不昂贵,但如果是的话,我会将任务分配如下:

# set up parallel environment. 2 engines started with `ipcluster start -n 2`
from IPython.parallel import Client
rc = Client()
dview = rc[:]

# in parallel
# do imports and push our lambda function over
dview.execute('import numpy')
dview.push(dict(numer_L=numer_L))
p_result = dview.map_sync(lambda y: numpy.linalg.det(numer_L(3,y)), range(30))

我得到以下错误:

[0:apply]: 

---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)<string> in <module>()

<ipython-input-5-1f431230550c> in <lambda>(y)

/Users/tkb/.virtualenvs/sympy/lib/python2.7/site-packages/numpy/__init__.pyc in <lambda>(x, y)

NameError: global name 'ImmutableMatrix' is not defined



[1:apply]: 

---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)<string> in <module>()

<ipython-input-5-1f431230550c> in <lambda>(y)

/Users/tkb/.virtualenvs/sympy/lib/python2.7/site-packages/numpy/__init__.pyc in <lambda>(x, y)

NameError: global name 'ImmutableMatrix' is not defined

这不起作用,因为显然lambda函数需要ImmutableMatrix 定义的,我从来没听说过,甚至不是我们的矩阵类型 删减:

type(L)  # sympy.matrices.dense.MutableDenseMatrix

无论如何,我不想让我的引擎运行任何sypy代码。我想要的任务 分布是数值的,不是代数的,希望lambdify已经生成了 可以独立运行的numpy代码。在

从sympy生成可并行化numpy代码的正确方法是什么?在

版本

这是用Python2.7.3、IPython 1.1.0、Sympy0.7.4.1和Numpy1.8.0完成的。我用来写这个问题的笔记本可以在nbviewer上访问。在


Tags: lambdainimportnumpyparallelipythonrange矩阵
2条回答

您可以使用第二个参数将内容添加到lambdify的名称空间,例如

>>> lambdify(x, Matrix([[x, 2], [3, 4]]), [{'ImmutableMatrix': numpy.matrix}, "numpy"])(1)
matrix([[1, 2],
   [3, 4]])

但是对于最新版本的SymPy,这应该是不必要的,因为映射已经用"numpy"完成了,如您所见{a1}。基本上,lambdify所做的就是创建一个lambda字符串和一个名称转换的名称空间,然后execs该名称空间中的字符串。我怀疑问题可能出在ipythonparallel的某个地方,或者你对它的使用。一个建议

^{pr2}$

可能是伊普顿对你来说太聪明了。如果您还在原始名称空间中执行from numpy import matrix as ImmutableMatrix操作,会怎么样?在

抱歉,如果这是一个没有回答,但它不适合评论。在

我不知道这是否是最好的答案,但这是我目前的解决办法。 我检查了lambdify源代码,发现了一个lambdastr函数 生成的代码应该显示:

from sympy.utilities.lambdify import lambdastr
lstr = lambdastr((x,y), L, dummify=True)

生成的代码lstr如下所示:

^{pr2}$

如果我只是将numpy.matrix导入为 ImmutableMatrix,但没有骰子:

# in parallel
# do imports and push our lambda function over
dview.execute('import numpy')
dview.execute('from numpy import matrix as ImmutableMatrix')
dview.push(dict(numer_L=numer_L))
p_result = dview.map_sync(lambda y: numpy.linalg.det(numer_L(3,y)), range(30))

失败,错误与以前相同。在

我通过将生成的代码作为一个字符串推送,并执行eval来实现它 我自己:

# in parallel
# do imports and push our lambda function over
dview.execute('import numpy')
dview.execute('from numpy import matrix as ImmutableMatrix')
dview.push(dict(lstr=lstr))
p_result = dview.map_sync(lambda y: numpy.linalg.det(eval(lstr)(3,y)), range(30))

这是有效的,并与按顺序计算的结果相匹配

p_result == s_result  # True

所以,我有点工作,但感觉不太对劲 可能是由于lambdify的工作方式。在

相关问题 更多 >

    热门问题