How to call SymPy Python function linear_eq_to_matrix

pycall

#1

I’m using SymPy in Julia to solve a system of equations and I would like to be able to call the SymPy function linear_eq_to_matrix as documented on this page: http://docs.sympy.org/latest/modules/solvers/solveset.html

I have a Python script containing the following code that uses the function:

#!/usr/local/bin/python
from sympy import *
x, y, z = symbols('x y z')
eqns = [x + 2*y + 3*z - 1, 3*x + y + z + 6, 2*x + 4*y + 9*z - 2]
print("eqns = ", eqns)
A, b = linear_eq_to_matrix(eqns, [x, y, z])
print("A = ", A)
print("b = ", b)

When I run this, I get the expected output:

eqns =  [x + 2*y + 3*z - 1, 3*x + y + z + 6, 2*x + 4*y + 9*z - 2]
A =  Matrix([[1, 2, 3], [3, 1, 1], [2, 4, 9]])
b =  Matrix([[1], [-6], [2]])

Now, when I try to do the same thing in Julia, I have tried the following input file:

#!/usr/local/bin/julia
using SymPy
@vars x y z
eqns = ([x + 2*y + 3*z - 1, 3*x + y + z + 6, 2*x + 4*y + 9*z - 2])
println("eqns = ", eqns)
A, b = linear_eq_to_matrix(eqns, ([x, y, z]))
println("A = ", A)
println("b = ", b)

But this fails with the following output/error:

eqns = SymPy.Sym[x + 2*y + 3*z - 1, 3*x + y + z + 6, 2*x + 4*y + 9*z - 2]
ERROR: LoadError: UndefVarError: linear_eq_to_matrix not defined
Stacktrace:
 [1] include_from_node1(::String) at ./loading.jl:569
 [2] include(::String) at ./sysimg.jl:14
 [3] process_options(::Base.JLOptions) at ./client.jl:305
 [4] _start() at ./client.jl:371
while loading /...path_to_my_file.../juliaTest.jl, in expression starting on line 10

I have tried to figure out how to use PyCall or something similar to directly call this function but with no success. I have confirmed that I am calling/using the same versions of Python/SymPy in Julia so that’s not the issue. I have also confirmed that the SymPy function “solveset” which is documented on the link I provided above does work as expected in both Julia and Python, so it seems like Julia should be able to call “linear_eq_to_matrix” somehow, even if it’s a bit clunky.

Can someone please show me how to do this? Thanks.


#2

Apparently that function isn’t explicitly wrapped by SymPy, but you can call the Python function directly by:

A, b = SymPy.sympy["linear_eq_to_matrix"](eqns, x, y, z)

#3

I just noticed that using either [“linear_eq_to_matrix”] or [:linear_eq_to_matrix] will work.

Would it be possible for you to comment on why either syntax is acceptable? And help me know if there are certain times I would need to use one or the other?

If I need to start a new topic for this though that’s fine too.

Thanks so much for your help! :smiley:


#4

I am pretty sure the difference is negligible. You can always use @time before the function to see which one takes slightly longer. And by negligible, I mean you should only worry about it if you use it in a humongous loop in which case you should be far more concerned with SymPy’s slowness, because it is written in Python, than with the difference between the 2 PyCall syntaxes.


#5

Either syntax works. As explained in the PyCall README, doing foo[:bar] or foo["bar"] are both analogous to foo.bar in Python, but foo[:bar] will try to convert the result to a native Julia type if possible while foo["bar"] will always return a PyObject. Whenever I have something that I know returns a function/method object, which will get left as a PyObject anyway, I tend to use foo["bar"] to avoid the type-introspection step, but in most cases it won’t make a noticeable performance difference.


#6

Excellent. Thanks for the quick and very helpful feedback guys. Code on!


#7

If speed isn’t an issue, I have a PR adding a sympy_str macro, so that you can call this as sympy"linear_eq_to_matrix"(...). The advantage is this will check beyond the sympy module to try and resolve the call, which is needed for some calls.