Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Interface to Mathematica
The Mathematica interface will only work if Mathematica is installed on your computer with a command line interface that runs when you give the ``math`` command. The interface lets you send certain Sage objects to Mathematica, run Mathematica functions, import certain Mathematica expressions to Sage, or any combination of the above.
To send a Sage object ``sobj`` to Mathematica, call ``mathematica(sobj)``. This exports the Sage object to Mathematica and returns a new Sage object wrapping the Mathematica expression/variable, so that you can use the Mathematica variable from within Sage. You can then call Mathematica functions on the new object; for example::
sage: mobj = mathematica(x^2-1) # optional - mathematica sage: mobj.Factor() # optional - mathematica (-1 + x)*(1 + x)
In the above example the factorization is done using Mathematica's ``Factor[]`` function.
To see Mathematica's output you can simply print the Mathematica wrapper object. However if you want to import Mathematica's output back to Sage, call the Mathematica wrapper object's ``sage()`` method. This method returns a native Sage object::
sage: mobj = mathematica(x^2-1) # optional - mathematica sage: mobj2 = mobj.Factor(); mobj2 # optional - mathematica (-1 + x)*(1 + x) sage: mobj2.parent() # optional - mathematica Mathematica sage: sobj = mobj2.sage(); sobj # optional - mathematica (x + 1)*(x - 1) sage: sobj.parent() # optional - mathematica Symbolic Ring
If you want to run a Mathematica function and don't already have the input in the form of a Sage object, then it might be simpler to input a string to ``mathematica(expr)``. This string will be evaluated as if you had typed it into Mathematica::
sage: mathematica('Factor[x^2-1]') # optional - mathematica (-1 + x)*(1 + x) sage: mathematica('Range[3]') # optional - mathematica {1, 2, 3}
If you don't want Sage to go to the trouble of creating a wrapper for the Mathematica expression, then you can call ``mathematica.eval(expr)``, which returns the result as a Mathematica AsciiArtString formatted string. If you want the result to be a string formatted like Mathematica's InputForm, call ``repr(mobj)`` on the wrapper object ``mobj``. If you want a string formatted in Sage style, call ``mobj._sage_repr()``::
sage: mathematica.eval('x^2 - 1') # optional - mathematica 2 -1 + x sage: repr(mathematica('Range[3]')) # optional - mathematica '{1, 2, 3}' sage: mathematica('Range[3]')._sage_repr() # optional - mathematica '[1, 2, 3]'
Finally, if you just want to use a Mathematica command line from within Sage, the function ``mathematica_console()`` dumps you into an interactive command-line Mathematica session. This is an enhanced version of the usual Mathematica command-line, in that it provides readline editing and history (the usual one doesn't!)
Tutorial --------
We follow some of the tutorial from http://library.wolfram.com/conferences/devconf99/withoff/Basic1.html/.
For any of this to work you must buy and install the Mathematica program, and it must be available as the command ``math`` in your PATH.
Syntax ~~~~~~
Now make 1 and add it to itself. The result is a Mathematica object.
::
sage: m = mathematica sage: a = m(1) + m(1); a # optional - mathematica 2 sage: a.parent() # optional - mathematica Mathematica sage: m('1+1') # optional - mathematica 2 sage: m(3)**m(50) # optional - mathematica 717897987691852588770249
The following is equivalent to ``Plus[2, 3]`` in Mathematica::
sage: m = mathematica sage: m(2).Plus(m(3)) # optional - mathematica 5
We can also compute `7(2+3)`.
::
sage: m(7).Times(m(2).Plus(m(3))) # optional - mathematica 35 sage: m('7(2+3)') # optional - mathematica 35
Some typical input ~~~~~~~~~~~~~~~~~~
We solve an equation and a system of two equations::
sage: eqn = mathematica('3x + 5 == 14') # optional - mathematica sage: eqn # optional - mathematica 5 + 3*x == 14 sage: eqn.Solve('x') # optional - mathematica {{x -> 3}} sage: sys = mathematica('{x^2 - 3y == 3, 2x - y == 1}') # optional - mathematica sage: print(sys) # optional - mathematica 2 {x - 3 y == 3, 2 x - y == 1} sage: sys.Solve('{x, y}') # optional - mathematica {{x -> 0, y -> -1}, {x -> 6, y -> 11}}
Assignments and definitions ~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you assign the mathematica `5` to a variable `c` in Sage, this does not affect the `c` in Mathematica.
::
sage: c = m(5) # optional - mathematica sage: print(m('b + c x')) # optional - mathematica b + c x sage: print(m('b') + c*m('x')) # optional - mathematica b + 5 x
The Sage interfaces changes Sage lists into Mathematica lists::
sage: m = mathematica sage: eq1 = m('x^2 - 3y == 3') # optional - mathematica sage: eq2 = m('2x - y == 1') # optional - mathematica sage: v = m([eq1, eq2]); v # optional - mathematica {x^2 - 3*y == 3, 2*x - y == 1} sage: v.Solve(['x', 'y']) # optional - mathematica {{x -> 0, y -> -1}, {x -> 6, y -> 11}}
Function definitions ~~~~~~~~~~~~~~~~~~~~
Define mathematica functions by simply sending the definition to the interpreter.
::
sage: m = mathematica sage: _ = mathematica('f[p_] = p^2'); # optional - mathematica sage: m('f[9]') # optional - mathematica 81
Numerical Calculations ~~~~~~~~~~~~~~~~~~~~~~
We find the `x` such that `e^x - 3x = 0`.
::
sage: e = mathematica('Exp[x] - 3x == 0') # optional - mathematica sage: e.FindRoot(['x', 2]) # optional - mathematica {x -> 1.512134551657842}
Note that this agrees with what the PARI interpreter gp produces::
sage: gp('solve(x=1,2,exp(x)-3*x)') 1.512134551657842473896739678 # 32-bit 1.5121345516578424738967396780720387046 # 64-bit
Next we find the minimum of a polynomial using the two different ways of accessing Mathematica::
sage: mathematica('FindMinimum[x^3 - 6x^2 + 11x - 5, {x,3}]') # optional - mathematica {0.6150998205402516, {x -> 2.5773502699629733}} sage: f = mathematica('x^3 - 6x^2 + 11x - 5') # optional - mathematica sage: f.FindMinimum(['x', 3]) # optional - mathematica {0.6150998205402516, {x -> 2.5773502699629733}}
Polynomial and Integer Factorization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We factor a polynomial of degree 200 over the integers.
::
sage: R.<x> = PolynomialRing(ZZ) sage: f = (x**100+17*x+5)*(x**100-5*x+20) sage: f x^200 + 12*x^101 + 25*x^100 - 85*x^2 + 315*x + 100 sage: g = mathematica(str(f)) # optional - mathematica sage: print(g) # optional - mathematica 2 100 101 200 100 + 315 x - 85 x + 25 x + 12 x + x sage: g # optional - mathematica 100 + 315*x - 85*x^2 + 25*x^100 + 12*x^101 + x^200 sage: print(g.Factor()) # optional - mathematica 100 100 (20 - 5 x + x ) (5 + 17 x + x )
We can also factor a multivariate polynomial::
sage: f = mathematica('x^6 + (-y - 2)*x^5 + (y^3 + 2*y)*x^4 - y^4*x^3') # optional - mathematica sage: print(f.Factor()) # optional - mathematica 3 2 3 x (x - y) (-2 x + x + y )
We factor an integer::
sage: n = mathematica(2434500) # optional - mathematica sage: n.FactorInteger() # optional - mathematica {{2, 2}, {3, 2}, {5, 3}, {541, 1}} sage: n = mathematica(2434500) # optional - mathematica sage: F = n.FactorInteger(); F # optional - mathematica {{2, 2}, {3, 2}, {5, 3}, {541, 1}} sage: F[1] # optional - mathematica {2, 2} sage: F[4] # optional - mathematica {541, 1}
Mathematica's ECM package is no longer available.
Long Input ----------
The Mathematica interface reads in even very long input (using files) in a robust manner.
::
sage: t = '"%s"'%10^10000 # ten thousand character string. sage: a = mathematica(t) # optional - mathematica sage: a = mathematica.eval(t) # optional - mathematica
Loading and saving ------------------
Mathematica has an excellent ``InputForm`` function, which makes saving and loading Mathematica objects possible. The first examples test saving and loading to strings.
::
sage: x = mathematica(pi/2) # optional - mathematica sage: print(x) # optional - mathematica Pi -- 2 sage: loads(dumps(x)) == x # optional - mathematica True sage: n = x.N(50) # optional - mathematica sage: print(n) # optional - mathematica 1.5707963267948966192313216916397514420985846996876 sage: loads(dumps(n)) == n # optional - mathematica True
Complicated translations ------------------------
The ``mobj.sage()`` method tries to convert a Mathematica object to a Sage object. In many cases, it will just work. In particular, it should be able to convert expressions entirely consisting of:
- numbers, i.e. integers, floats, complex numbers; - functions and named constants also present in Sage, where:
- Sage knows how to translate the function or constant's name from Mathematica's, or - the Sage name for the function or constant is trivially related to Mathematica's;
- symbolic variables whose names don't pathologically overlap with objects already defined in Sage.
This method will not work when Mathematica's output includes:
- strings; - functions unknown to Sage; - Mathematica functions with different parameters/parameter order to the Sage equivalent.
If you want to convert more complicated Mathematica expressions, you can instead call ``mobj._sage_()`` and supply a translation dictionary::
sage: m = mathematica('NewFn[x]') # optional - mathematica sage: m._sage_(locals={'NewFn': sin}) # optional - mathematica sin(x)
For more details, see the documentation for ``._sage_()``.
OTHER Examples::
sage: def math_bessel_K(nu,x): ....: return mathematica(nu).BesselK(x).N(20) sage: math_bessel_K(2,I) # optional - mathematica -2.5928861754911969782 + 0.1804899720669620266 I
::
sage: slist = [[1, 2], 3., 4 + I] sage: mlist = mathematica(slist); mlist # optional - mathematica {{1, 2}, 3., 4 + I} sage: slist2 = list(mlist); slist2 # optional - mathematica [{1, 2}, 3., 4 + I] sage: slist2[0] # optional - mathematica {1, 2} sage: slist2[0].parent() # optional - mathematica Mathematica sage: slist3 = mlist.sage(); slist3 # optional - mathematica [[1, 2], 3.0, I + 4]
::
sage: mathematica('10.^80') # optional - mathematica 1.*^80 sage: mathematica('10.^80').sage() # optional - mathematica 1e+80
AUTHORS:
- William Stein (2005): first version
- Doug Cutrell (2006-03-01): Instructions for use under Cygwin/Windows.
- Felix Lawrence (2009-08-21): Added support for importing Mathematica lists and floats with exponents. """
#***************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # # This code is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import print_function
import os import re
from sage.misc.cachefunc import cached_method from sage.interfaces.expect import (Expect, ExpectElement, ExpectFunction, FunctionElement, AsciiArtString) from sage.interfaces.tab_completion import ExtraTabCompletion from sage.docs.instancedoc import instancedoc
def clean_output(s): if s is None: return '' i = s.find('Out[') j = i + s[i:].find('=') s = s[:i] + ' '*(j+1-i) + s[j+1:] s = s.replace('\\\n','') return s.strip('\n')
def _un_camel(name): """ Convert `CamelCase` to `camel_case`.
EXAMPLES::
sage: sage.interfaces.mathematica._un_camel('CamelCase') 'camel_case' sage: sage.interfaces.mathematica._un_camel('EllipticE') 'elliptic_e' sage: sage.interfaces.mathematica._un_camel('FindRoot') 'find_root' sage: sage.interfaces.mathematica._un_camel('GCD') 'gcd' """
class Mathematica(ExtraTabCompletion, Expect): """ Interface to the Mathematica interpreter. """ def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None, command=None, verbose_start=False): # We use -rawterm to get a raw text interface in Mathematica 9 or later. # This works around the following issues of Mathematica 9 or later # (tested with Mathematica 11.0.1 for Mac OS X x86 (64-bit)) # # 1) If TERM is unset and input is a pseudoterminal, Mathematica shows no # prompts, so pexpect will not work. # # 2) If TERM is set (to dumb, lpr, vt100, or xterm), there will be # prompts; but there is bizarre echoing behavior by Mathematica (not # the terminal driver). For example, with TERM=dumb, many spaces and # \r's are echoed. With TERM=vt100 or better, in addition, many escape # sequences are printed. # if command is None: command = os.getenv('SAGE_MATHEMATICA_COMMAND') or 'math -rawterm' eval_using_file_cutoff = 1024 # Removing terminal echo using "stty -echo" is not essential but it slightly # improves performance (system time) and eliminates races of the terminal echo # as a possible source of error. if server: command = 'stty -echo; {}'.format(command) else: command = 'sh -c "stty -echo; {}"'.format(command) Expect.__init__(self, name = 'mathematica', command = command, prompt = 'In[[0-9]+]:=', server = server, server_tmpdir = server_tmpdir, script_subdirectory = script_subdirectory, verbose_start = verbose_start, logfile=logfile, eval_using_file_cutoff=eval_using_file_cutoff)
def _read_in_file_command(self, filename): return '<<"%s"'%filename
def _keyboard_interrupt(self): print("Interrupting %s..." % self) e = self._expect e.sendline(chr(3)) # send ctrl-c e.expect('Interrupt> ') e.sendline("a") # a -- abort e.expect(self._prompt) return e.before
def _install_hints(self): """ Hints for installing mathematica on your computer.
AUTHORS:
- William Stein and Justin Walker (2006-02-12) """ return """ In order to use the Mathematica interface you need to have Mathematica installed and have a script in your PATH called "math" that runs the command-line version of Mathematica. Alternatively, you could use a remote connection to a server running Mathematica -- for hints, type print(mathematica._install_hints_ssh())
(1) You might have to buy Mathematica (http://www.wolfram.com/).
(2) * LINUX: The math script comes standard with your Mathematica install.
* APPLE OS X: (a) create a file called math (in your PATH): #!/bin/sh /Applications/Mathematica.app/Contents/MacOS/MathKernel $@
The path in the above script must be modified if you installed Mathematica elsewhere or installed an old version of Mathematica that has the version in the .app name.
(b) Make the file executable. chmod +x math
* WINDOWS:
Install Mathematica for Linux into the VMware virtual machine (sorry, that's the only way at present). """
## The following only works with Sage for Cygwin (not colinux). ## Note that Sage colinux is the preferred way to run Sage in Windows, ## and I do not know how to use Mathematica from colinux Sage (unless ## you install Mathematica-for-linux into the colinux machine, which ## is possible).
## Create a file named "math", which you place in the Sage root ## directory. The file contained a single line, which was the ## path to the mathematica math.exe file. In my case, this might be:
## C:/Program Files/Wolfram Research/Mathematica/4.0/math.exe
## The key points are ## 1) there is a file named "math.exe", and it will generally be ## located in a place analogous to the above (depending on where ## Mathematica has been installed). This file is used only for ## launching the kernel with a text-based interface. ## 2) a cygwin batch file must be created which executes this file, ## which means using forward slashes rather than back slashes, ## and probably surrounding everything in quotes ## 3) this cygwin batch file must be on the path for Sage (placing ## it in <SAGE_LOCAL>/bin/ is an easy way to ensure this).
def eval(self, code, strip=True, **kwds): s = Expect.eval(self, code, **kwds) if strip: return AsciiArtString(clean_output(s)) else: return AsciiArtString(s)
#def _keyboard_interrupt(self): # print("Keyboard interrupt pressed; trying to recover.") # E = self.expect() # E.sendline(chr(3)) # E.sendline('a') # E.expect(':= ') # raise KeyboardInterrupt, "Ctrl-c pressed while running Mathematica command"
def set(self, var, value): """ Set the variable var to the given value. """ #out = self.eval(cmd) if len(out) > 8: raise TypeError("Error executing code in Mathematica\nCODE:\n\t%s\nMathematica ERROR:\n\t%s"%(cmd, out))
def get(self, var, ascii_art=False): """ Get the value of the variable var.
AUTHORS:
- William Stein
- Kiran Kedlaya (2006-02-04): suggested using InputForm """ if ascii_art: return self.eval(var, strip=True) else: return self.eval('InputForm[%s, NumberMarks->False]'%var, strip=True)
#def clear(self, var): # """ # Clear the variable named var. # """ # self.eval('Clear[%s]'%var)
def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=False): allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt) return str(s).strip('\n')
def _function_call_string(self, function, args, kwds): """ Returns the string used to make function calls.
EXAMPLES::
sage: mathematica._function_call_string('Sin', ['x'], []) 'Sin[x]' """
def _left_list_delim(self):
def _right_list_delim(self):
def _left_func_delim(self): return "["
def _right_func_delim(self): return "]"
########################################### # System -- change directory, etc ########################################### def chdir(self, dir): """ Change Mathematica's current working directory.
EXAMPLES::
sage: mathematica.chdir('/') # optional - mathematica sage: mathematica('Directory[]') # optional - mathematica "/" """ self.eval('SetDirectory["%s"]'%dir)
def _true_symbol(self): return ' True'
def _false_symbol(self): return ' False'
def _equality_symbol(self):
def _assign_symbol(self): return ":="
def _exponent_symbol(self): """ Returns the symbol used to denote the exponent of a number in Mathematica.
EXAMPLES::
sage: mathematica._exponent_symbol() # optional - mathematica '*^'
::
sage: bignum = mathematica('10.^80') # optional - mathematica sage: repr(bignum) # optional - mathematica '1.*^80' sage: repr(bignum).replace(mathematica._exponent_symbol(), 'e').strip() # optional - mathematica '1.e80' """ return "*^"
def _object_class(self):
def console(self, readline=True): mathematica_console(readline=readline)
def _tab_completion(self): a = self.eval('Names["*"]') return a.replace('$','').replace('\n \n>','').replace(',','').replace('}','').replace('{','').split()
def help(self, cmd): return self.eval('? %s'%cmd)
def __getattr__(self, attrname): if attrname[:1] == "_": raise AttributeError return MathematicaFunction(self, attrname)
@instancedoc class MathematicaElement(ExpectElement): def __getitem__(self, n): return self.parent().new('%s[[%s]]'%(self._name, n))
def __getattr__(self, attrname): self._check_valid() if attrname[:1] == "_": raise AttributeError return MathematicaFunctionElement(self, attrname)
def __float__(self, precision=16): P = self.parent() return float(P.eval('N[%s,%s]'%(self.name(),precision)))
def _reduce(self): return self.parent().eval('InputForm[%s]'%self.name())
def __reduce__(self): return reduce_load, (self._reduce(), )
def _latex_(self): z = self.parent().eval('TeXForm[%s]'%self.name()) i = z.find('=') return z[i+1:].strip()
def _repr_(self): P = self.parent() return P.get(self._name, ascii_art=False).strip()
def _sage_(self, locals={}): r""" Attempt to return a Sage version of this object.
This method works successfully when Mathematica returns a result or list of results that consist only of: - numbers, i.e. integers, floats, complex numbers; - functions and named constants also present in Sage, where: - Sage knows how to translate the function or constant's name from Mathematica's naming scheme, or - you provide a translation dictionary `locals`, or - the Sage name for the function or constant is simply the Mathematica name in lower case; - symbolic variables whose names don't pathologically overlap with objects already defined in Sage.
This method will not work when Mathematica's output includes: - strings; - functions unknown to Sage that are not specified in `locals`; - Mathematica functions with different parameters/parameter order to the Sage equivalent. In this case, define a function to do the parameter conversion, and pass it in via the locals dictionary.
EXAMPLES:
Mathematica lists of numbers/constants become Sage lists of numbers/constants::
sage: m = mathematica('{{1., 4}, Pi, 3.2e100, I}') # optional - mathematica sage: s = m.sage(); s # optional - mathematica [[1.0, 4], pi, 3.2*e100, I] sage: s[1].n() # optional - mathematica 3.14159265358979 sage: s[3]^2 # optional - mathematica -1
::
sage: m = mathematica('x^2 + 5*y') # optional - mathematica sage: m.sage() # optional - mathematica x^2 + 5*y
::
sage: m = mathematica('Sin[Sqrt[1-x^2]] * (1 - Cos[1/x])^2') # optional - mathematica sage: m.sage() # optional - mathematica (cos(1/x) - 1)^2*sin(sqrt(-x^2 + 1))
::
sage: m = mathematica('NewFn[x]') # optional - mathematica sage: m._sage_(locals={'NewFn': sin}) # optional - mathematica sin(x)
::
sage: var('bla') # optional - mathematica bla sage: m = mathematica('bla^2') # optional - mathematica sage: bla^2 - m.sage() # optional - mathematica 0
::
sage: m = mathematica('bla^2') # optional - mathematica sage: mb = m.sage() # optional - mathematica sage: var('bla') # optional - mathematica bla sage: bla^2 - mb # optional - mathematica 0
AUTHORS:
- Felix Lawrence (2010-11-03): Major rewrite to use ._sage_repr() and sage.calculus.calculus.symbolic_expression_from_string() for greater compatibility, while still supporting conversion of symbolic expressions. """ from sage.libs.pynac.pynac import symbol_table from sage.symbolic.constants import constants_name_table as constants from sage.calculus.calculus import symbolic_expression_from_string from sage.calculus.calculus import _find_func as find_func
# Get Mathematica's output and perform preliminary formatting res = self._sage_repr() if '"' in res: raise NotImplementedError("String conversion from Mathematica \ does not work. Mathematica's output was: %s" % res)
# Find all the mathematica functions, constants and symbolic variables # present in `res`. Convert MMA functions and constants to their # Sage equivalents (if possible), using `locals` and # `sage.libs.pynac.pynac.symbol_table['mathematica']` as translation # dictionaries. If a MMA function or constant is not either # dictionary, then we use a variety of tactics listed in `autotrans`. # If a MMA variable is not in any dictionary, then create an # identically named Sage equivalent.
# Merge the user-specified locals dictionary and the symbol_table # (locals takes priority) lsymbols = symbol_table['mathematica'].copy() lsymbols.update(locals)
# Strategies for translating unknown functions/constants: autotrans = [ str.lower, # Try it in lower case _un_camel, # Convert `CamelCase` to `camel_case` lambda x: x # Try the original name ]
# Find the MMA funcs/vars/constants - they start with a letter. # Exclude exponents (e.g. 'e8' from 4.e8) p = re.compile('(?<!\.)[a-zA-Z]\w*') for m in p.finditer(res): # If the function, variable or constant is already in the # translation dictionary, then just move on. if m.group() in lsymbols: pass # Now try to translate all other functions -- try each strategy # in `autotrans` and check if the function exists in Sage elif m.end() < len(res) and res[m.end()] == '(': for t in autotrans: f = find_func(t(m.group()), create_when_missing = False) if f is not None: lsymbols[m.group()] = f break else: raise NotImplementedError("Don't know a Sage equivalent \ for Mathematica function '%s'. Please specify one \ manually using the 'locals' dictionary" % m.group()) # Check if Sage has an equivalent constant else: for t in autotrans: if t(m.group()) in constants: lsymbols[m.group()] = constants[t(m.group())] break # If Sage has never heard of the variable, then # symbolic_expression_from_string will automatically create it try: return symbolic_expression_from_string(res, lsymbols, accept_sequence=True) except Exception: raise NotImplementedError("Unable to parse Mathematica \ output: %s" % res)
def __str__(self): P = self._check_valid() return P.get(self._name, ascii_art=True)
def __len__(self): """ Return the object's length, evaluated by mathematica.
EXAMPLES::
sage: len(mathematica([1,1.,2])) # optional - mathematica 3
AUTHORS: - Felix Lawrence (2009-08-21) """ return self.Length()
@cached_method def _is_graphics(self): """ Test whether the mathematica expression is graphics
OUTPUT:
Boolean.
EXAMPLES::
sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica sage: P._is_graphics() # optional - mathematica True """ P = self._check_valid() return P.eval('InputForm[%s]' % self.name()).strip().startswith('Graphics[')
def save_image(self, filename, ImageSize=600): r""" Save a mathematica graphics
INPUT:
- ``filename`` -- string. The filename to save as. The extension determines the image file format.
- ``ImageSize`` -- integer. The size of the resulting image.
EXAMPLES::
sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica sage: filename = tmp_filename() # optional - mathematica sage: P.save_image(filename, ImageSize=800) # optional - mathematica """ P = self._check_valid() if not self._is_graphics(): raise ValueError('mathematica expression is not graphics') filename = os.path.abspath(filename) s = 'Export["%s", %s, ImageSize->%s]'%(filename, self.name(), ImageSize) P.eval(s)
def _rich_repr_(self, display_manager, **kwds): """ Rich Output Magic Method
See :mod:`sage.repl.rich_output` for details.
EXAMPLES::
sage: from sage.repl.rich_output import get_display_manager sage: dm = get_display_manager() sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica
The following test requires a working X display on Linux so that the Mathematica frontend can do the rendering (:trac:`23112`)::
sage: P._rich_repr_(dm) # optional - mathematica mathematicafrontend OutputImagePng container """ if self._is_graphics(): OutputImagePng = display_manager.types.OutputImagePng if display_manager.preferences.graphics == 'disable': return if OutputImagePng in display_manager.supported_output(): return display_manager.graphics_from_save( self.save_image, kwds, '.png', OutputImagePng) else: OutputLatex = display_manager.types.OutputLatex dmp = display_manager.preferences.text if dmp is None or dmp == 'plain': return if dmp == 'latex' and OutputLatex in display_manager.supported_output(): return OutputLatex(self._latex_())
def show(self, ImageSize=600): r""" Show a mathematica expression immediately.
This method attempts to display the graphics immediately, without waiting for the currently running code (if any) to return to the command line. Be careful, calling it from within a loop will potentially launch a large number of external viewer programs.
INPUT:
- ``ImageSize`` -- integer. The size of the resulting image.
OUTPUT:
This method does not return anything. Use :meth:`save` if you want to save the figure as an image.
EXAMPLES::
sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica sage: show(P) # optional - mathematica sage: P.show(ImageSize=800) # optional - mathematica sage: Q = mathematica('Sin[x Cos[y]]/Sqrt[1-x^2]') # optional - mathematica sage: show(Q) # optional - mathematica <html><script type="math/tex">\frac{\sin (x \cos (y))}{\sqrt{1-x^2}}</script></html> """ from sage.repl.rich_output import get_display_manager dm = get_display_manager() dm.display_immediately(self, ImageSize=ImageSize)
def str(self): return str(self)
def __cmp__(self, other): #if not (isinstance(other, ExpectElement) and other.parent() is self.parent()): # return coerce.cmp(self, other) P = self.parent() if P.eval("%s < %s"%(self.name(), other.name())).strip() == 'True': return -1 elif P.eval("%s > %s"%(self.name(), other.name())).strip() == 'True': return 1 elif P.eval("%s == %s"%(self.name(), other.name())).strip() == 'True': return 0 else: return -1 # everything is supposed to be comparable in Python, so we define # the comparison thus when no comparable in interfaced system.
def N(self, precision=None): r""" Numerical approximation by calling Mathematica's `N[]`
Calling Mathematica's `N[]` function, with optional precision in decimal digits. Unlike Sage's `n()`, `N()` can be applied to symbolic Mathematica objects.
A workaround for :trac:`18888` backtick issue, stripped away by `get()`, is included.
.. note::
The base class way up the hierarchy defines an `N` (modeled after Mathematica's) which overwrites the Mathematica one, and doesn't work at all. We restore it here.
EXAMPLES::
sage: mathematica('Pi/2').N(10) # optional -- mathematica 1.570796327 sage: mathematica('Pi').N(50) # optional -- mathematica 3.1415926535897932384626433832795028841971693993751 sage: mathematica('Pi*x^2-1/2').N() # optional -- mathematica 2 -0.5 + 3.14159 x """ P = self.parent() if precision is None: return P.eval('N[%s]'%self.name()) return P.eval('N[%s,%s]'%(self.name(),precision))
def n(self, *args, **kwargs): r""" Numerical approximation by converting to Sage object first
Convert the object into a Sage object and return its numerical approximation. See documentation of the function :func:`sage.misc.functional.n` for details.
EXAMPLES::
sage: mathematica('Pi').n(10) # optional -- mathematica 3.1 sage: mathematica('Pi').n() # optional -- mathematica 3.14159265358979 sage: mathematica('Pi').n(digits=10) # optional -- mathematica 3.141592654 """ return self._sage_().n(*args, **kwargs)
@instancedoc class MathematicaFunction(ExpectFunction): def _instancedoc_(self): M = self._parent return M.help(self._name)
@instancedoc class MathematicaFunctionElement(FunctionElement): def _instancedoc_(self): M = self._obj.parent() return M.help(self._name)
# An instance mathematica = Mathematica()
def reduce_load(X): return mathematica(X)
def mathematica_console(readline=True): from sage.repl.rich_output.display_manager import get_display_manager if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%mathematica magics instead.') if not readline: os.system('math') return else: os.system('math-readline') return |