0

私が取り組んでいる数値計算では、大きな Liouvilian 行列を定義する必要があります。面倒でエラーが発生しやすい要素ごとにプログラムするのではなく、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 定義する必要があるため、これは機能しませんでした。これは聞いたことがなく、ラムダ化した行列のタイプでさえありません。

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次のように、2 番目の引数を使用しての名前空間に追加できます。

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

しかし、SymPy の最新バージョンではこのマッピングは既に行われているため、これは必要ありませ"numpy"ん。基本的には、ラムダ文字列と名前変換の名前空間を作成し、その名前空間で文字列を s するだけです。この問題は、IPython の並列処理、またはその使用のどこかにあると思われます。1 つの提案、あなたのlambdifyexec

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.matrixas として インポートするだけ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 に答える