[SciPy-dev] python / mathematica

Fernando Perez Fernando.Perez at colorado.edu
Thu Oct 7 23:12:04 EDT 2004


Jelle Feringa // EZCT / Amsterdam schrieb:
> Dear Mr Perez,
> 
> I'm sorry to get back to a discussing which has been long due.
> My interest in combining the powers of both Mathematica and Python.
> I've been checking out for instance PY_ML, I'm sure you are aware of it,
> also the fact that its outdated (for Mathematica v3, I'm using 5)
> Could you be so kind to point me in the right direction for the interface as
> being discussed in the scipy forum?

Well, I don't really know more than what's on that archive.  I don't have 
direct contact with the person who mentioned the mathematica project, so you'd 
have to dig him out of the internet :)

Here, we've mostly just kept mathematica and python as parallel tools without 
much communication.  All I can offer, I guess, are a couple of little 
utilities I wrote to facilitate exchaning _data_ between the two with minimal 
fuss.  But this is NOT an API for cross-calling, just a way to automatically 
generate a .py module from within a mathematica file and to auto-generate a .m 
file out of python variables.  I'll just post them here in case they are 
useful to you or others.  I guess that perhaps some of this could make it into 
some 'utilities' area of scipy, much like the facilities for interfacing with 
matlab files.  Obviously this requires having mathematica installed, since I 
didn't write anything for reading .m files in python.

Best,

f

Please note that while the code below has been used for real work, it's not 
exhaustively tested.  Test first :)

#############################
# Python code
import sys
import Numeric as N

def MathematicaSave(fname,varnames,ns=None,precision=18):
     """Save a list of names to a Mathematica file.

     The resulting file can be used in Mathematica via '<<fname'.

     Inputs:

     - fname: name of mathematica file, typically ending in .m.

     - varnames: a list/tuple of names to be used

     Optional:

     - ns: a namespace where the list of names is to be evaluated, typically
     locals().  If not provided, this function automatically extracts the
     locals() of the caller.

     - precision: float precision passed to Numeric's array2string function.

     Caveats:

     - This function is NOT perfect, because Mathematica's floating point
     format requires changing numbers from 1.23e+04 to 1.23^*+04.  This is done
     as a string replacement on 'e', so accidentally strings may end up
     modified (though for normal strings the code tries to avoid this).

     - Mathematica does NOT allow underscores in variable names.  This function
     simply removes them blindly, so if you try to save both 'ab' and 'a_b',
     the second one will overwrite the first."""

     # get all variables first
     if ns is None:
         ns = sys._getframe(1).f_locals
     val = {}
     try:
         for varname in varnames:
             val[varname] = ns[varname]
     except KeyError,key:
         print '*** ERROR ***'
         print 'Variable not found:',key
         print 'Aborting without creating file \'%s\'' % fname
         return

     # Our values for generating repr().  There's a bug in array2string, so I
     # need to put things into sys and use repr(), which seems to be the only
     # string-generating function which works correctly
     output_line_width = 80
     float_output_precision = precision

     # Don't mess up user settings
     save_olw = save_fop = 0
     if hasattr(sys,'output_line_width'):
         save_olw = 1
         save_olw_val = sys.output_line_width
     if hasattr(sys,'float_output_precision'):
         save_fop = 1
         save_fop_val = sys.float_output_precision

     # Store values in sys
     sys.output_line_width = output_line_width
     sys.float_output_precision = float_output_precision

     # if we get this far, we have everything we need for saving
     mfile = open(fname,'w')
     print >> mfile,'(* File automatically created by Python. *)\n'
     for name in varnames:
         var = val[name]
         if type(var) == N.ArrayType: # numeric arrays
             vstr = N.array_repr(var)
             vstr = vstr.replace('[','{').replace(']','}').replace('e','*^')
             vstr = vstr.replace('array(','').replace(')','')
         elif isinstance(var,str):  # simple strings
             vstr = '"%s"' % var
         elif hasattr(var,'__getslice__'):  # lists, tuples, etc
             vstr = str(var).replace('[','{').replace(']','}').replace('e','*^')
         elif isinstance(var,(float,complex)):  # single float/complex numbers
             vstr = str(var).replace('e','*^')
         else: # the rest.  This probably won't be valid Mathematica
               # except for integers.
             vstr = str(var)
         # Save the variable's representation to the Mathematica file, removing
         # all underscores from the name
         print >> mfile,'%s = %s;\n' % (name.replace('_',''),vstr)
     mfile.close()

     # Restore user settings
     if save_olw:
         sys.output_line_width = save_olw_val
     if save_fop:
         sys.float_output_precision = save_fop_val


#############################
# Mathematica code

pythonSave[fname_, symnames_List, precision_:24] := Module[
       {k, sym, symname, snamestr, symCForm, pysym, pyfile},
       pyfile = OpenWrite[fname];
       (* Write python header.
             Mathematica uses "\< ... \>" for multiline strings *)

       WriteString[pyfile,
         "\<\"\"\" *** FILE AUTO-GENERATED BY MATHEMATICA.  DO NOT EDIT!!! *** \
\"\"\"

from Numeric import array

\>"];
       For[k = 1, k <= Length[symnames], k++,
         symname = Extract[Unevaluated[symnames], k, Hold];
         snamestr =
           StringReplace[ToString[symname], {"Hold[" -> "", "]" -> ""}];
         sym = SetPrecision[ReleaseHold[symname], precision];
         pysym = ToString[sym, CForm];
         (* Print["name: ", symname];
           Print["name2: ", snamestr];
           Print["sym:  ", sym]; *)
         (* For lists,
           CForm doesn't cut it in python, we need to change things a bit *)

               If[Head[sym] === List,

           pysym = StringForm["array(`1`)",
                 StringReplace[pysym, {"List(" -> "[", ")" -> "]"}]];
           ];
         WriteString[pyfile, StringForm["`1` = `2`\n\n", snamestr, pysym]];
         ]; (* End for loop *)
       Close[pyfile];
       ] (* End module *);
SetAttributes[pySave, HoldRest];

#############################




More information about the SciPy-Dev mailing list