对于我正在进行的数值计算,我需要定义一个大的
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上访问。
答案 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
的工作方式。