For a numerical computation I am working on, I need to define a large
Liouvillian matrix. Rather than program it in element by element, which is
tedious and error-prone, I have used Sympy to construct it algebraically, and
then use lambdify
to make numpy matrices for use in numerical work. This works
fine for small tasks, but weird errors happen when I distribute these functions to worker engines using IPython.parallel
.
Here, for example, I construct a dumb sympy matrix that doesn't mean anything:
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)])
In the case of this example, I could have constructed a numpy matrix directly using the same nested loop, but this isn't true of the matrix in my actual problem. Anyway it is nice to see it written out in algebraic notation before plugging in numbers.
I use lambdify
to get a Numpy matrix for my numerical work:
numer_L = s.lambdify((x,y), L, 'numpy')
numer_L(3,4) # gives numpy matrix for x=3, y=4
Say I want to do a computation involving this matrix (determinant, say)
evaluated at multiple values of y
:
# in series
import numpy
s_result = list(map(lambda y: numpy.linalg.det(numer_L(3,y)), range(30)))
This example isn't expensive, but if it were, I would distribute the task like:
# 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))
I get the following error:
[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
That didn't work because apparently the lambda function needs ImmutableMatrix
defined, which I hadn't ever heard of, and is not even the type of the matrix we
lambdified:
type(L) # sympy.matrices.dense.MutableDenseMatrix
In any case, I don't want my engines running any Sympy code. The task I want to distribute is numerical, not algebraic, and hopefully lambdify has generated numpy code that can run on its own.
What is the proper way to generate parallelizable numpy code from sympy?
Versions
This was done with Python 2.7.3, IPython 1.1.0, Sympy 0.7.4.1, and Numpy 1.8.0. The notebook I used to write this question is accessible on nbviewer.