Skip to content

Commit

Permalink
Trac #31756: regression: conversion of Mathematica's Sqrt to Sage fails
Browse files Browse the repository at this point in the history
This works with Sage 9.2, but fails with 9.3.rc4:

{{{
sage: mathematica('Sqrt[x]').sage()
Sqrt(x)
}}}

The result is an uppercase symbolic function, but should be the
lowercase function `sqrt` in Sage.

A doctest in interfaces/mathematica.py now fails:
{{{
File "src/sage/interfaces/mathematica.py", line 776, in
sage.interfaces.mathematica.MathematicaElement._sage_
Failed example:
    m.sage()                          # optional - mathematica
Expected:
    (cos(1/x) - 1)^2*sin(sqrt(-x^2 + 1))
Got:
    (cos(1/x) - 1)^2*sin(Sqrt(-x^2 + 1))
}}}

This is also reproducible with `mathematica_free`, see
[https://groups.google.com/g/sage-release/c/rjM44KX8pbc/m/8xYVp77iBgAJ
this post on sage-release].

This also affects the Gamma function:
{{{
File "src/sage/functions/gamma.py", line 731, in
sage.functions.gamma._mathematica_gamma
Failed example:
    gamma(4/3)._mathematica_().sage()       # indirect doctest, optional
- mathematica
Expected:
    gamma(4/3)
Got:
    Gamma(4/3)
}}}

URL: https://trac.sagemath.org/31756
Reported by: gh-mwageringel
Ticket author(s): Markus Wageringel
Reviewer(s): Emmanuel Charpentier
  • Loading branch information
Release Manager committed May 9, 2021
2 parents d6c5cd9 + 6bacab2 commit c21d3c6
Showing 1 changed file with 33 additions and 4 deletions.
37 changes: 33 additions & 4 deletions src/sage/calculus/calculus.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@

from sage.misc.lazy_import import lazy_import
lazy_import('sage.interfaces.maxima_lib', 'maxima')
from types import FunctionType


########################################################
Expand Down Expand Up @@ -2057,6 +2058,34 @@ def _inverse_laplace_latex_(self, *args):
maxima_hyper = re.compile(r"\%f\[\d+,\d+\]") # matches %f[m,n]


def _is_function(v):
r"""
Return whether a symbolic element is a function, not a variable.
TESTS::
sage: from sage.calculus.calculus import _is_function
sage: _is_function(x)
False
sage: _is_function(sin)
True
Check that :trac:`31756` is fixed::
sage: from sage.libs.pynac.pynac import symbol_table
sage: _is_function(symbol_table['mathematica']['Gamma'])
True
sage: from sage.libs.pynac.pynac import register_symbol
sage: foo = lambda x: x^2 + 1
sage: register_symbol(foo, dict(mathematica='Foo')) # optional - mathematica
sage: mathematica('Foo[x]').sage() # optional - mathematica
x^2 + 1
"""
# note that Sage variables are callable, so we only check the type
return isinstance(v, Function) or isinstance(v, FunctionType)


def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima):
r"""
Given a string representation of a Maxima expression, parse it and
Expand Down Expand Up @@ -2144,9 +2173,9 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima):
+Infinity
"""
var_syms = {k: v for k, v in symbol_table.get('maxima', {}).items()
if not isinstance(v,Function)}
if not _is_function(v)}
function_syms = {k: v for k, v in symbol_table.get('maxima', {}).items()
if isinstance(v,Function)}
if _is_function(v)}

if not len(x):
raise RuntimeError("invalid symbolic expression -- ''")
Expand Down Expand Up @@ -2402,9 +2431,9 @@ def symbolic_expression_from_string(s, syms={}, accept_sequence=False):
"""
parse_func = SR_parser.parse_sequence if accept_sequence else SR_parser.parse_expression
parser_make_var.set_names({k: v for k, v in syms.items()
if not isinstance(v,Function)})
if not _is_function(v)})
parser_make_function.set_names({k: v for k, v in syms.items()
if isinstance(v,Function)})
if _is_function(v)})
return parse_func(s)


Expand Down

0 comments on commit c21d3c6

Please sign in to comment.