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.symbolic.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.symbolic.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 != 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 StandardError: raise NotImplementedError, "Unable to parse Mathematica \ output: %s" % res
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.symbolic.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.symbolic.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 symbolic_expression_from_mathematica_string(mexpr): r""" Translate a mathematica string into a symbolic expression INPUT: - ``mexpr`` -- string OUTPUT: symbolic expression EXAMPLES:: sage: from sage.symbolic.integration.external import symbolic_expression_from_mathematica_string sage: symbolic_expression_from_mathematica_string(u'-Cos[x]') -cos(x) """ import re from sage.libs.pynac.pynac import symbol_table from sage.interfaces.mathematica import _un_camel as un_camel 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 expr = mexpr.replace('\n', ' ').replace('\r', '') expr = expr.replace('[', '(').replace(']', ')') expr = expr.replace('{', '[').replace('}', ']') lsymbols = symbol_table['mathematica'].copy() autotrans = [ lambda x: x.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(r'(?<!\.)[a-zA-Z]\w*') for m in p.finditer(expr): # 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(expr) and expr[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'." % 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 return symbolic_expression_from_string(expr, lsymbols, accept_sequence=True)
def mma_free_integrator(expression, v, a=None, b=None): """ Integration using Mathematica's online integrator EXAMPLES:: sage: from sage.symbolic.integration.external import mma_free_integrator sage: mma_free_integrator(sin(x), x) # optional - internet -cos(x) TESTS: Check that :trac:`18212` is resolved:: sage: var('y') # optional - internet y sage: integral(sin(y)^2, y, algorithm='mathematica_free') # optional - internet -1/2*cos(y)*sin(y) + 1/2*y sage: mma_free_integrator(exp(-x^2)*log(x), x) # optional - internet 1/2*sqrt(pi)*erf(x)*log(x) - x*hypergeometric((1/2, 1/2), (3/2, 3/2), -x^2) """ import re # import compatible with py2 and py3 from six.moves.urllib.request import urlopen from six.moves.urllib.parse import urlencode # We need to integrate against x vars = [str(x) for x in expression.variables()] if any(len(x)>1 for x in vars): raise NotImplementedError("Mathematica online integrator can only handle single letter variables.") x = SR.var('x') if repr(v) != 'x': for i in range(ord('a'), ord('z')+1): if chr(i) not in vars: shadow_x = SR.var(chr(i)) break expression = expression.subs({x:shadow_x}).subs({v: x}) params = urlencode({'expr': expression._mathematica_init_(), 'random': 'false'}) page = urlopen("http://integrals.wolfram.com/home.jsp", params).read() page = page[page.index('"inputForm"'):page.index('"outputForm"')] page = re.sub("\s", "", page) mexpr = re.match(r".*Integrate.*==</em><br/>(.*)</p>", page).groups()[0] try: from sage.libs.pynac.pynac import symbol_table from sage.interfaces.mathematica import _un_camel as un_camel 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 expr = mexpr.replace('\n',' ').replace('\r', '') expr = expr.replace('[', '(').replace(']', ')') expr = expr.replace('{', '[').replace('}', ']') lsymbols = symbol_table['mathematica'].copy() 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(expr): # 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(expr) and expr[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'." % 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 ans = symbolic_expression_from_string(expr, lsymbols, accept_sequence=True) if repr(v) != 'x': ans = ans.subs({x:v}).subs({shadow_x:x}) return ans except TypeError: raise ValueError("Unable to parse: %s" % mexpr)