0

对于我正在进行的数值计算,我需要定义一个大的刘维利矩阵。我没有逐个元素地对它进行编程,这既繁琐又容易出错,我使用 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 矩阵:

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

这不起作用,因为显然需要ImmutableMatrix 定义 lambda 函数,这是我从未听说过的,甚至不是我们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上访问。

4

2 回答 2

2

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

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

但是对于最新版本的 SymPy,这应该是不必要的,因为该映射已经完成"numpy",正如您在此处看到的那样。基本上所有lambdify要做的就是创建一个 lambda 字符串和一个名称转换的命名空间,然后execs 该命名空间中的字符串。我怀疑问题可能出在 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你原来的命名空间中做呢?

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

于 2014-01-16T02:40:23.740 回答
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如果我只导入as ,看起来这应该可以工作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))

失败并出现与以前相同的错误。

我通过将生成的代码作为字符串推送并自己进行评估来使其工作:

# 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

于 2014-01-15T23:24:15.487 回答