[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