Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/interfaces/mathematica.py
4036 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
from sage.misc.misc import graphics_filename
372
373
def clean_output(s):
374
if s is None:
375
return ''
376
i = s.find('Out[')
377
j = i + s[i:].find('=')
378
s = s[:i] + ' '*(j+1-i) + s[j+1:]
379
s = s.replace('\\\n','')
380
return s.strip('\n')
381
382
def _un_camel(name):
383
"""
384
Convert `CamelCase` to `camel_case`.
385
386
EXAMPLES::
387
388
sage: sage.interfaces.mathematica._un_camel('CamelCase')
389
'camel_case'
390
sage: sage.interfaces.mathematica._un_camel('EllipticE')
391
'elliptic_e'
392
sage: sage.interfaces.mathematica._un_camel('FindRoot')
393
'find_root'
394
sage: sage.interfaces.mathematica._un_camel('GCD')
395
'gcd'
396
"""
397
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
398
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
399
400
class Mathematica(Expect):
401
"""
402
Interface to the Mathematica interpreter.
403
"""
404
def __init__(self, maxread=100, script_subdirectory="", logfile=None, server=None, server_tmpdir=None):
405
Expect.__init__(self,
406
name = 'mathematica',
407
prompt = 'In[[0-9]+]:=',
408
command = "math",
409
maxread = maxread,
410
server = server,
411
server_tmpdir = server_tmpdir,
412
script_subdirectory = script_subdirectory,
413
verbose_start = False,
414
logfile=logfile,
415
eval_using_file_cutoff=50)
416
417
def _read_in_file_command(self, filename):
418
return '<<"%s"'%filename
419
420
def _keyboard_interrupt(self):
421
print "Interrupting %s..."%self
422
e = self._expect
423
e.sendline(chr(3)) # send ctrl-c
424
e.expect('Interrupt> ')
425
e.sendline("a") # a -- abort
426
e.expect(self._prompt)
427
return e.before
428
429
def _install_hints(self):
430
"""
431
Hints for installing mathematica on your computer.
432
433
AUTHORS:
434
435
- William Stein and Justin Walker (2006-02-12)
436
"""
437
return """
438
In order to use the Mathematica interface you need to have Mathematica
439
installed and have a script in your PATH called "math" that runs the
440
command-line version of Mathematica. Alternatively, you could use a
441
remote connection to a server running Mathematica -- for hints, type
442
print mathematica._install_hints_ssh()
443
444
445
(1) You might have to buy Mathematica (http://www.wolfram.com/).
446
447
(2) * LINUX: The math script comes standard with your Mathematica install.
448
449
* APPLE OS X:
450
(a) create a file called math (in your PATH):
451
#!/bin/sh
452
/Applications/Mathematica.app/Contents/MacOS/MathKernel $@
453
454
The path in the above script must be modified if you installed
455
Mathematica elsewhere or installed an old version of
456
Mathematica that has the version in the .app name.
457
458
(b) Make the file executable.
459
chmod +x math
460
461
* WINDOWS:
462
463
Install Mathematica for Linux into the VMware virtual machine (sorry,
464
that's the only way at present).
465
"""
466
467
## The following only works with Sage for Cygwin (not colinux).
468
## Note that Sage colinux is the preferred way to run Sage in Windows,
469
## and I do not know how to use Mathematica from colinux Sage (unless
470
## you install Mathematica-for-linux into the colinux machine, which
471
## is possible).
472
473
## Create a file named "math", which you place in the Sage root
474
## directory. The file contained a single line, which was the
475
## path to the mathematica math.exe file. In my case, this might be:
476
477
## C:/Program Files/Wolfram Research/Mathematica/4.0/math.exe
478
479
## The key points are
480
## 1) there is a file named "math.exe", and it will generally be
481
## located in a place analogous to the above (depending on where
482
## Mathematica has been installed). This file is used only for
483
## launching the kernel with a text-based interface.
484
## 2) a cygwin batch file must be created which executes this file,
485
## which means using forward slashes rather than back slashes,
486
## and probably surrounding everything in quotes
487
## 3) this cygwin batch file must be on the path for Sage (placing
488
## it in <SAGE_ROOT>/local/bin/ is an easy way to ensure this).
489
490
def eval(self, code, strip=True, **kwds):
491
s = Expect.eval(self, code, **kwds)
492
if strip:
493
return AsciiArtString(clean_output(s))
494
else:
495
return AsciiArtString(s)
496
497
#def _keyboard_interrupt(self):
498
# print "Keyboard interrupt pressed; trying to recover."
499
# E = self.expect()
500
# E.sendline(chr(3))
501
# E.sendline('a')
502
# E.expect(':= ')
503
# raise KeyboardInterrupt, "Ctrl-c pressed while running Mathematica command"
504
505
506
def set(self, var, value):
507
"""
508
Set the variable var to the given value.
509
"""
510
cmd = '%s=%s;'%(var,value)
511
#out = self.eval(cmd)
512
out = self._eval_line(cmd, allow_use_file=True)
513
if len(out) > 8:
514
raise TypeError, "Error executing code in Mathematica\nCODE:\n\t%s\nMathematica ERROR:\n\t%s"%(cmd, out)
515
516
def get(self, var, ascii_art=False):
517
"""
518
Get the value of the variable var.
519
520
AUTHORS:
521
522
- William Stein
523
524
- Kiran Kedlaya (2006-02-04): suggested using InputForm
525
"""
526
if ascii_art:
527
return self.eval(var, strip=True)
528
else:
529
return self.eval('InputForm[%s, NumberMarks->False]'%var, strip=True)
530
531
#def clear(self, var):
532
# """
533
# Clear the variable named var.
534
# """
535
# self.eval('Clear[%s]'%var)
536
537
def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=False):
538
s = Expect._eval_line(self, line,
539
allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt)
540
return str(s).strip('\n')
541
542
def _function_call_string(self, function, args, kwds):
543
"""
544
Returns the string used to make function calls.
545
546
EXAMPLES::
547
548
sage: mathematica._function_call_string('Sin', ['x'], [])
549
'Sin[x]'
550
"""
551
return "%s[%s]"%(function, ",".join(args))
552
553
def _left_list_delim(self):
554
return "{"
555
556
def _right_list_delim(self):
557
return "}"
558
559
def _left_func_delim(self):
560
return "["
561
562
def _right_func_delim(self):
563
return "]"
564
565
###########################################
566
# System -- change directory, etc
567
###########################################
568
def chdir(self, dir):
569
"""
570
Change Mathematica's current working directory.
571
572
EXAMPLES::
573
574
sage: mathematica.chdir('/') # optional
575
sage: mathematica('Directory[]') # optional
576
"/"
577
"""
578
self.eval('SetDirectory["%s"]'%dir)
579
580
def _true_symbol(self):
581
return ' True'
582
583
def _false_symbol(self):
584
return ' False'
585
586
def _equality_symbol(self):
587
return '=='
588
589
def _assign_symbol(self):
590
return ":="
591
592
def _exponent_symbol(self):
593
"""
594
Returns the symbol used to denote the exponent of a number in
595
Mathematica.
596
597
EXAMPLES::
598
599
sage: mathematica._exponent_symbol() # optional - mathematica
600
'*^'
601
602
::
603
604
sage: bignum = mathematica('10.^80') # optional - mathematica
605
sage: repr(bignum) # optional - mathematica
606
'1.*^80'
607
sage: repr(bignum).replace(mathematica._exponent_symbol(), 'e').strip() # optional - mathematica
608
'1.e80'
609
"""
610
return "*^"
611
612
def _object_class(self):
613
return MathematicaElement
614
615
def console(self, readline=True):
616
mathematica_console(readline=readline)
617
618
def trait_names(self):
619
a = self.eval('Names["*"]')
620
return a.replace('$','').replace('\n \n>','').replace(',','').replace('}','').replace('{','').split()
621
622
623
def help(self, cmd):
624
return self.eval('? %s'%cmd)
625
626
def __getattr__(self, attrname):
627
if attrname[:1] == "_":
628
raise AttributeError
629
return MathematicaFunction(self, attrname)
630
631
class MathematicaElement(ExpectElement):
632
def __getitem__(self, n):
633
return self.parent().new('%s[[%s]]'%(self._name, n))
634
635
def __getattr__(self, attrname):
636
self._check_valid()
637
if attrname[:1] == "_":
638
raise AttributeError
639
return MathematicaFunctionElement(self, attrname)
640
641
def __float__(self):
642
P = self.parent()
643
# TODO: Is 16 enough?
644
return float(P.eval('N[%s,16]'%self.name()))
645
646
def _reduce(self):
647
return self.parent().eval('InputForm[%s]'%self.name())
648
649
def __reduce__(self):
650
return reduce_load, (self._reduce(), )
651
652
def _latex_(self):
653
z = self.parent().eval('TeXForm[%s]'%self.name())
654
i = z.find('=')
655
return z[i+1:].strip()
656
657
def __repr__(self):
658
P = self._check_valid()
659
return P.get(self._name, ascii_art=False).strip()
660
661
def _sage_(self, locals={}):
662
r"""
663
Attempt to return a Sage version of this object.
664
665
This method works successfully when Mathematica returns a result
666
or list of results that consist only of:
667
- numbers, i.e. integers, floats, complex numbers;
668
- functions and named constants also present in Sage, where:
669
- Sage knows how to translate the function or constant's name
670
from Mathematica's naming scheme, or
671
- you provide a translation dictionary `locals`, or
672
- the Sage name for the function or constant is simply the
673
Mathematica name in lower case;
674
- symbolic variables whose names don't pathologically overlap with
675
objects already defined in Sage.
676
677
This method will not work when Mathematica's output includes:
678
- strings;
679
- functions unknown to Sage that are not specified in `locals`;
680
- Mathematica functions with different parameters/parameter order to
681
the Sage equivalent. In this case, define a function to do the
682
parameter conversion, and pass it in via the locals dictionary.
683
684
EXAMPLES:
685
686
Mathematica lists of numbers/constants become Sage lists of
687
numbers/constants::
688
689
sage: m = mathematica('{{1., 4}, Pi, 3.2e100, I}') # optional - mathematica
690
sage: s = m.sage(); s # optional - mathematica
691
[[1.0, 4], pi, 3.2*e100, I]
692
sage: s[1].n() # optional - mathematica
693
3.14159265358979
694
sage: s[3]^2 # optional - mathematica
695
-1
696
697
::
698
699
sage: m = mathematica('x^2 + 5*y') # optional - mathematica
700
sage: m.sage() # optional - mathematica
701
x^2 + 5*y
702
703
::
704
705
sage: m = mathematica('Sin[Sqrt[1-x^2]] * (1 - Cos[1/x])^2') # optional - mathematica
706
sage: m.sage() # optional - mathematica
707
(cos(1/x) - 1)^2*sin(sqrt(-x^2 + 1))
708
709
::
710
711
sage: m = mathematica('NewFn[x]') # optional - mathematica
712
sage: m._sage_(locals={'NewFn': sin}) # optional - mathematica
713
sin(x)
714
715
::
716
717
sage: var('bla') # optional - mathematica
718
bla
719
sage: m = mathematica('bla^2') # optional - mathematica
720
sage: bla^2 - m.sage() # optional - mathematica
721
0
722
723
::
724
725
sage: m = mathematica('bla^2') # optional - mathematica
726
sage: mb = m.sage() # optional - mathematica
727
sage: var('bla') # optional - mathematica
728
bla
729
sage: bla^2 - mb # optional - mathematica
730
0
731
732
733
AUTHORS:
734
735
- Felix Lawrence (2010-11-03): Major rewrite to use ._sage_repr() and
736
sage.calculus.calculus.symbolic_expression_from_string() for greater
737
compatibility, while still supporting conversion of symbolic
738
expressions.
739
"""
740
from sage.symbolic.pynac import symbol_table
741
from sage.symbolic.constants import constants_name_table as constants
742
from sage.calculus.calculus import symbolic_expression_from_string
743
from sage.calculus.calculus import _find_func as find_func
744
745
# Get Mathematica's output and perform preliminary formatting
746
res = self._sage_repr()
747
if '"' in res:
748
raise NotImplementedError, "String conversion from Mathematica \
749
does not work. Mathematica's output was: %s" % res
750
751
# Find all the mathematica functions, constants and symbolic variables
752
# present in `res`. Convert MMA functions and constants to their
753
# Sage equivalents (if possible), using `locals` and
754
# `sage.symbolic.pynac.symbol_table['mathematica']` as translation
755
# dictionaries. If a MMA function or constant is not either
756
# dictionary, then we use a variety of tactics listed in `autotrans`.
757
# If a MMA variable is not in any dictionary, then create an
758
# identically named Sage equivalent.
759
760
# Merge the user-specified locals dictionary and the symbol_table
761
# (locals takes priority)
762
lsymbols = symbol_table['mathematica'].copy()
763
lsymbols.update(locals)
764
765
# Strategies for translating unknown functions/constants:
766
autotrans = [ str.lower, # Try it in lower case
767
_un_camel, # Convert `CamelCase` to `camel_case`
768
lambda x: x # Try the original name
769
]
770
771
# Find the MMA funcs/vars/constants - they start with a letter.
772
# Exclude exponents (e.g. 'e8' from 4.e8)
773
p = re.compile('(?<!\.)[a-zA-Z]\w*')
774
for m in p.finditer(res):
775
# If the function, variable or constant is already in the
776
# translation dictionary, then just move on.
777
if m.group() in lsymbols:
778
pass
779
# Now try to translate all other functions -- try each strategy
780
# in `autotrans` and check if the function exists in Sage
781
elif m.end() < len(res) and res[m.end()] == '(':
782
for t in autotrans:
783
f = find_func(t(m.group()), create_when_missing = False)
784
if f != None:
785
lsymbols[m.group()] = f
786
break
787
else:
788
raise NotImplementedError, "Don't know a Sage equivalent \
789
for Mathematica function '%s'. Please specify one \
790
manually using the 'locals' dictionary" % m.group()
791
# Check if Sage has an equivalent constant
792
else:
793
for t in autotrans:
794
if t(m.group()) in constants:
795
lsymbols[m.group()] = constants[t(m.group())]
796
break
797
# If Sage has never heard of the variable, then
798
# symbolic_expression_from_string will automatically create it
799
try:
800
return symbolic_expression_from_string(res, lsymbols,
801
accept_sequence=True)
802
except:
803
raise NotImplementedError, "Unable to parse Mathematica \
804
output: %s" % res
805
806
def __str__(self):
807
P = self._check_valid()
808
return P.get(self._name, ascii_art=True)
809
810
def __len__(self):
811
"""
812
Return the object's length, evaluated by mathematica.
813
814
EXAMPLES::
815
816
sage: len(mathematica([1,1.,2])) # optional - mathematica
817
3
818
819
AUTHORS:
820
- Felix Lawrence (2009-08-21)
821
"""
822
return self.Length()
823
824
def show(self, filename=None, ImageSize=600):
825
r"""
826
Show a mathematica expression or plot in the Sage notebook.
827
828
EXAMPLES::
829
830
sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica
831
sage: show(P) # optional - mathematica
832
sage: P.show(ImageSize=800) # optional - mathematica
833
sage: Q = mathematica('Sin[x Cos[y]]/Sqrt[1-x^2]') # optional - mathematica
834
sage: show(Q) # optional - mathematica
835
<html><div class="math">\frac{\sin (x \cos (y))}{\sqrt{1-x^2}}</div></html>
836
"""
837
P = self._check_valid()
838
if P.eval('InputForm[%s]' % self.name()).strip().startswith('Graphics['):
839
if filename is None:
840
filename = graphics_filename()
841
orig_dir = P.eval('Directory[]').strip()
842
P.chdir(os.path.abspath("."))
843
s = 'Export["%s", %s, ImageSize->%s]'%(filename, self.name(), ImageSize)
844
P.eval(s)
845
P.chdir(orig_dir)
846
else:
847
print '<html><div class="math">%s</div></html>' % self._latex_()
848
849
def str(self):
850
return str(self)
851
852
def __cmp__(self, other):
853
#if not (isinstance(other, ExpectElement) and other.parent() is self.parent()):
854
# return coerce.cmp(self, other)
855
P = self.parent()
856
if P.eval("%s < %s"%(self.name(), other.name())).strip() == 'True':
857
return -1
858
elif P.eval("%s > %s"%(self.name(), other.name())).strip() == 'True':
859
return 1
860
elif P.eval("%s == %s"%(self.name(), other.name())).strip() == 'True':
861
return 0
862
else:
863
return -1 # everything is supposed to be comparable in Python, so we define
864
# the comparison thus when no comparable in interfaced system.
865
866
def N(self, *args):
867
"""
868
EXAMPLES::
869
870
sage: mathematica('Pi').N(10) # optional -- mathematica
871
3.1415926536
872
sage: mathematica('Pi').N(50) # optional -- mathematica
873
3.14159265358979323846264338327950288419716939937511
874
"""
875
# The base class way up the hierarchy defines an "N" (modeled
876
# after Mathematica's!) which overwrites the Mathematica one,
877
# and doesn't work at all. We restore it here.
878
return self.parent().N(self, *args)
879
880
881
class MathematicaFunction(ExpectFunction):
882
def _sage_doc_(self):
883
M = self._parent
884
return M.help(self._name)
885
886
887
class MathematicaFunctionElement(FunctionElement):
888
def _sage_doc_(self):
889
M = self._obj.parent()
890
return M.help(self._name)
891
892
893
# An instance
894
mathematica = Mathematica(script_subdirectory='user')
895
896
def reduce_load(X):
897
return mathematica(X)
898
899
# Cleverly run Mathematica with the benefit of readline, which
900
# is something the usual commercial mathematica doesn't provide!
901
# See
902
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/363500
903
904
import os, sys
905
def mathematica_console(readline=True):
906
if not readline:
907
os.system('math')
908
return
909
f1 = os.popen('math ', 'w')
910
f1.flush()
911
try:
912
while True:
913
sys.stdout.write('')
914
try:
915
line = raw_input(' ')
916
f1.writelines(line+'\n')
917
f1.flush()
918
except KeyboardInterrupt:
919
f1.close()
920
break
921
except EOFError:
922
pass
923
sys.stdout.write('\n')
924
925
#def mathematica_console():
926
# os.system('mathematica')
927
928
929
930