70
$\begingroup$

I'd like to know how can I call Mathematica functions from Python.

I appreciate a example, for example, using the Mathematica function Prime.

I had search about MathLink but how to use it in Python is a little obscure to me.

I tried to use a Mathematica-Python library called pyml but I hadn't no sucess, maybe because this lib looks very old (in tutorial says Mathematica 2 or 3).

So, someone knows a good way to write python programs who uses Mathematica functions and can give me an example?

Old Edit:

Maybe this edit can help someone who wants to use mathlinks directly.

To another solution, please see the answer accepted.

Using the Wolfram/Mathematica/8.0/SystemFiles/Links/Python I could had sucess in compiling the module changing some things in setup.py.

My architechture is x86-64.

1-Change the mathematicaversion to 8.0.

2-Changing the lib name ML32i3 to ML64i3.

3-Copying the file Wolfram/Mathematica/8.0/SystemFiles/Libraries/Linux-x86-64/libML64i3.so to the path pointed in setup.py library_dirs = ["/usr/local/Wolfram/Mathematica/" + mathematicaversion + "/SystemFiles/Links/MathLink/DeveloperKit/Linux/CompilerAdditions"].

5-Compiling the source with sudo python setup.py build.

6-Installing the lib with sudo python setup.py install

4-Editing the file /etc/ld.so.conf and putting the line include /usr/local/lib.

5-Creating a directory in /usr/local/lib/python2.6/dist-packages/mathlink with the lib libML64i3.so.

6-Running sudo ldconfig

I had tested the scripts guifrontend.py with python guifrontend.py -linkname "math -mathlink" -linkmode launch and textfrontend.py with python textfrontend.py -linkname "math -mathlink" -linkmode launch and worked fine.

Looks like I almost. But the script

>>> from mathlink import *
>>> import exceptions,sys, re, os
>>> from types import ListType
>>> mathematicaversion = "8.0"
>>> os.environ["PATH"] = "/usr/local/Wolfram/Mathematica/" + mathematicaversion + ":/usr/local/bin:/usr/bin:/bin"
>>> e = env()
>>> sys.argv=['textfrontend.py', '-linkname', 'math -mathlink', '-linkmode', 'launch']
>>> kernel = e.openargv(sys.argv)
>>> kernel.connect()
>>> kernel.ready()
0
>>> kernel.putfunction("Prime",1)
>>> kernel.putinteger(10)
>>> kernel.flush()
>>> kernel.ready()
0
>>> kernel.nextpacket()
8
>>> packetdescriptiondictionary[3]
'ReturnPacket'
>>> kernel.getinteger()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
mathlink.error: MLGet out of sequence.

breaks in the last command and I don't know why. How can I fix this?

$\endgroup$
17
  • $\begingroup$ Mathematica comes with Python bindings. They are found in SystemFiles/Links/Python in the Mathematica installation directory. You need to compile the C language part yourself before you can use this. This link is unsupported an the readme file says: "WRI has made no attempt to make the mathlink module compliant with versions of Python newer than 2.3.". I never used it so I can't tell you if it works with newer Pythons, but I'd give it a try. $\endgroup$
    – Szabolcs
    Apr 23, 2012 at 7:33
  • $\begingroup$ @Szabolcs. I tried to build the module to use this link. Unfortunally no sucess. Several error ocurrs when trying to run python setup.py build. $\endgroup$
    – GarouDan
    Apr 23, 2012 at 7:48
  • $\begingroup$ Well, what errors did you get and what have you tried to do to fix them? Have you read the documentation on how to compile? $\endgroup$
    – Szabolcs
    Apr 23, 2012 at 7:58
  • $\begingroup$ In documentations says the first thing is run this command (above) to create the module. The erros are so large that flooded my shell. See a part of it here. I think solve all of this is out of my hands. $\endgroup$
    – GarouDan
    Apr 23, 2012 at 8:03
  • 1
    $\begingroup$ Are there specific Mathematica only functions that you need to call? If not, it's quite likely that another library implements what you're after. numpy is an extensive math library for Python, for example. $\endgroup$
    – Peter
    Apr 23, 2012 at 11:19

7 Answers 7

28
$\begingroup$

This solution can work with several programming languages. Check this GitHub repository of mine.

See this link.

I have found a solution. Works fine to me.

Steps:

1-Create a script named runMath with the content:

#!/usr/bin/env wolframscript
# for certain older versions of Mathematica replace 'wolframscript' by
# 'MathematicaScript -script' in the shebang line

value=ToExpression[$ScriptCommandLine[[2]]];

(*The next line prints the script name.*)
(*Print[$ScriptCommandLine[[1]]];*)

Print[value];

2-I gave execution privilege to the file.

sudo chmod +x runMath

3-Moved the file to the execution path

sudo mv runMath /usr/local/bin/

4-Created a new script called run with the content:

#!/usr/bin/python
from subprocess import *
from sys import *

command='/usr/local/bin/runMath'
parameter=argv[1]

call([command,parameter])

5-Moved to the execution path

sudo mv run /usr/local/bin

6-Finally, tested it:

$run Prime[100]
541

$run 'Sum[2x-1,{x,1,k}]'
k^2

$run Integrate[Log[x],x]
-x + x*Log[x]

$run 'Zeta[2]'
Pi^2/6

You can use with ou without '. The ' are needed to command with spaces.

$run 'f[n_] := f[n] = f[n - 1] + f[n - 2]; f[1] = f[2] = 1; Table[f[n],{n,5}]'
{1, 1, 2, 3, 5}

Happy!

$\endgroup$
1
  • 2
    $\begingroup$ Is there a solution for Mac since it does not allow any changes in /usr/bin (since EI Capitan) $\endgroup$
    – zed111
    May 2, 2017 at 5:40
11
$\begingroup$

You can call Mathematica function in Python using the Python MathLink module (the source you found in .../SystemFiles/Links/Python), though you'll need to edit a couple of setup files to get it up and running ([email protected] should be able to help you out there).

To use Prime from Python you would run something like:

kernel.ready()

0

kernel.putfunction("Prime",1)

kernel.putinteger(10)

kernel.flush()

kernel.ready()

1

kernel.nextpacket()

3

packetdescriptiondictionary[3]

'ReturnPacket'

kernel.getinteger()

29

$\endgroup$
3
  • $\begingroup$ Looks like I'm almost nikko^^. Almost everything runned but the final command breaks. Could you take a look in this pastebin link and tell to me what's going on? $\endgroup$
    – GarouDan
    Apr 23, 2012 at 17:50
  • $\begingroup$ Thx a lot about your help nikko. $\endgroup$
    – GarouDan
    Apr 23, 2012 at 19:54
  • $\begingroup$ what is the source code license for Python MathLink C API? $\endgroup$
    – den.run.ai
    Feb 13, 2015 at 4:13
10
$\begingroup$

Better late than never, but the error in the python script appears to be due to the format of the current packet. Using your routine (with k = kernel):

>>> k.putfunction("Prime",1)
>>> k.putinteger(10)
>>> k.flush()
>>> k.nextpacket()
8

8 is a RETURNPKT, but what is the kernel returning?

>>> k.getnext()
34
>>> tokendictionary[34]
'MLTKSTR'

The kernel wants to send you a string, let's grab that instead

>>> k.getstring()
'In[1]:= '

I have noticed this behavior with the Python MathLink, namely that the kernel pretty adamantly wants to send us the first input prompt. Fair enough. Continuing:

>>> k. nextpacket()
3
>>> tokendictionary[k.getnext()]
'MLTKINT'
>>> k.getinteger()
29

Finally. The lesson here is that the python MathLink bindings need the end-user to pay very close attention to the packets being sent and their type. It is also very unforgiving; once you have thrown an error, no other kernel requests will be honored until k.clearerror() is called.

$\endgroup$
8
$\begingroup$

Try Jupyter and SAGE notebook extensions for Mathematica:

http://www.sagemath.org/doc/reference/interfaces/sage/interfaces/mathematica.html

https://github.com/bjedwards/IPython-mathematicamagic-extension

$\endgroup$
7
$\begingroup$

As yet another solution, you can use a new package called PJLink which implements JLink for python.

Once you have the package installed you start a KernelLink object and can use that to either evaluate strings or use the MathematicaBlock helper to write Mathematica-esque code:

>>> import sys, os
>>> path_to_PJLink = os.path.expanduser("~/Documents/Python/IDEA/PJLink")
>>> sys.path.insert(0, path_to_PJLink)
>>> from PJLink import create_kernel_link
>>> kernel = create_kernel_link()
>>> kernel.evaluateString("$Version")
'11.3.0 for Mac OS X x86 (64-bit) (March 7, 2018)'
>>> with MathematicaBlock():
...   print(kernel.evaluate(RandomReal([-1, 1], [5, 5, 5])))
... 
[[[ 0.82333428 -0.22120173  0.28668275  0.04229312  0.92312944]
  [-0.43474731  0.64218193 -0.54186876 -0.6428228  -0.21671452]
  [-0.05066144 -0.29888543 -0.45723433  0.46926194 -0.72166916]
  [ 0.60358171  0.67254163  0.22736352  0.42711063  0.702733  ]
  [ 0.89118955 -0.76092357  0.65784946  0.42381519 -0.18184603]]

 [[-0.05566714  0.32324674  0.16537235  0.29394423 -0.3826456 ]
  [-0.30799836  0.61072882  0.87721626 -0.40292037 -0.99221593]
  [ 0.79848099  0.86318783 -0.09653227 -0.30479808  0.81070852]
  [ 0.15083946  0.71684487 -0.54012157 -0.70812674  0.16847963]
  [-0.54408339 -0.17084765  0.25754549  0.62201424 -0.41126613]]

 [[ 0.24181817  0.65082232 -0.9448459  -0.6740693  -0.70014564]
  [ 0.04181131 -0.45243563  0.02266605  0.67429721  0.53853541]
  [ 0.79842224  0.38250834 -0.42321046  0.62054957 -0.78189105]
  [ 0.91608362  0.91750963 -0.03043691  0.35382865 -0.42971801]
  [ 0.05856562  0.38297739  0.21494046 -0.77326953 -0.06090548]]

 [[-0.38581506  0.40810805 -0.06970923  0.58814432  0.970209  ]
  [-0.63803971 -0.26755306 -0.55287498  0.51696225  0.2504991 ]
  [ 0.57078906 -0.40804371 -0.26543291 -0.05022896 -0.34215896]
  [-0.27644055 -0.06931716  0.17401444 -0.5905933  -0.74513478]
  [ 0.16364204 -0.12781597 -0.77921589  0.90835378 -0.86846471]]

 [[-0.00391625  0.64797141 -0.32733043 -0.85628204 -0.39096691]
  [ 0.99579966 -0.08433519 -0.94709096  0.42123235 -0.35505469]
  [ 0.62157133  0.85142865  0.63162374 -0.43469092 -0.86983996]
  [ 0.98171147  0.0102183  -0.45457086 -0.40369601  0.45952086]
  [ 0.38977525 -0.23563561 -0.66688691  0.51853403  0.23597912]]]

that last bit there returned as a numpy.ndarray since I had NumPy installed, but it uses a different memoryview-esque thing if there's no NumPy to use

$\endgroup$
6
$\begingroup$

I haven't done this before, so can't share any useful experiences, but you can try using JLink from Jython to connect to Mathematica. I am fairly sure that the amount of glue code necessary will be quite small.

A quick hack to make your attempt for PyhtonLink work would be to add the folder with the mentioned shared lib to LD_LIBRARY_PATH (Linux). You can do so by modifying some global scripts, or you can start your process in a shell script, having first redefined LD_LIBRARY_PATH there.

$\endgroup$
3
  • $\begingroup$ Leonid, thx about your clue. Firstly I will try just with python as I'm trying above. But if I do not have any success I will try Jython^^. Anyway, if you can take the time to look at this and get a running code I would like to know. Thx. $\endgroup$
    – GarouDan
    Apr 23, 2012 at 18:10
  • $\begingroup$ @GarouDan I will keep this in mind, and try it when I get some time on my hands, but this won't probably be until the end of the week. $\endgroup$ Apr 23, 2012 at 18:19
  • $\begingroup$ Leonid, I had found a solution. Take a look after. Thx about your help. $\endgroup$
    – GarouDan
    Apr 23, 2012 at 19:51
2
$\begingroup$

In May 16, 2019, Wolfram Client Library for Python is announced, so nowadays the problem can be solved easily with:

from wolframclient.evaluation import WolframLanguageSession
from wolframclient.language import wl

session = WolframLanguageSession()

session.evaluate(wl.Prime(50))
#229
$\endgroup$
1
  • $\begingroup$ Should be the most upvoted answer ! $\endgroup$ yesterday

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.