Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/interfaces/mathematica.py
8814 views
1
r"""
2
Interface to Mathematica
3
4
The Mathematica interface will only work if Mathematica is installed on your
5
computer with a command line interface that runs when you give the ``math``
6
command. The interface lets you send certain Sage objects to Mathematica,
7
run Mathematica functions, import certain Mathematica expressions to Sage,
8
or any combination of the above.
9
10
To send a Sage object ``sobj`` to Mathematica, call ``mathematica(sobj)``.
11
This exports the Sage object to Mathematica and returns a new Sage object
12
wrapping the Mathematica expression/variable, so that you can use the
13
Mathematica variable from within Sage. You can then call Mathematica
14
functions on the new object; for example::
15
16
sage: mobj = mathematica(x^2-1) # optional - mathematica
17
sage: mobj.Factor() # optional - mathematica
18
(-1 + x)*(1 + x)
19
20
In the above example the factorization is done using Mathematica's
21
``Factor[]`` function.
22
23
To see Mathematica's output you can simply print the Mathematica wrapper
24
object. However if you want to import Mathematica's output back to Sage,
25
call the Mathematica wrapper object's ``sage()`` method. This method returns
26
a native Sage object::
27
28
sage: mobj = mathematica(x^2-1) # optional - mathematica
29
sage: mobj2 = mobj.Factor(); mobj2 # optional - mathematica
30
(-1 + x)*(1 + x)
31
sage: mobj2.parent() # optional - mathematica
32
Mathematica
33
sage: sobj = mobj2.sage(); sobj # optional - mathematica
34
(x - 1)*(x + 1)
35
sage: sobj.parent() # optional - mathematica
36
Symbolic Ring
37
38
39
If you want to run a Mathematica function and don't already have the input
40
in the form of a Sage object, then it might be simpler to input a string to
41
``mathematica(expr)``. This string will be evaluated as if you had typed it
42
into Mathematica::
43
44
sage: mathematica('Factor[x^2-1]') # optional - mathematica
45
(-1 + x)*(1 + x)
46
sage: mathematica('Range[3]') # optional - mathematica
47
{1, 2, 3}
48
49
If you don't want Sage to go to the trouble of creating a wrapper for the
50
Mathematica expression, then you can call ``mathematica.eval(expr)``, which
51
returns the result as a Mathematica AsciiArtString formatted string. If you
52
want the result to be a string formatted like Mathematica's InputForm, call
53
``repr(mobj)`` on the wrapper object ``mobj``. If you want a string
54
formatted in Sage style, call ``mobj._sage_repr()``::
55
56
sage: mathematica.eval('x^2 - 1') # optional - mathematica
57
2
58
-1 + x
59
sage: repr(mathematica('Range[3]')) # optional - mathematica
60
'{1, 2, 3}'
61
sage: mathematica('Range[3]')._sage_repr() # optional - mathematica
62
'[1, 2, 3]'
63
64
Finally, if you just want to use a Mathematica command line from within
65
Sage, the function ``mathematica_console()`` dumps you into an interactive
66
command-line Mathematica session. This is an enhanced version of the usual
67
Mathematica command-line, in that it provides readline editing and history
68
(the usual one doesn't!)
69
70
Tutorial
71
--------
72
73
We follow some of the tutorial from
74
http://library.wolfram.com/conferences/devconf99/withoff/Basic1.html/.
75
76
For any of this to work you must buy and install the Mathematica
77
program, and it must be available as the command
78
``math`` in your PATH.
79
80
Syntax
81
~~~~~~
82
83
Now make 1 and add it to itself. The result is a Mathematica
84
object.
85
86
::
87
88
sage: m = mathematica
89
sage: a = m(1) + m(1); a # optional - mathematica
90
2
91
sage: a.parent() # optional - mathematica
92
Mathematica
93
sage: m('1+1') # optional - mathematica
94
2
95
sage: m(3)**m(50) # optional - mathematica
96
717897987691852588770249
97
98
The following is equivalent to ``Plus[2, 3]`` in
99
Mathematica::
100
101
sage: m = mathematica
102
sage: m(2).Plus(m(3)) # optional - mathematica
103
5
104
105
We can also compute `7(2+3)`.
106
107
::
108
109
sage: m(7).Times(m(2).Plus(m(3))) # optional - mathematica
110
35
111
sage: m('7(2+3)') # optional - mathematica
112
35
113
114
Some typical input
115
~~~~~~~~~~~~~~~~~~
116
117
We solve an equation and a system of two equations::
118
119
sage: eqn = mathematica('3x + 5 == 14') # optional - mathematica
120
sage: eqn # optional - mathematica
121
5 + 3*x == 14
122
sage: eqn.Solve('x') # optional - mathematica
123
{{x -> 3}}
124
sage: sys = mathematica('{x^2 - 3y == 3, 2x - y == 1}') # optional - mathematica
125
sage: print sys # optional - mathematica
126
2
127
{x - 3 y == 3, 2 x - y == 1}
128
sage: sys.Solve('{x, y}') # optional - mathematica
129
{{x -> 0, y -> -1}, {x -> 6, y -> 11}}
130
131
Assignments and definitions
132
~~~~~~~~~~~~~~~~~~~~~~~~~~~
133
134
If you assign the mathematica `5` to a variable `c`
135
in Sage, this does not affect the `c` in Mathematica.
136
137
::
138
139
sage: c = m(5) # optional - mathematica
140
sage: print m('b + c x') # optional - mathematica
141
b + c x
142
sage: print m('b') + c*m('x') # optional - mathematica
143
b + 5 x
144
145
The Sage interfaces changes Sage lists into Mathematica lists::
146
147
sage: m = mathematica
148
sage: eq1 = m('x^2 - 3y == 3') # optional - mathematica
149
sage: eq2 = m('2x - y == 1') # optional - mathematica
150
sage: v = m([eq1, eq2]); v # optional - mathematica
151
{x^2 - 3*y == 3, 2*x - y == 1}
152
sage: v.Solve(['x', 'y']) # optional - mathematica
153
{{x -> 0, y -> -1}, {x -> 6, y -> 11}}
154
155
Function definitions
156
~~~~~~~~~~~~~~~~~~~~
157
158
Define mathematica functions by simply sending the definition to
159
the interpreter.
160
161
::
162
163
sage: m = mathematica
164
sage: _ = mathematica('f[p_] = p^2'); # optional - mathematica
165
sage: m('f[9]') # optional - mathematica
166
81
167
168
Numerical Calculations
169
~~~~~~~~~~~~~~~~~~~~~~
170
171
We find the `x` such that `e^x - 3x = 0`.
172
173
::
174
175
sage: e = mathematica('Exp[x] - 3x == 0') # optional - mathematica
176
sage: e.FindRoot(['x', 2]) # optional - mathematica
177
{x -> 1.512134551657842}
178
179
Note that this agrees with what the PARI interpreter gp produces::
180
181
sage: gp('solve(x=1,2,exp(x)-3*x)')
182
1.512134551657842473896739678 # 32-bit
183
1.5121345516578424738967396780720387046 # 64-bit
184
185
Next we find the minimum of a polynomial using the two different
186
ways of accessing Mathematica::
187
188
sage: mathematica('FindMinimum[x^3 - 6x^2 + 11x - 5, {x,3}]') # optional - mathematica
189
{0.6150998205402516, {x -> 2.5773502699629733}}
190
sage: f = mathematica('x^3 - 6x^2 + 11x - 5') # optional - mathematica
191
sage: f.FindMinimum(['x', 3]) # optional - mathematica
192
{0.6150998205402516, {x -> 2.5773502699629733}}
193
194
Polynomial and Integer Factorization
195
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
196
197
We factor a polynomial of degree 200 over the integers.
198
199
::
200
201
sage: R.<x> = PolynomialRing(ZZ)
202
sage: f = (x**100+17*x+5)*(x**100-5*x+20)
203
sage: f
204
x^200 + 12*x^101 + 25*x^100 - 85*x^2 + 315*x + 100
205
sage: g = mathematica(str(f)) # optional - mathematica
206
sage: print g # optional - mathematica
207
2 100 101 200
208
100 + 315 x - 85 x + 25 x + 12 x + x
209
sage: g # optional - mathematica
210
100 + 315*x - 85*x^2 + 25*x^100 + 12*x^101 + x^200
211
sage: print g.Factor() # optional - mathematica
212
100 100
213
(20 - 5 x + x ) (5 + 17 x + x )
214
215
We can also factor a multivariate polynomial::
216
217
sage: f = mathematica('x^6 + (-y - 2)*x^5 + (y^3 + 2*y)*x^4 - y^4*x^3') # optional - mathematica
218
sage: print f.Factor() # optional - mathematica
219
3 2 3
220
x (x - y) (-2 x + x + y )
221
222
We factor an integer::
223
224
sage: n = mathematica(2434500) # optional - mathematica
225
sage: n.FactorInteger() # optional - mathematica
226
{{2, 2}, {3, 2}, {5, 3}, {541, 1}}
227
sage: n = mathematica(2434500) # optional - mathematica
228
sage: F = n.FactorInteger(); F # optional - mathematica
229
{{2, 2}, {3, 2}, {5, 3}, {541, 1}}
230
sage: F[1] # optional - mathematica
231
{2, 2}
232
sage: F[4] # optional - mathematica
233
{541, 1}
234
235
We can also load the ECM package and factoring using it::
236
237
sage: _ = mathematica.eval("<<NumberTheory`FactorIntegerECM`"); # optional - mathematica
238
sage: mathematica.FactorIntegerECM('932901*939321') # optional - mathematica
239
8396109
240
241
Long Input
242
----------
243
244
The Mathematica interface reads in even very long input (using
245
files) in a robust manner.
246
247
::
248
249
sage: t = '"%s"'%10^10000 # ten thousand character string.
250
sage: a = mathematica(t) # optional - mathematica
251
sage: a = mathematica.eval(t) # optional - mathematica
252
253
Loading and saving
254
------------------
255
256
Mathematica has an excellent ``InputForm`` function,
257
which makes saving and loading Mathematica objects possible. The
258
first examples test saving and loading to strings.
259
260
::
261
262
sage: x = mathematica(pi/2) # optional - mathematica
263
sage: print x # optional - mathematica
264
Pi
265
--
266
2
267
sage: loads(dumps(x)) == x # optional - mathematica
268
True
269
sage: n = x.N(50) # optional - mathematica
270
sage: print n # optional - mathematica
271
1.5707963267948966192313216916397514420985846996876
272
sage: loads(dumps(n)) == n # optional - mathematica
273
True
274
275
Complicated translations
276
------------------------
277
278
The ``mobj.sage()`` method tries to convert a Mathematica object to a Sage
279
object. In many cases, it will just work. In particular, it should be able to
280
convert expressions entirely consisting of:
281
282
- numbers, i.e. integers, floats, complex numbers;
283
- functions and named constants also present in Sage, where:
284
285
- Sage knows how to translate the function or constant's name from
286
Mathematica's, or
287
- the Sage name for the function or constant is trivially related to
288
Mathematica's;
289
290
- symbolic variables whose names don't pathologically overlap with
291
objects already defined in Sage.
292
293
This method will not work when Mathematica's output includes:
294
295
- strings;
296
- functions unknown to Sage;
297
- Mathematica functions with different parameters/parameter order to
298
the Sage equivalent.
299
300
If you want to convert more complicated Mathematica expressions, you can
301
instead call ``mobj._sage_()`` and supply a translation dictionary::
302
303
sage: m = mathematica('NewFn[x]') # optional - mathematica
304
sage: m._sage_(locals={'NewFn': sin}) # optional - mathematica
305
sin(x)
306
307
For more details, see the documentation for ``._sage_()``.
308
309
310
OTHER Examples::
311
312
sage: def math_bessel_K(nu,x):
313
... return mathematica(nu).BesselK(x).N(20)
314
...
315
sage: math_bessel_K(2,I) # optional - mathematica
316
0.180489972066962*I - 2.592886175491197 # 32-bit
317
-2.59288617549119697817 + 0.18048997206696202663*I # 64-bit
318
319
::
320
321
sage: slist = [[1, 2], 3., 4 + I]
322
sage: mlist = mathematica(slist); mlist # optional - mathematica
323
{{1, 2}, 3., 4 + I}
324
sage: slist2 = list(mlist); slist2 # optional - mathematica
325
[{1, 2}, 3., 4 + I]
326
sage: slist2[0] # optional - mathematica
327
{1, 2}
328
sage: slist2[0].parent() # optional - mathematica
329
Mathematica
330
sage: slist3 = mlist.sage(); slist3 # optional - mathematica
331
[[1, 2], 3.0, I + 4]
332
333
::
334
335
sage: mathematica('10.^80') # optional - mathematica
336
1.*^80
337
sage: mathematica('10.^80').sage() # optional - mathematica
338
1e+80
339
340
AUTHORS:
341
342
- William Stein (2005): first version
343
344
- Doug Cutrell (2006-03-01): Instructions for use under Cygwin/Windows.
345
346
- Felix Lawrence (2009-08-21): Added support for importing Mathematica lists
347
and floats with exponents.
348
"""
349
350
#*****************************************************************************
351
# Copyright (C) 2005 William Stein <[email protected]>
352
#
353
# Distributed under the terms of the GNU General Public License (GPL)
354
#
355
# This code is distributed in the hope that it will be useful,
356
# but WITHOUT ANY WARRANTY; without even the implied warranty of
357
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
358
# General Public License for more details.
359
#
360
# The full text of the GPL is available at:
361
#
362
# http://www.gnu.org/licenses/
363
#*****************************************************************************
364
365
import os
366
import re
367
368
from expect import (Expect, ExpectElement, ExpectFunction,
369
FunctionElement, AsciiArtString)
370
371
def clean_output(s):
372
if s is None:
373
return ''
374
i = s.find('Out[')
375
j = i + s[i:].find('=')
376
s = s[:i] + ' '*(j+1-i) + s[j+1:]
377
s = s.replace('\\\n','')
378
return s.strip('\n')
379
380
def _un_camel(name):
381
"""
382
Convert `CamelCase` to `camel_case`.
383
384
EXAMPLES::
385
386
sage: sage.interfaces.mathematica._un_camel('CamelCase')
387
'camel_case'
388
sage: sage.interfaces.mathematica._un_camel('EllipticE')
389
'elliptic_e'
390
sage: sage.interfaces.mathematica._un_camel('FindRoot')
391
'find_root'
392
sage: sage.interfaces.mathematica._un_camel('GCD')
393
'gcd'
394
"""
395
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
396
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
397
398
class Mathematica(Expect):
399
"""
400
Interface to the Mathematica interpreter.
401
"""
402
def __init__(self, maxread=100, script_subdirectory="", logfile=None, server=None, server_tmpdir=None):
403
Expect.__init__(self,
404
name = 'mathematica',
405
prompt = 'In[[0-9]+]:=',
406
command = "math",
407
maxread = maxread,
408
server = server,
409
server_tmpdir = server_tmpdir,
410
script_subdirectory = script_subdirectory,
411
verbose_start = False,
412
logfile=logfile,
413
eval_using_file_cutoff=50)
414
415
def _read_in_file_command(self, filename):
416
return '<<"%s"'%filename
417
418
def _keyboard_interrupt(self):
419
print "Interrupting %s..."%self
420
e = self._expect
421
e.sendline(chr(3)) # send ctrl-c
422
e.expect('Interrupt> ')
423
e.sendline("a") # a -- abort
424
e.expect(self._prompt)
425
return e.before
426
427
def _install_hints(self):
428
"""
429
Hints for installing mathematica on your computer.
430
431
AUTHORS:
432
433
- William Stein and Justin Walker (2006-02-12)
434
"""
435
return """
436
In order to use the Mathematica interface you need to have Mathematica
437
installed and have a script in your PATH called "math" that runs the
438
command-line version of Mathematica. Alternatively, you could use a
439
remote connection to a server running Mathematica -- for hints, type
440
print mathematica._install_hints_ssh()
441
442
443
(1) You might have to buy Mathematica (http://www.wolfram.com/).
444
445
(2) * LINUX: The math script comes standard with your Mathematica install.
446
447
* APPLE OS X:
448
(a) create a file called math (in your PATH):
449
#!/bin/sh
450
/Applications/Mathematica.app/Contents/MacOS/MathKernel $@
451
452
The path in the above script must be modified if you installed
453
Mathematica elsewhere or installed an old version of
454
Mathematica that has the version in the .app name.
455
456
(b) Make the file executable.
457
chmod +x math
458
459
* WINDOWS:
460
461
Install Mathematica for Linux into the VMware virtual machine (sorry,
462
that's the only way at present).
463
"""
464
465
## The following only works with Sage for Cygwin (not colinux).
466
## Note that Sage colinux is the preferred way to run Sage in Windows,
467
## and I do not know how to use Mathematica from colinux Sage (unless
468
## you install Mathematica-for-linux into the colinux machine, which
469
## is possible).
470
471
## Create a file named "math", which you place in the Sage root
472
## directory. The file contained a single line, which was the
473
## path to the mathematica math.exe file. In my case, this might be:
474
475
## C:/Program Files/Wolfram Research/Mathematica/4.0/math.exe
476
477
## The key points are
478
## 1) there is a file named "math.exe", and it will generally be
479
## located in a place analogous to the above (depending on where
480
## Mathematica has been installed). This file is used only for
481
## launching the kernel with a text-based interface.
482
## 2) a cygwin batch file must be created which executes this file,
483
## which means using forward slashes rather than back slashes,
484
## and probably surrounding everything in quotes
485
## 3) this cygwin batch file must be on the path for Sage (placing
486
## it in <SAGE_LOCAL>/bin/ is an easy way to ensure this).
487
488
def eval(self, code, strip=True, **kwds):
489
s = Expect.eval(self, code, **kwds)
490
if strip:
491
return AsciiArtString(clean_output(s))
492
else:
493
return AsciiArtString(s)
494
495
#def _keyboard_interrupt(self):
496
# print "Keyboard interrupt pressed; trying to recover."
497
# E = self.expect()
498
# E.sendline(chr(3))
499
# E.sendline('a')
500
# E.expect(':= ')
501
# raise KeyboardInterrupt, "Ctrl-c pressed while running Mathematica command"
502
503
504
def set(self, var, value):
505
"""
506
Set the variable var to the given value.
507
"""
508
cmd = '%s=%s;'%(var,value)
509
#out = self.eval(cmd)
510
out = self._eval_line(cmd, allow_use_file=True)
511
if len(out) > 8:
512
raise TypeError, "Error executing code in Mathematica\nCODE:\n\t%s\nMathematica ERROR:\n\t%s"%(cmd, out)
513
514
def get(self, var, ascii_art=False):
515
"""
516
Get the value of the variable var.
517
518
AUTHORS:
519
520
- William Stein
521
522
- Kiran Kedlaya (2006-02-04): suggested using InputForm
523
"""
524
if ascii_art:
525
return self.eval(var, strip=True)
526
else:
527
return self.eval('InputForm[%s, NumberMarks->False]'%var, strip=True)
528
529
#def clear(self, var):
530
# """
531
# Clear the variable named var.
532
# """
533
# self.eval('Clear[%s]'%var)
534
535
def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=False):
536
s = Expect._eval_line(self, line,
537
allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt)
538
return str(s).strip('\n')
539
540
def _function_call_string(self, function, args, kwds):
541
"""
542
Returns the string used to make function calls.
543
544
EXAMPLES::
545
546
sage: mathematica._function_call_string('Sin', ['x'], [])
547
'Sin[x]'
548
"""
549
return "%s[%s]"%(function, ",".join(args))
550
551
def _left_list_delim(self):
552
return "{"
553
554
def _right_list_delim(self):
555
return "}"
556
557
def _left_func_delim(self):
558
return "["
559
560
def _right_func_delim(self):
561
return "]"
562
563
###########################################
564
# System -- change directory, etc
565
###########################################
566
def chdir(self, dir):
567
"""
568
Change Mathematica's current working directory.
569
570
EXAMPLES::
571
572
sage: mathematica.chdir('/') # optional
573
sage: mathematica('Directory[]') # optional
574
"/"
575
"""
576
self.eval('SetDirectory["%s"]'%dir)
577
578
def _true_symbol(self):
579
return ' True'
580
581
def _false_symbol(self):
582
return ' False'
583
584
def _equality_symbol(self):
585
return '=='
586
587
def _assign_symbol(self):
588
return ":="
589
590
def _exponent_symbol(self):
591
"""
592
Returns the symbol used to denote the exponent of a number in
593
Mathematica.
594
595
EXAMPLES::
596
597
sage: mathematica._exponent_symbol() # optional - mathematica
598
'*^'
599
600
::
601
602
sage: bignum = mathematica('10.^80') # optional - mathematica
603
sage: repr(bignum) # optional - mathematica
604
'1.*^80'
605
sage: repr(bignum).replace(mathematica._exponent_symbol(), 'e').strip() # optional - mathematica
606
'1.e80'
607
"""
608
return "*^"
609
610
def _object_class(self):
611
return MathematicaElement
612
613
def console(self, readline=True):
614
mathematica_console(readline=readline)
615
616
def trait_names(self):
617
a = self.eval('Names["*"]')
618
return a.replace('$','').replace('\n \n>','').replace(',','').replace('}','').replace('{','').split()
619
620
621
def help(self, cmd):
622
return self.eval('? %s'%cmd)
623
624
def __getattr__(self, attrname):
625
if attrname[:1] == "_":
626
raise AttributeError
627
return MathematicaFunction(self, attrname)
628
629
class MathematicaElement(ExpectElement):
630
def __getitem__(self, n):
631
return self.parent().new('%s[[%s]]'%(self._name, n))
632
633
def __getattr__(self, attrname):
634
self._check_valid()
635
if attrname[:1] == "_":
636
raise AttributeError
637
return MathematicaFunctionElement(self, attrname)
638
639
def __float__(self):
640
P = self.parent()
641
# TODO: Is 16 enough?
642
return float(P.eval('N[%s,16]'%self.name()))
643
644
def _reduce(self):
645
return self.parent().eval('InputForm[%s]'%self.name())
646
647
def __reduce__(self):
648
return reduce_load, (self._reduce(), )
649
650
def _latex_(self):
651
z = self.parent().eval('TeXForm[%s]'%self.name())
652
i = z.find('=')
653
return z[i+1:].strip()
654
655
def __repr__(self):
656
P = self._check_valid()
657
return P.get(self._name, ascii_art=False).strip()
658
659
def _sage_(self, locals={}):
660
r"""
661
Attempt to return a Sage version of this object.
662
663
This method works successfully when Mathematica returns a result
664
or list of results that consist only of:
665
- numbers, i.e. integers, floats, complex numbers;
666
- functions and named constants also present in Sage, where:
667
- Sage knows how to translate the function or constant's name
668
from Mathematica's naming scheme, or
669
- you provide a translation dictionary `locals`, or
670
- the Sage name for the function or constant is simply the
671
Mathematica name in lower case;
672
- symbolic variables whose names don't pathologically overlap with
673
objects already defined in Sage.
674
675
This method will not work when Mathematica's output includes:
676
- strings;
677
- functions unknown to Sage that are not specified in `locals`;
678
- Mathematica functions with different parameters/parameter order to
679
the Sage equivalent. In this case, define a function to do the
680
parameter conversion, and pass it in via the locals dictionary.
681
682
EXAMPLES:
683
684
Mathematica lists of numbers/constants become Sage lists of
685
numbers/constants::
686
687
sage: m = mathematica('{{1., 4}, Pi, 3.2e100, I}') # optional - mathematica
688
sage: s = m.sage(); s # optional - mathematica
689
[[1.0, 4], pi, 3.2*e100, I]
690
sage: s[1].n() # optional - mathematica
691
3.14159265358979
692
sage: s[3]^2 # optional - mathematica
693
-1
694
695
::
696
697
sage: m = mathematica('x^2 + 5*y') # optional - mathematica
698
sage: m.sage() # optional - mathematica
699
x^2 + 5*y
700
701
::
702
703
sage: m = mathematica('Sin[Sqrt[1-x^2]] * (1 - Cos[1/x])^2') # optional - mathematica
704
sage: m.sage() # optional - mathematica
705
(cos(1/x) - 1)^2*sin(sqrt(-x^2 + 1))
706
707
::
708
709
sage: m = mathematica('NewFn[x]') # optional - mathematica
710
sage: m._sage_(locals={'NewFn': sin}) # optional - mathematica
711
sin(x)
712
713
::
714
715
sage: var('bla') # optional - mathematica
716
bla
717
sage: m = mathematica('bla^2') # optional - mathematica
718
sage: bla^2 - m.sage() # optional - mathematica
719
0
720
721
::
722
723
sage: m = mathematica('bla^2') # optional - mathematica
724
sage: mb = m.sage() # optional - mathematica
725
sage: var('bla') # optional - mathematica
726
bla
727
sage: bla^2 - mb # optional - mathematica
728
0
729
730
731
AUTHORS:
732
733
- Felix Lawrence (2010-11-03): Major rewrite to use ._sage_repr() and
734
sage.calculus.calculus.symbolic_expression_from_string() for greater
735
compatibility, while still supporting conversion of symbolic
736
expressions.
737
"""
738
from sage.symbolic.pynac import symbol_table
739
from sage.symbolic.constants import constants_name_table as constants
740
from sage.calculus.calculus import symbolic_expression_from_string
741
from sage.calculus.calculus import _find_func as find_func
742
743
# Get Mathematica's output and perform preliminary formatting
744
res = self._sage_repr()
745
if '"' in res:
746
raise NotImplementedError, "String conversion from Mathematica \
747
does not work. Mathematica's output was: %s" % res
748
749
# Find all the mathematica functions, constants and symbolic variables
750
# present in `res`. Convert MMA functions and constants to their
751
# Sage equivalents (if possible), using `locals` and
752
# `sage.symbolic.pynac.symbol_table['mathematica']` as translation
753
# dictionaries. If a MMA function or constant is not either
754
# dictionary, then we use a variety of tactics listed in `autotrans`.
755
# If a MMA variable is not in any dictionary, then create an
756
# identically named Sage equivalent.
757
758
# Merge the user-specified locals dictionary and the symbol_table
759
# (locals takes priority)
760
lsymbols = symbol_table['mathematica'].copy()
761
lsymbols.update(locals)
762
763
# Strategies for translating unknown functions/constants:
764
autotrans = [ str.lower, # Try it in lower case
765
_un_camel, # Convert `CamelCase` to `camel_case`
766
lambda x: x # Try the original name
767
]
768
769
# Find the MMA funcs/vars/constants - they start with a letter.
770
# Exclude exponents (e.g. 'e8' from 4.e8)
771
p = re.compile('(?<!\.)[a-zA-Z]\w*')
772
for m in p.finditer(res):
773
# If the function, variable or constant is already in the
774
# translation dictionary, then just move on.
775
if m.group() in lsymbols:
776
pass
777
# Now try to translate all other functions -- try each strategy
778
# in `autotrans` and check if the function exists in Sage
779
elif m.end() < len(res) and res[m.end()] == '(':
780
for t in autotrans:
781
f = find_func(t(m.group()), create_when_missing = False)
782
if f != None:
783
lsymbols[m.group()] = f
784
break
785
else:
786
raise NotImplementedError, "Don't know a Sage equivalent \
787
for Mathematica function '%s'. Please specify one \
788
manually using the 'locals' dictionary" % m.group()
789
# Check if Sage has an equivalent constant
790
else:
791
for t in autotrans:
792
if t(m.group()) in constants:
793
lsymbols[m.group()] = constants[t(m.group())]
794
break
795
# If Sage has never heard of the variable, then
796
# symbolic_expression_from_string will automatically create it
797
try:
798
return symbolic_expression_from_string(res, lsymbols,
799
accept_sequence=True)
800
except Exception:
801
raise NotImplementedError, "Unable to parse Mathematica \
802
output: %s" % res
803
804
def __str__(self):
805
P = self._check_valid()
806
return P.get(self._name, ascii_art=True)
807
808
def __len__(self):
809
"""
810
Return the object's length, evaluated by mathematica.
811
812
EXAMPLES::
813
814
sage: len(mathematica([1,1.,2])) # optional - mathematica
815
3
816
817
AUTHORS:
818
- Felix Lawrence (2009-08-21)
819
"""
820
return self.Length()
821
822
def show(self, filename=None, ImageSize=600):
823
r"""
824
Show a mathematica expression or plot in the Sage notebook.
825
826
EXAMPLES::
827
828
sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica
829
sage: show(P) # optional - mathematica
830
sage: P.show(ImageSize=800) # optional - mathematica
831
sage: Q = mathematica('Sin[x Cos[y]]/Sqrt[1-x^2]') # optional - mathematica
832
sage: show(Q) # optional - mathematica
833
<html><div class="math">\frac{\sin (x \cos (y))}{\sqrt{1-x^2}}</div></html>
834
"""
835
P = self._check_valid()
836
if P.eval('InputForm[%s]' % self.name()).strip().startswith('Graphics['):
837
if filename is None:
838
from sage.misc.temporary_file import graphics_filename
839
filename = graphics_filename()
840
orig_dir = P.eval('Directory[]').strip()
841
P.chdir(os.path.abspath("."))
842
s = 'Export["%s", %s, ImageSize->%s]'%(filename, self.name(), ImageSize)
843
P.eval(s)
844
P.chdir(orig_dir)
845
else:
846
print '<html><div class="math">%s</div></html>' % self._latex_()
847
848
def str(self):
849
return str(self)
850
851
def __cmp__(self, other):
852
#if not (isinstance(other, ExpectElement) and other.parent() is self.parent()):
853
# return coerce.cmp(self, other)
854
P = self.parent()
855
if P.eval("%s < %s"%(self.name(), other.name())).strip() == 'True':
856
return -1
857
elif P.eval("%s > %s"%(self.name(), other.name())).strip() == 'True':
858
return 1
859
elif P.eval("%s == %s"%(self.name(), other.name())).strip() == 'True':
860
return 0
861
else:
862
return -1 # everything is supposed to be comparable in Python, so we define
863
# the comparison thus when no comparable in interfaced system.
864
865
def N(self, *args):
866
"""
867
EXAMPLES::
868
869
sage: mathematica('Pi').N(10) # optional -- mathematica
870
3.1415926536
871
sage: mathematica('Pi').N(50) # optional -- mathematica
872
3.14159265358979323846264338327950288419716939937511
873
"""
874
# The base class way up the hierarchy defines an "N" (modeled
875
# after Mathematica's!) which overwrites the Mathematica one,
876
# and doesn't work at all. We restore it here.
877
return self.parent().N(self, *args)
878
879
880
class MathematicaFunction(ExpectFunction):
881
def _sage_doc_(self):
882
M = self._parent
883
return M.help(self._name)
884
885
886
class MathematicaFunctionElement(FunctionElement):
887
def _sage_doc_(self):
888
M = self._obj.parent()
889
return M.help(self._name)
890
891
892
# An instance
893
mathematica = Mathematica(script_subdirectory='user')
894
895
def reduce_load(X):
896
return mathematica(X)
897
898
# Cleverly run Mathematica with the benefit of readline, which
899
# is something the usual commercial mathematica doesn't provide!
900
# See
901
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/363500
902
903
import os, sys
904
def mathematica_console(readline=True):
905
if not readline:
906
os.system('math')
907
return
908
f1 = os.popen('math ', 'w')
909
f1.flush()
910
try:
911
while True:
912
sys.stdout.write('')
913
try:
914
line = raw_input(' ')
915
f1.writelines(line+'\n')
916
f1.flush()
917
except KeyboardInterrupt:
918
f1.close()
919
break
920
except EOFError:
921
pass
922
sys.stdout.write('\n')
923
924
#def mathematica_console():
925
# os.system('mathematica')
926
927
928
929