使用Sympy的`lambdify`和`IPython.parallel`的错误

时间:2014-01-15 23:17:02

标签: python numpy ipython sympy ipython-parallel

对于我正在进行的数值计算,我需要定义一个大的 Liouvillian矩阵。而不是逐个元素地编程,这是 单调乏味且容易出错,我用Sympy代数构造它,并且 然后使用lambdify制作用于数值工作的numpy矩阵。这有效 对于小任务很好,但是当我使用IPython.parallel将这些函数分发给工作引擎时会发生奇怪的错误。

在这里,例如,我构建了一个没有任何意义的愚蠢的交际矩阵:

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矩阵:

numer_L = s.lambdify((x,y), L, 'numpy')
numer_L(3,4)  # gives numpy matrix for x=3, y=4

说我想做一个涉及这个矩阵的计算(比如说决定因素) 以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 定义,我从未听说过,甚至不是我们矩阵的类型 lambdified:

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

无论如何,我不希望我的引擎运行任何Sympy代码。我想要的任务 分布是数字的,而不是代数的,并且希望lambdify产生 可以单独运行的numpy代码。

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

版本

这是通过Python 2.7.3,IPython 1.1.0,Sympy 0.7.4.1和Numpy 1.8.0完成的。我用来写这个问题的笔记本可以在nbviewer上访问。

2 个答案:

答案 0 :(得分:2)

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

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

但是,对于最新版本的SymPy,这应该是不必要的,因为该映射已经使用"numpy"完成,您可以看到here。基本上所有lambdify都会创建一个lambda字符串和一个名称翻译的命名空间,然后exec是该命名空间中的字符串。我怀疑这个问题可能存在于IPython并行的某个地方,或者你使用它。一个建议,与你的

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))
p_result

可能是因为IPython太聪明了。如果您还在原始命名空间中执行from numpy import matrix as ImmutableMatrix该怎么办?

很抱歉,如果这不是一个答案,但它不适合评论。

答案 1 :(得分:1)

我不知道这是否是最好的答案,但这是我目前的解决方法。 我检查了lambdify源代码并找到了lambdastr函数 应该告诉我生成的代码:

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

以下是生成的代码lstr的外观:

'lambda x,y: (ImmutableMatrix([[y, 1, 2, y, 4, 5, y, 7, 8], [0, x, y, 3*x, 4*x, y, 6*x, 7*x, y], [0, y, 2*x**2, 3*x**2, y, 5*x**2, 6*x**2, y, 8*x**2], [y, x**3, 2*x**3, y, 4*x**3, 5*x**3, y, 7*x**3, 8*x**3], [0, x**4, y, 3*x**4, 4*x**4, y, 6*x**4, 7*x**4, y], [0, y, 2*x**5, 3*x**5, y, 5*x**5, 6*x**5, y, 8*x**5], [y, x**6, 2*x**6, y, 4*x**6, 5*x**6, y, 7*x**6, 8*x**6], [0, x**7, y, 3*x**7, 4*x**7, y, 6*x**7, 7*x**7, y], [0, y, 2*x**8, 3*x**8, y, 5*x**8, 6*x**8, y, 8*x**8]]))'

如果我只是导入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的工作方式。