From b323f1e16c590d486b26f41192b212210008d956 Mon Sep 17 00:00:00 2001 From: mmatera Date: Sat, 22 Jul 2023 19:11:52 -0300 Subject: [PATCH] split to_sympy from BaseElement --- mathics/builtin/arithfns/basic.py | 10 ++-- mathics/builtin/arithmetic.py | 47 +++++++++-------- mathics/builtin/base.py | 6 +-- mathics/builtin/forms/output.py | 7 +-- mathics/builtin/list/constructing.py | 8 +-- mathics/builtin/numbers/algebra.py | 50 +++++++++---------- mathics/builtin/numbers/calculus.py | 41 ++++++++------- mathics/builtin/numbers/diffeqns.py | 6 +-- mathics/builtin/numbers/hyperbolic.py | 26 ++++++---- mathics/builtin/numbers/integer.py | 6 +-- mathics/builtin/numbers/linalg.py | 6 +-- mathics/builtin/numbers/numbertheory.py | 14 +++--- mathics/builtin/numbers/trig.py | 33 +++++++----- mathics/builtin/numeric.py | 8 +-- mathics/builtin/optimization.py | 22 ++++---- mathics/builtin/quantum_mechanics/angular.py | 8 +-- mathics/builtin/recurrence.py | 6 +-- mathics/builtin/specialfns/elliptic.py | 10 ++-- mathics/builtin/specialfns/gamma.py | 4 +- .../equality_inequality.py | 5 +- .../numerical_properties.py | 5 +- mathics/core/convert/matrix.py | 6 ++- mathics/core/convert/sympy.py | 28 +++++++++-- mathics/core/element.py | 3 -- mathics/core/expression.py | 16 ------ mathics/core/symbols.py | 5 -- mathics/eval/arithmetic.py | 12 ++--- mathics/eval/hyperbolic.py | 8 +-- mathics/eval/math_ops.py | 6 +-- mathics/eval/numbers.py | 4 +- mathics/eval/testing_expressions.py | 5 +- test/core/convert/test_sympy.py | 10 ++-- test/core/test_sympy_python_convert.py | 6 +-- 33 files changed, 231 insertions(+), 206 deletions(-) diff --git a/mathics/builtin/arithfns/basic.py b/mathics/builtin/arithfns/basic.py index 6fb5a8873..07ce6c364 100644 --- a/mathics/builtin/arithfns/basic.py +++ b/mathics/builtin/arithfns/basic.py @@ -31,7 +31,7 @@ A_READ_PROTECTED, ) from mathics.core.convert.expression import to_expression -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy from mathics.core.expression import Expression from mathics.core.list import ListExpression from mathics.core.symbols import ( @@ -347,16 +347,16 @@ def negate(item): # -> Expression (see FIXME below) else: return Expression(SymbolTimes, IntegerM1, *item.elements) elif isinstance(item, Number): - return from_sympy(-item.to_sympy()) + return from_sympy(to_sympy(-item)) else: return Expression(SymbolTimes, IntegerM1, item) def is_negative(value) -> bool: if isinstance(value, Complex): - real, imag = value.to_sympy().as_real_imag() + real, imag = to_sympy(value).as_real_imag() if real <= 0 and imag <= 0: return True - elif isinstance(value, Number) and value.to_sympy() < 0: + elif isinstance(value, Number) and to_sympy(value) < 0: return True return False @@ -786,7 +786,7 @@ def inverse(item): if ( item.has_form("Power", 2) and isinstance(item.elements[1], (Integer, Rational, Real)) - and item.elements[1].to_sympy() < 0 + and to_sympy(item.elements[1]) < 0 ): # nopep8 negative.append(inverse(item)) diff --git a/mathics/builtin/arithmetic.py b/mathics/builtin/arithmetic.py index 851316ad0..6d73aa2b4 100644 --- a/mathics/builtin/arithmetic.py +++ b/mathics/builtin/arithmetic.py @@ -45,7 +45,12 @@ A_PROTECTED, ) from mathics.core.convert.expression import to_expression -from mathics.core.convert.sympy import SympyExpression, from_sympy, sympy_symbol_prefix +from mathics.core.convert.sympy import ( + SympyExpression, + from_sympy, + sympy_symbol_prefix, + to_sympy, +) from mathics.core.element import BaseElement from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression @@ -128,7 +133,7 @@ def eval(self, z, evaluation: Evaluation): # if no arguments are inexact attempt to use sympy if all(not x.is_inexact() for x in args): - result = to_expression(self.get_name(), *args).to_sympy() + result = to_sympy(to_expression(self.get_name(), *args)) result = self.prepare_mathics(result) result = from_sympy(result) # evaluate elements to convert e.g. Plus[2, I] -> Complex[2, 1] @@ -467,7 +472,7 @@ def eval(self, r, i, evaluation: Evaluation): "Complex[r_?NumberQ, i_?NumberQ]" if isinstance(r, Complex) or isinstance(i, Complex): - sym_form = r.to_sympy() + sympy.I * i.to_sympy() + sym_form = to_sympy(r) + sympy.I * to_sympy(i) r, i = sym_form.simplify().as_real_imag() r, i = from_sympy(r), from_sympy(i) return Complex(r, i) @@ -548,12 +553,12 @@ def to_sympy(self, expr, **kwargs): elif cond is SymbolFalse: sympy_cond = False if sympy_cond is None: - sympy_cond = cond.to_sympy(**kwargs) + sympy_cond = to_sympy(cond, **kwargs) if not (sympy_cond.is_Relational or sympy_cond.is_Boolean): return sympy_cases = ( - (expr.to_sympy(**kwargs), sympy_cond), + (to_sympy(expr, **kwargs), sympy_cond), (sympy.Symbol(sympy_symbol_prefix + "System`Undefined"), True), ) return sympy.Piecewise(*sympy_cases) @@ -719,7 +724,7 @@ def to_sympy(self, expr, **kwargs): elif dir == -1: return -sympy.oo else: - return sympy.Mul((expr.elements[0].to_sympy()), sympy.zoo) + return sympy.Mul((to_sympy(expr.elements[0])), sympy.zoo) else: return sympy.zoo @@ -866,7 +871,7 @@ def eval_number(self, number, evaluation: Evaluation): def eval(self, number, evaluation: Evaluation): "Im[number_]" - return from_sympy(sympy.im(number.to_sympy().expand(complex=True))) + return from_sympy(sympy.im(to_sympy(number).expand(complex=True))) class Integer_(Builtin): @@ -965,16 +970,16 @@ def to_sympy(self, expr, **kwargs): elif cond is SymbolFalse: sympy_cond = False if sympy_cond is None: - sympy_cond = cond.to_sympy(**kwargs) + sympy_cond = to_sympy(cond, **kwargs) if not (sympy_cond.is_Relational or sympy_cond.is_Boolean): return - sympy_cases.append((then.to_sympy(**kwargs), sympy_cond)) + sympy_cases.append((to_sympy(then, **kwargs), sympy_cond)) if len(elements) == 2: # default case - sympy_cases.append((elements[1].to_sympy(**kwargs), True)) + sympy_cases.append((to_sympy(elements[1], **kwargs), True)) else: - sympy_cases.append((Integer0.to_sympy(**kwargs), True)) + sympy_cases.append((to_sympy(Integer0, **kwargs), True)) return sympy.Piecewise(*sympy_cases) @@ -1056,10 +1061,10 @@ def to_sympy(self, expr, **kwargs): try: e_kwargs = kwargs.copy() e_kwargs["convert_all_global_functions"] = True - e = expr.elements[0].to_sympy(**e_kwargs) - i = index.elements[0].to_sympy(**kwargs) - start = index.elements[1].to_sympy(**kwargs) - stop = index.elements[2].to_sympy(**kwargs) + e = to_sympy(expr.elements[0], **e_kwargs) + i = to_sympy(index.elements[0], **kwargs) + start = to_sympy(index.elements[1], **kwargs) + stop = to_sympy(index.elements[2], **kwargs) return sympy.product(e, (i, start, stop)) except ZeroDivisionError: @@ -1136,7 +1141,7 @@ def eval_number(self, number, evaluation: Evaluation): def eval(self, number, evaluation: Evaluation): "Re[number_]" - return from_sympy(sympy.re(number.to_sympy().expand(complex=True))) + return from_sympy(sympy.re(to_sympy(number).expand(complex=True))) class Real_(Builtin): @@ -1384,7 +1389,7 @@ def eval(self, x, evaluation: Evaluation): return result # return None - sympy_x = x.to_sympy() + sympy_x = to_sympy(x) if sympy_x is None: return None # Unhandled cases. Use sympy @@ -1505,7 +1510,7 @@ def to_sympy(self, expr, **kwargs) -> Optional[SympyExpression]: index = expr.elements[1] arg_kwargs = kwargs.copy() arg_kwargs["convert_all_global_functions"] = True - f_sympy = expr.elements[0].to_sympy(**arg_kwargs) + f_sympy = to_sympy(expr.elements[0], **arg_kwargs) if f_sympy is None: return @@ -1513,7 +1518,7 @@ def to_sympy(self, expr, **kwargs) -> Optional[SympyExpression]: # Handle summation parameters: variable, min, max var_min_max = index.elements[:3] - bounds = [expr.to_sympy(**kwargs) for expr in var_min_max] + bounds = [to_sympy(expr, **kwargs) for expr in var_min_max] if evaluation: # Min and max might be Mathics expressions. If so, evaluate them. @@ -1521,7 +1526,7 @@ def to_sympy(self, expr, **kwargs) -> Optional[SympyExpression]: min_max_expr = var_min_max[i] if not isinstance(expr, Symbol): min_max_expr_eval = min_max_expr.evaluate(evaluation) - value = min_max_expr_eval.to_sympy(**kwargs) + value = to_sympy(min_max_expr_eval, **kwargs) bounds[i] = value # FIXME: The below tests on SympyExpression, but really the @@ -1546,7 +1551,7 @@ def to_sympy(self, expr, **kwargs) -> Optional[SympyExpression]: ) ret = self.get_result(values.elements).evaluate(evaluation) # Make sure to convert the result back to sympy. - return ret.to_sympy() + return to_sympy(ret) if None not in bounds: return sympy.summation(f_sympy, bounds) diff --git a/mathics/builtin/base.py b/mathics/builtin/base.py index 4a21365a2..e02f9a3a3 100644 --- a/mathics/builtin/base.py +++ b/mathics/builtin/base.py @@ -22,7 +22,7 @@ from mathics.core.convert.expression import to_expression from mathics.core.convert.op import ascii_operator_to_symbol from mathics.core.convert.python import from_bool -from mathics.core.convert.sympy import from_sympy, to_numeric_sympy_args +from mathics.core.convert.sympy import from_sympy, to_numeric_sympy_args, to_sympy from mathics.core.definitions import Definition from mathics.core.evaluation import Evaluation from mathics.core.exceptions import MessageException @@ -691,7 +691,7 @@ def eval_iter(self, expr, i, imin, imax, di, evaluation): whole_expr = to_expression( self.get_name(), expr, ListExpression(i, imin, imax) ) - sympy_expr = whole_expr.to_sympy(evaluation=evaluation) + sympy_expr = to_sympy(whole_expr, evaluation=evaluation) if sympy_expr is None: return None @@ -964,7 +964,7 @@ def to_sympy(self, expr, **kwargs): try: if self.sympy_name: elements = self.prepare_sympy(expr.elements) - sympy_args = [element.to_sympy(**kwargs) for element in elements] + sympy_args = [to_sympy(element, **kwargs) for element in elements] if None in sympy_args: return None sympy_function = self.get_sympy_function(elements) diff --git a/mathics/builtin/forms/output.py b/mathics/builtin/forms/output.py index 76f05d1e3..03b251118 100644 --- a/mathics/builtin/forms/output.py +++ b/mathics/builtin/forms/output.py @@ -29,6 +29,7 @@ String, StringFromPython, ) +from mathics.core.convert.sympy import to_sympy from mathics.core.evaluation import Evaluation from mathics.core.expression import BoxError, Expression from mathics.core.list import ListExpression @@ -124,7 +125,7 @@ def eval_makeboxes(self, expr, n, f, evaluation: Evaluation): return None if isinstance(expr, PrecisionReal): - x = expr.to_sympy() + x = to_sympy(expr) p = int(ceil(expr.get_precision() / LOG2_10) + 1) elif isinstance(expr, MachineReal): x = expr.value @@ -796,7 +797,7 @@ def eval_python(self, expr, evaluation) -> Expression: def build_python_form(expr): if isinstance(expr, Symbol): - return expr.to_sympy() + return to_sympy(expr) return expr.to_python() try: @@ -832,7 +833,7 @@ def eval_sympy(self, expr, evaluation) -> Optional[Expression]: "MakeBoxes[expr_, SympyForm]" try: - sympy_equivalent = expr.to_sympy() + sympy_equivalent = to_sympy(expr) except Exception: return return StringFromPython(sympy_equivalent) diff --git a/mathics/builtin/list/constructing.py b/mathics/builtin/list/constructing.py index 93e20f267..1d371362c 100644 --- a/mathics/builtin/list/constructing.py +++ b/mathics/builtin/list/constructing.py @@ -15,7 +15,7 @@ from mathics.core.atoms import Integer, is_integer_rational_or_real from mathics.core.attributes import A_HOLD_FIRST, A_LISTABLE, A_LOCKED, A_PROTECTED from mathics.core.convert.expression import to_expression -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy from mathics.core.element import ElementsProperties from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression, structure @@ -263,9 +263,9 @@ def eval(self, imin, imax, di, evaluation: Evaluation): *result, elements_properties=range_list_elements_properties ) - imin = imin.to_sympy() - imax = imax.to_sympy() - di = di.to_sympy() + imin = to_sympy(imin) + imax = to_sympy(imax) + di = to_sympy(di) index = imin result = [] while index <= imax: diff --git a/mathics/builtin/numbers/algebra.py b/mathics/builtin/numbers/algebra.py index 5cbbe3871..bf98be747 100644 --- a/mathics/builtin/numbers/algebra.py +++ b/mathics/builtin/numbers/algebra.py @@ -25,7 +25,7 @@ from mathics.core.atoms import Integer, Integer0, Integer1, Number, RationalOneHalf from mathics.core.attributes import A_LISTABLE, A_PROTECTED from mathics.core.convert.python import from_bool -from mathics.core.convert.sympy import from_sympy, sympy_symbol_prefix +from mathics.core.convert.sympy import from_sympy, sympy_symbol_prefix, to_sympy from mathics.core.element import BaseElement from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression @@ -295,12 +295,12 @@ def find_vars(e, e_sympy): variables.add(e) elif e.has_form(("Plus", "Times"), None): for lv in e.elements: - lv_sympy = lv.to_sympy() + lv_sympy = to_sympy(lv) if lv_sympy is not None: find_vars(lv, lv_sympy) elif e.has_form("Power", 2): (a, b) = e.elements # a^b - a_sympy, b_sympy = a.to_sympy(), b.to_sympy() + a_sympy, b_sympy = to_sympy(a), to_sympy(b) if a_sympy is None or b_sympy is None: return if not (a_sympy.is_constant()) and b_sympy.is_rational: @@ -310,7 +310,7 @@ def find_vars(e, e_sympy): exprs = expr.elements if expr.has_form("List", None) else [expr] for e in exprs: - e_sympy = e.to_sympy() + e_sympy = to_sympy(e) if e_sympy is not None: find_vars(e, e_sympy) @@ -321,8 +321,8 @@ def get_exponents_sorted(expr, var) -> list: """ Return a sorted list of exponents of var in expr """ - f = expr.to_sympy() - x = var.to_sympy() + f = to_sympy(expr) + x = to_sympy(var) if f is None or x is None: return [Integer0] @@ -393,8 +393,8 @@ class Apart(Builtin): def eval(self, expr, var, evaluation): "Apart[expr_, var_Symbol]" - expr_sympy = expr.to_sympy() - var_sympy = var.to_sympy() + expr_sympy = to_sympy(expr) + var_sympy = to_sympy(var) if expr_sympy is None or var_sympy is None: return None @@ -444,9 +444,9 @@ def _coefficient(name, expr, form, n, evaluation): evaluation.message(name, "ivar", form) return - sympy_exprs = expr.to_sympy().as_ordered_terms() - sympy_var = form.to_sympy() - sympy_n = n.to_sympy() + sympy_exprs = to_sympy(expr).as_ordered_terms() + sympy_var = to_sympy(form) + sympy_n = to_sympy(n) def combine_exprs(exprs): result = 0 @@ -962,8 +962,8 @@ def eval(self, expr, form, evaluation): elif form.has_form("List", 0): return expr - sympy_expr = expr.to_sympy() - sympy_vars = [v.to_sympy() for v in vars] + sympy_expr = to_sympy(expr) + sympy_vars = [to_sympy(v) for v in vars] if not sympy_expr.is_polynomial(*[x for x in sympy_vars]): evaluation.message("CoefficientList", "poly", expr) @@ -1090,7 +1090,7 @@ class Denominator(Builtin): def eval(self, expr, evaluation): "Denominator[expr_]" - sympy_expr = expr.to_sympy() + sympy_expr = to_sympy(expr) if sympy_expr is None: return None numer, denom = sympy_expr.as_numer_denom() @@ -1434,7 +1434,7 @@ class Factor(Builtin): def eval(self, expr, evaluation): "Factor[expr_]" - expr_sympy = expr.to_sympy() + expr_sympy = to_sympy(expr) if expr_sympy is None: return None @@ -1500,15 +1500,15 @@ def eval_list(self, expr, vars, evaluation): evaluation.message("CoefficientList", "ivar", x) return - sympy_expr = expr.to_sympy() + sympy_expr = to_sympy(expr) if sympy_expr is None: return ListExpression(Integer1, expr) sympy_expr = sympy.together(sympy_expr) sympy_vars = [ - x.to_sympy() + to_sympy(x) for x in vars.elements - if isinstance(x, Symbol) and sympy_expr.is_polynomial(x.to_sympy()) + if isinstance(x, Symbol) and sympy_expr.is_polynomial(to_sympy(x)) ] result = [] @@ -1700,7 +1700,7 @@ def do_apply(self, expr, evaluation, options={}): # At this point, we used all the tools available in Mathics. # If the expression has a sympy form, try to use it. # Now, convert the expression to sympy - sympy_expr = expr.to_sympy() + sympy_expr = to_sympy(expr) # If the expression cannot be handled by Sympy, just return it. if sympy_expr is None: return expr @@ -1811,7 +1811,7 @@ def eval(self, s, x, evaluation): evaluation.message("MinimalPolynomial", "nalg", s) return - sympy_s, sympy_x = s.to_sympy(), x.to_sympy() + sympy_s, sympy_x = to_sympy(s), to_sympy(x) if sympy_s is None or sympy_x is None: return None sympy_result = sympy.minimal_polynomial(sympy_s, polys=True)(sympy_x) @@ -1842,7 +1842,7 @@ class Numerator(Builtin): def eval(self, expr, evaluation): "Numerator[expr_]" - sympy_expr = expr.to_sympy() + sympy_expr = to_sympy(expr) if sympy_expr is None: return None numer, denom = sympy_expr.as_numer_denom() @@ -1933,11 +1933,11 @@ def eval(self, expr, v, evaluation): if len(var.elements) == 0: evaluation.message("PolynomialQ", "novar") return - sympy_var = [x.to_sympy() for x in var.elements] + sympy_var = [to_sympy(x) for x in var.elements] else: - sympy_var = [var.to_sympy()] + sympy_var = [to_sympy(var)] - sympy_expr = expr.to_sympy() + sympy_expr = to_sympy(expr) sympy_result = sympy_expr.is_polynomial(*[x for x in sympy_var]) return from_bool(sympy_result) @@ -2005,7 +2005,7 @@ class Together(Builtin): def eval(self, expr, evaluation): "Together[expr_]" - expr_sympy = expr.to_sympy() + expr_sympy = to_sympy(expr) if expr_sympy is None: return None result = sympy.together(expr_sympy) diff --git a/mathics/builtin/numbers/calculus.py b/mathics/builtin/numbers/calculus.py index 3287d35c7..2737ae4b2 100644 --- a/mathics/builtin/numbers/calculus.py +++ b/mathics/builtin/numbers/calculus.py @@ -52,7 +52,12 @@ from mathics.core.convert.expression import to_expression, to_mathics_list from mathics.core.convert.function import expression_to_callable_and_args from mathics.core.convert.python import from_python -from mathics.core.convert.sympy import SympyExpression, from_sympy, sympy_symbol_prefix +from mathics.core.convert.sympy import ( + SympyExpression, + from_sympy, + sympy_symbol_prefix, + to_sympy, +) from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.list import ListExpression @@ -499,7 +504,7 @@ def to_sympy(self, expr, **kwargs): if len(exprs[0].elements) != len(exprs[2].elements): return - sym_args = [element.to_sympy() for element in exprs[0].elements] + sym_args = [to_sympy(element) for element in exprs[0].elements] if None in sym_args: return @@ -557,9 +562,9 @@ class DiscreteLimit(Builtin): def eval(self, f, n, n0, evaluation: Evaluation, options: dict = {}): "DiscreteLimit[f_, n_->n0_, OptionsPattern[DiscreteLimit]]" - f = f.to_sympy(convert_all_global_functions=True) - n = n.to_sympy() - n0 = n0.to_sympy() + f = to_sympy(f, convert_all_global_functions=True) + n = to_sympy(n) + n0 = to_sympy(n0) if n0 != sympy.oo: return @@ -1073,7 +1078,7 @@ def from_sympy(self, sympy_name, elements): def eval(self, f, xs, evaluation: Evaluation, options: dict): "Integrate[f_, xs__, OptionsPattern[]]" - f_sympy = f.to_sympy() + f_sympy = to_sympy(f) if f_sympy.is_infinite: return Expression(SymbolIntegrate, Integer1, xs).evaluate(evaluation) * f if f_sympy is None or isinstance(f_sympy, SympyExpression): @@ -1090,8 +1095,8 @@ def eval(self, f, xs, evaluation: Evaluation, options: dict): prec_new = min(prec_a, prec_b) if prec is None or prec_new < prec: prec = prec_new - a = a.to_sympy() - b = b.to_sympy() + a = to_sympy(a) + b = to_sympy(b) if a is None or b is None: return else: @@ -1099,7 +1104,7 @@ def eval(self, f, xs, evaluation: Evaluation, options: dict): if not x.get_name(): evaluation.message("Integrate", "ilim") return - x = x.to_sympy() + x = to_sympy(x) if x is None: return if a is None or b is None: @@ -1246,9 +1251,9 @@ class Limit(Builtin): def eval(self, expr, x, x0, evaluation: Evaluation, options={}): "Limit[expr_, x_->x0_, OptionsPattern[Limit]]" - expr = expr.to_sympy() - x = x.to_sympy() - x0 = x0.to_sympy() + expr = to_sympy(expr) + x = to_sympy(x) + x0 = to_sympy(x0) if expr is None or x is None or x0 is None: return @@ -1642,14 +1647,14 @@ def eval(self, f, i, evaluation: Evaluation): body = f.elements[0] poly = body.replace_slots([f, Symbol("_1")], evaluation) - idx = i.to_sympy() - 1 + idx = to_sympy(i) - 1 # Check for negative indeces (they are not allowed in Mathematica) if idx < 0: evaluation.message("Root", "iidx", i) return - r = sympy.CRootOf(poly.to_sympy(), idx) + r = sympy.CRootOf(to_sympy(poly), idx) except sympy.PolynomialError: evaluation.message("Root", "nuni", f) return @@ -1673,7 +1678,7 @@ def to_sympy(self, expr, **kwargs): return None body = f.elements[0].replace_slots([f, Symbol("_1")], None) - poly = body.to_sympy(**kwargs) + poly = to_sympy(body, **kwargs) i = expr.elements[1].get_int_value(**kwargs) - 1 @@ -2259,8 +2264,8 @@ def eval(self, eqs, vars, evaluation: Evaluation): return else: left, right = eq.elements - left = left.to_sympy() - right = right.to_sympy() + left = to_sympy(left) + right = to_sympy(right) if left is None or right is None: return eq = left - right @@ -2270,7 +2275,7 @@ def eval(self, eqs, vars, evaluation: Evaluation): numer, denom = eq.as_numer_denom() sympy_denoms.append(denom) - vars_sympy = [var.to_sympy() for var in vars] + vars_sympy = [to_sympy(var) for var in vars] if None in vars_sympy: return diff --git a/mathics/builtin/numbers/diffeqns.py b/mathics/builtin/numbers/diffeqns.py index 9f158f48c..94860a942 100644 --- a/mathics/builtin/numbers/diffeqns.py +++ b/mathics/builtin/numbers/diffeqns.py @@ -7,7 +7,7 @@ import sympy from mathics.builtin.base import Builtin -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.list import ListExpression @@ -153,8 +153,8 @@ def eval(self, eqn, y, x, evaluation: Evaluation): f_name = func.get_head_name() conversion_args = {"converted_functions": set([f_name])} - sym_func = func.to_sympy(**conversion_args) - sym_eq = eqn.to_sympy(**conversion_args) + sym_func = to_sympy(func, **conversion_args) + sym_eq = to_sympy(eqn, **conversion_args) # XXX when sympy adds support for higher-order PDE we will have to # change this to a tuple of solvefuns diff --git a/mathics/builtin/numbers/hyperbolic.py b/mathics/builtin/numbers/hyperbolic.py index 44670b15c..e59bccdb9 100644 --- a/mathics/builtin/numbers/hyperbolic.py +++ b/mathics/builtin/numbers/hyperbolic.py @@ -17,7 +17,7 @@ from mathics.builtin.arithmetic import _MPMathFunction from mathics.builtin.base import Builtin, SympyFunction from mathics.core.atoms import IntegerM1 -from mathics.core.convert.sympy import SympyExpression +from mathics.core.convert.sympy import SympyExpression, to_sympy from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.list import ListExpression @@ -148,9 +148,11 @@ class ArcCsch(_MPMathFunction): def to_sympy(self, expr, **kwargs) -> Optional[SympyExpression]: if len(expr.elements) == 1: - return Expression( - SymbolArcSinh, Expression(SymbolPower, expr.elements[0], IntegerM1) - ).to_sympy() + return to_sympy( + Expression( + SymbolArcSinh, Expression(SymbolPower, expr.elements[0], IntegerM1) + ) + ) class ArcSech(_MPMathFunction): @@ -184,9 +186,11 @@ class ArcSech(_MPMathFunction): def to_sympy(self, expr, **kwargs) -> Optional[SympyExpression]: if len(expr.elements) == 1: - return Expression( - SymbolArcCosh, Expression(SymbolPower, expr.elements[0], IntegerM1) - ).to_sympy() + return to_sympy( + Expression( + SymbolArcCosh, Expression(SymbolPower, expr.elements[0], IntegerM1) + ) + ) class ArcSinh(_MPMathFunction): @@ -462,9 +466,11 @@ class Sech(_MPMathFunction): def to_sympy(self, expr, **kwargs) -> Optional[SympyExpression]: if len(expr.elements) == 1: - return Expression( - SymbolPower, Expression(SymbolCosh, expr.elements[0]), IntegerM1 - ).to_sympy() + return to_sympy( + Expression( + SymbolPower, Expression(SymbolCosh, expr.elements[0]), IntegerM1 + ) + ) class Sinh(_MPMathFunction): diff --git a/mathics/builtin/numbers/integer.py b/mathics/builtin/numbers/integer.py index 9b15fc606..cdf9a2d3b 100644 --- a/mathics/builtin/numbers/integer.py +++ b/mathics/builtin/numbers/integer.py @@ -12,7 +12,7 @@ from mathics.core.atoms import Integer, Integer0, String from mathics.core.attributes import A_LISTABLE, A_NUMERIC_FUNCTION, A_PROTECTED from mathics.core.convert.expression import to_mathics_list -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy from mathics.core.expression import Expression from mathics.core.list import ListExpression from mathics.core.symbols import SymbolPlus, SymbolTimes @@ -110,7 +110,7 @@ class Ceiling(SympyFunction): def eval(self, x, evaluation): "Ceiling[x_]" - x = x.to_sympy() + x = to_sympy(x) if x is None: return return from_sympy(sympy.ceiling(x)) @@ -216,7 +216,7 @@ class Floor(SympyFunction): def eval_real(self, x, evaluation): "Floor[x_]" - x = x.to_sympy() + x = to_sympy(x) if x is not None: return from_sympy(sympy.floor(x)) diff --git a/mathics/builtin/numbers/linalg.py b/mathics/builtin/numbers/linalg.py index 287b8b9bf..5b88b195e 100644 --- a/mathics/builtin/numbers/linalg.py +++ b/mathics/builtin/numbers/linalg.py @@ -13,7 +13,7 @@ from mathics.core.convert.expression import to_mathics_list from mathics.core.convert.matrix import matrix_data from mathics.core.convert.mpmath import from_mpmath, to_mpmath_matrix -from mathics.core.convert.sympy import from_sympy, to_sympy_matrix +from mathics.core.convert.sympy import from_sympy, to_sympy, to_sympy_matrix from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.list import ListExpression @@ -547,7 +547,7 @@ def eval(self, m, b, evaluation: Evaluation): evaluation.message("LinearSolve", "matrix", b, 2) return - system = [mm + [v.to_sympy()] for mm, v in zip(matrix, b.elements)] + system = [mm + [to_sympy(v)] for mm, v in zip(matrix, b.elements)] system = to_sympy_matrix(system) if system is None: evaluation.message("LinearSolve", "matrix", b, 2) @@ -651,7 +651,7 @@ def eval(self, m, power, evaluation: Evaluation): evaluation.message("MatrixPower", "matrix", m, 1) return - sympy_power = power.to_sympy() + sympy_power = to_sympy(power) if sympy_power is None: return diff --git a/mathics/builtin/numbers/numbertheory.py b/mathics/builtin/numbers/numbertheory.py index 05431cee2..169d31e07 100644 --- a/mathics/builtin/numbers/numbertheory.py +++ b/mathics/builtin/numbers/numbertheory.py @@ -18,7 +18,7 @@ ) from mathics.core.convert.expression import to_mathics_list from mathics.core.convert.python import from_bool, from_python -from mathics.core.convert.sympy import SympyPrime, from_sympy +from mathics.core.convert.sympy import SympyPrime, from_sympy, to_sympy from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.list import ListExpression @@ -71,7 +71,7 @@ def eval(self, x, evaluation: Evaluation): def eval_with_n(self, x, n: Integer, evaluation: Evaluation): "%(name)s[x_, n_Integer]" py_n = n.value - sympy_x = x.to_sympy() + sympy_x = to_sympy(x) it = sympy.continued_fraction_iterator(sympy_x) return from_sympy([next(it) for _ in range(py_n)]) @@ -243,7 +243,7 @@ def eval(self, n, evaluation: Evaluation): def _fractional_part(self, n, expr, evaluation: Evaluation): - n_sympy = n.to_sympy() + n_sympy = to_sympy(n) if n_sympy.is_constant(): if n_sympy >= 0: positive_integer_part = ( @@ -426,7 +426,7 @@ class MantissaExponent(Builtin): def eval(self, n, evaluation: Evaluation): "MantissaExponent[n_]" - n_sympy = n.to_sympy() + n_sympy = to_sympy(n) expr = Expression(SymbolMantissaExponent, n) if isinstance(n.to_python(), complex): @@ -447,7 +447,7 @@ def eval(self, n, evaluation: Evaluation): def eval_with_b(self, n, b, evaluation: Evaluation): "MantissaExponent[n_, b_]" # Handle Input with special cases such as PI and E - n_sympy, b_sympy = n.to_sympy(), b.to_sympy() + n_sympy, b_sympy = to_sympy(n), to_sympy(b) expr = Expression(SymbolMantissaExponent, n, b) @@ -608,11 +608,11 @@ class Prime(SympyFunction): def eval(self, n, evaluation: Evaluation): "Prime[n_]" - return from_sympy(SympyPrime(n.to_sympy())) + return from_sympy(SympyPrime(to_sympy(n))) def to_sympy(self, expr, **kwargs): if expr.has_form("Prime", 1): - return SympyPrime(expr.elements[0].to_sympy(**kwargs)) + return SympyPrime(to_sympy(expr.elements[0], **kwargs)) class PrimePi(SympyFunction): diff --git a/mathics/builtin/numbers/trig.py b/mathics/builtin/numbers/trig.py index 079976d72..0fb87d4c1 100644 --- a/mathics/builtin/numbers/trig.py +++ b/mathics/builtin/numbers/trig.py @@ -18,6 +18,7 @@ from mathics.builtin.base import Builtin from mathics.core.atoms import Integer, Integer0, IntegerM1, Real from mathics.core.convert.python import from_python +from mathics.core.convert.sympy import to_sympy from mathics.core.exceptions import IllegalStepSpecification from mathics.core.expression import Expression from mathics.core.list import ListExpression @@ -442,9 +443,11 @@ class ArcCsc(_MPMathFunction): def to_sympy(self, expr, **kwargs): if len(expr.elements) == 1: - return Expression( - SymbolArcSin, Expression(SymbolPower, expr.elements[0], Integer(-1)) - ).to_sympy() + return to_sympy( + Expression( + SymbolArcSin, Expression(SymbolPower, expr.elements[0], Integer(-1)) + ) + ) class ArcSec(_MPMathFunction): @@ -484,9 +487,11 @@ class ArcSec(_MPMathFunction): def to_sympy(self, expr, **kwargs): if len(expr.elements) == 1: - return Expression( - SymbolArcCos, Expression(SymbolPower, expr.elements[0], IntegerM1) - ).to_sympy() + return to_sympy( + Expression( + SymbolArcCos, Expression(SymbolPower, expr.elements[0], IntegerM1) + ) + ) class ArcSin(_MPMathFunction): @@ -697,9 +702,11 @@ class Csc(_MPMathFunction): def to_sympy(self, expr, **kwargs): if len(expr.elements) == 1: - return Expression( - SymbolPower, Expression(SymbolSin, expr.elements[0]), Integer(-1) - ).to_sympy() + return to_sympy( + Expression( + SymbolPower, Expression(SymbolSin, expr.elements[0]), Integer(-1) + ) + ) class Haversine(_MPMathFunction): @@ -783,9 +790,11 @@ class Sec(_MPMathFunction): def to_sympy(self, expr, **kwargs): if len(expr.elements) == 1: - return Expression( - SymbolPower, Expression(SymbolCos, expr.elements[0]), Integer(-1) - ).to_sympy() + return to_sympy( + Expression( + SymbolPower, Expression(SymbolCos, expr.elements[0]), Integer(-1) + ) + ) class Sin(_MPMathFunction): diff --git a/mathics/builtin/numeric.py b/mathics/builtin/numeric.py index d0bb14222..18f91566d 100644 --- a/mathics/builtin/numeric.py +++ b/mathics/builtin/numeric.py @@ -17,7 +17,7 @@ from mathics.builtin.base import Builtin from mathics.core.atoms import Complex, Integer, Integer0, Rational, Real from mathics.core.attributes import A_LISTABLE, A_NUMERIC_FUNCTION, A_PROTECTED -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.number import MACHINE_EPSILON @@ -309,7 +309,7 @@ class Rationalize(Builtin): def eval(self, x, evaluation: Evaluation): "Rationalize[x_]" - py_x = x.to_sympy() + py_x = to_sympy(x) if py_x is None or (not py_x.is_number) or (not py_x.is_real): return x @@ -351,10 +351,10 @@ def find_exact(x): def eval_dx(self, x, dx, evaluation: Evaluation): "Rationalize[x_, dx_]" - py_x = x.to_sympy() + py_x = to_sympy(x) if py_x is None: return x - py_dx = dx.to_sympy() + py_dx = to_sympy(dx) if ( py_dx is None or (not py_dx.is_number) diff --git a/mathics/builtin/optimization.py b/mathics/builtin/optimization.py index 46d8694f6..d9454e851 100644 --- a/mathics/builtin/optimization.py +++ b/mathics/builtin/optimization.py @@ -22,7 +22,7 @@ from mathics.core.atoms import IntegerM1 from mathics.core.attributes import A_CONSTANT, A_PROTECTED, A_READ_PROTECTED from mathics.core.convert.python import from_python -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.list import ListExpression @@ -60,7 +60,7 @@ class Maximize(Builtin): def eval(self, f, vars, evaluation: Evaluation): "Maximize[f_?NotListQ, vars_]" - dual_f = f.to_sympy() * (-1) + dual_f = to_sympy(f) * (-1) dual_solutions = ( Expression(SymbolMinimize, from_sympy(dual_f), vars) @@ -79,7 +79,7 @@ def eval_constraints(self, f, vars, evaluation: Evaluation): "Maximize[f_List, vars_]" constraints = [function for function in f.elements] - constraints[0] = from_sympy(constraints[0].to_sympy() * IntegerM1) + constraints[0] = from_sympy(to_sympy(constraints[0]) * IntegerM1) dual_solutions = ( Expression(SymbolMinimize, constraints, vars).evaluate(evaluation).elements @@ -121,8 +121,8 @@ class Minimize(Builtin): def eval_onevariable(self, f, x, evaluation: Evaluation): "Minimize[f_?NotListQ, x_?NotListQ]" - sympy_x = x.to_sympy() - sympy_f = f.to_sympy() + sympy_x = to_sympy(x) + sympy_f = to_sympy(f) derivative = sympy.diff(sympy_f, sympy_x) second_derivative = sympy.diff(derivative, sympy_x) @@ -165,8 +165,8 @@ def eval_multiplevariable(self, f, vars, evaluation: Evaluation): evaluation.message("Minimize", "ivar", vars_or) return - vars_sympy = [var.to_sympy() for var in vars] - sympy_f = f.to_sympy() + vars_sympy = [to_sympy(var) for var in vars] + sympy_f = to_sympy(f) jacobian = [sympy.diff(sympy_f, x) for x in vars_sympy] hessian = sympy.Matrix( @@ -242,9 +242,9 @@ def eval_constraints(self, f, vars, evaluation: Evaluation): evaluation.message("Minimize", "ivar", vars_or) return - vars_sympy = [var.to_sympy() for var in vars] + vars_sympy = [to_sympy(var) for var in vars] constraints = [function for function in f.elements] - objective_function = constraints[0].to_sympy() + objective_function = to_sympy(constraints[0]) constraints = constraints[1:] @@ -258,8 +258,8 @@ def eval_constraints(self, f, vars, evaluation: Evaluation): left, right = constraint.elements head_name = constraint.get_head_name() - left = left.to_sympy() - right = right.to_sympy() + left = to_sympy(left) + right = to_sympy(right) if head_name == "System`LessEqual" or head_name == "System`Less": eq = left - right diff --git a/mathics/builtin/quantum_mechanics/angular.py b/mathics/builtin/quantum_mechanics/angular.py index b063c7081..e2bcf9754 100644 --- a/mathics/builtin/quantum_mechanics/angular.py +++ b/mathics/builtin/quantum_mechanics/angular.py @@ -22,7 +22,7 @@ A_READ_PROTECTED, ) from mathics.core.convert.python import from_python -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy from mathics.core.evaluation import Evaluation from mathics.core.list import ListExpression from mathics.core.symbols import Symbol @@ -78,7 +78,7 @@ def eval( for pair in (j1m1, j2m2, jm): if len(pair.elements) != 2: return - sympy_jms += [p.to_sympy() for p in pair.elements] + sympy_jms += [to_sympy(p) for p in pair.elements] return from_sympy(CG(*sympy_jms).doit()) @@ -204,7 +204,7 @@ def eval(self, j13: ListExpression, j46: ListExpression, evaluation: Evaluation) "SixJSymbol", "6jsymbol_symbol", i, triple, element ) return - py_element = element.to_sympy() + py_element = to_sympy(element) sympy_js.append(py_element) try: @@ -288,7 +288,7 @@ def eval( if isinstance(element, Symbol): evaluation.message("ThreeJSymbol", "threejsymbol", i, pair, element) return - py_element = element.to_sympy() + py_element = to_sympy(element) # SymPy wants all of the j's together first and then all of the m's together # rather than pairs if (j, m). sympy_js[j * 3 + i] = py_element diff --git a/mathics/builtin/recurrence.py b/mathics/builtin/recurrence.py index f6c215b26..53d07cd02 100644 --- a/mathics/builtin/recurrence.py +++ b/mathics/builtin/recurrence.py @@ -15,7 +15,7 @@ from mathics.builtin.base import Builtin from mathics.core.atoms import IntegerM1 from mathics.core.attributes import A_CONSTANT -from mathics.core.convert.sympy import from_sympy, sympy_symbol_prefix +from mathics.core.convert.sympy import from_sympy, sympy_symbol_prefix, to_sympy from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.list import ListExpression @@ -119,7 +119,7 @@ def is_relation(eqn): and ri.is_numeric(evaluation) ): - r_sympy = ri.to_sympy() + r_sympy = to_sympy(ri) if r_sympy is None: raise ValueError conditions[le.elements[0].to_python()] = r_sympy @@ -138,7 +138,7 @@ def is_relation(eqn): SymbolPlus, left, Expression(SymbolTimes, IntegerM1, right) ).evaluate(evaluation) - sym_eq = relation.to_sympy(converted_functions={func.get_head_name()}) + sym_eq = to_sympy(relation, converted_functions={func.get_head_name()}) if sym_eq is None: return sym_n = sympy.core.symbols(str(sympy_symbol_prefix + n.name)) diff --git a/mathics/builtin/specialfns/elliptic.py b/mathics/builtin/specialfns/elliptic.py index 928b4bd26..3df9161cb 100644 --- a/mathics/builtin/specialfns/elliptic.py +++ b/mathics/builtin/specialfns/elliptic.py @@ -15,7 +15,7 @@ from mathics.builtin.base import SympyFunction from mathics.core.atoms import Integer from mathics.core.attributes import A_LISTABLE, A_NUMERIC_FUNCTION, A_PROTECTED -from mathics.core.convert.sympy import from_sympy, to_numeric_sympy_args +from mathics.core.convert.sympy import from_sympy, to_numeric_sympy_args, to_sympy from mathics.eval.numerify import numerify @@ -61,7 +61,7 @@ def eval_default(self, args, evaluation): def eval_m(self, m, evaluation): "%(name)s[m_]" - sympy_arg = numerify(m, evaluation).to_sympy() + sympy_arg = to_sympy(numerify(m, evaluation)) try: return from_sympy(sympy.elliptic_e(sympy_arg)) except Exception: @@ -69,7 +69,7 @@ def eval_m(self, m, evaluation): def eval_phi_m(self, phi, m, evaluation): "%(name)s[phi_, m_]" - sympy_args = [numerify(a, evaluation).to_sympy() for a in (phi, m)] + sympy_args = [to_sympy(numerify(a, evaluation)) for a in (phi, m)] try: return from_sympy(sympy.elliptic_e(*sympy_args)) except Exception: @@ -115,7 +115,7 @@ def eval_default(self, args, evaluation): def eval(self, phi, m, evaluation): "%(name)s[phi_, m_]" - sympy_args = [numerify(a, evaluation).to_sympy() for a in (phi, m)] + sympy_args = [to_sympy(numerify(a, evaluation)) for a in (phi, m)] try: return from_sympy(sympy.elliptic_f(*sympy_args)) except Exception: @@ -162,7 +162,7 @@ def eval_default(self, args, evaluation): def eval(self, m, evaluation): "%(name)s[m_]" args = numerify(m, evaluation).get_sequence() - sympy_args = [a.to_sympy() for a in args] + sympy_args = [to_sympy(a) for a in args] try: return from_sympy(sympy.elliptic_k(*sympy_args)) except Exception: diff --git a/mathics/builtin/specialfns/gamma.py b/mathics/builtin/specialfns/gamma.py index e441b8a57..752acf7b3 100644 --- a/mathics/builtin/specialfns/gamma.py +++ b/mathics/builtin/specialfns/gamma.py @@ -12,7 +12,7 @@ from mathics.core.attributes import A_LISTABLE, A_NUMERIC_FUNCTION, A_PROTECTED from mathics.core.convert.mpmath import from_mpmath from mathics.core.convert.python import from_python -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy from mathics.core.expression import Expression from mathics.core.number import FP_MANTISA_BINARY_DIGITS, dps, min_prec from mathics.core.symbols import Symbol, SymbolSequence @@ -229,7 +229,7 @@ def fact2_generic(x): convert_from_fn = from_mpmath fact2_fn = getattr(mpmath, self.mpmath_name) elif preference == "sympy": - number_arg = number.to_sympy() + number_arg = to_sympy(number) convert_from_fn = from_sympy fact2_fn = getattr(sympy, self.sympy_name) else: diff --git a/mathics/builtin/testing_expressions/equality_inequality.py b/mathics/builtin/testing_expressions/equality_inequality.py index 59152e31e..e99456001 100644 --- a/mathics/builtin/testing_expressions/equality_inequality.py +++ b/mathics/builtin/testing_expressions/equality_inequality.py @@ -18,6 +18,7 @@ A_PROTECTED, ) from mathics.core.convert.expression import to_expression, to_numeric_args +from mathics.core.convert.sympy import to_sympy from mathics.core.expression import Expression from mathics.core.expression_predefined import ( MATHICS3_COMPLEX_INFINITY, @@ -154,8 +155,8 @@ def infty_equal(self, lhs, rhs, max_extra_prec=None) -> Optional[bool]: def sympy_equal(self, lhs, rhs, max_extra_prec=None) -> Optional[bool]: try: - lhs_sympy = lhs.to_sympy(evaluate=True, prec=COMPARE_PREC) - rhs_sympy = rhs.to_sympy(evaluate=True, prec=COMPARE_PREC) + lhs_sympy = to_sympy(lhs, evaluate=True, prec=COMPARE_PREC) + rhs_sympy = to_sympy(rhs, evaluate=True, prec=COMPARE_PREC) except NotImplementedError: return None diff --git a/mathics/builtin/testing_expressions/numerical_properties.py b/mathics/builtin/testing_expressions/numerical_properties.py index 5f5822f9e..2199d0356 100644 --- a/mathics/builtin/testing_expressions/numerical_properties.py +++ b/mathics/builtin/testing_expressions/numerical_properties.py @@ -9,6 +9,7 @@ from mathics.core.atoms import Integer, Integer0, Number from mathics.core.attributes import A_LISTABLE, A_NUMERIC_FUNCTION, A_PROTECTED from mathics.core.convert.python import from_bool, from_python +from mathics.core.convert.sympy import to_sympy from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.symbols import BooleanType, SymbolFalse, SymbolTrue @@ -465,12 +466,12 @@ def eval(self, expr, evaluation): if test_zero_arithmetic_expr(expr): return SymbolTrue - sympy_expr = expr.to_sympy() + sympy_expr = to_sympy(expr) result = _iszero(sympy_expr) if result is None: # try expanding the expression exprexp = Expression(SymbolExpandAll, expr).evaluate(evaluation) - exprexp = exprexp.to_sympy() + exprexp = to_sympy(exprexp) result = _iszero(exprexp) if result is None: # Can't get exact answer, so try approximate equal diff --git a/mathics/core/convert/matrix.py b/mathics/core/convert/matrix.py index e60e7f965..fd44e4f3a 100644 --- a/mathics/core/convert/matrix.py +++ b/mathics/core/convert/matrix.py @@ -4,13 +4,15 @@ def matrix_data(m): + from mathics.core.convert.sympy import to_sympy + if not m.has_form("List", None): return None if all(element.has_form("List", None) for element in m.elements): - result = [[item.to_sympy() for item in row.elements] for row in m.elements] + result = [[to_sympy(item) for item in row.elements] for row in m.elements] if not any(None in row for row in result): return result elif not any(element.has_form("List", None) for element in m.elements): - result = [item.to_sympy() for item in m.elements] + result = [to_sympy(item) for item in m.elements] if None not in result: return result diff --git a/mathics/core/convert/sympy.py b/mathics/core/convert/sympy.py index 843d679f3..f9aeee632 100644 --- a/mathics/core/convert/sympy.py +++ b/mathics/core/convert/sympy.py @@ -118,6 +118,15 @@ def is_Cn_expr(name) -> bool: return False +def to_sympy(expr, **kwargs): + if hasattr(expr, "to_sympy"): + return expr.to_sympy(**kwargs) + if isinstance(expr, Symbol): + return symbol_to_sympy(expr, **kwargs) + if isinstance(expr, Expression): + return expression_to_sympy(expr, **kwargs) + + def to_sympy_matrix(data, **kwargs) -> Optional[sympy.MutableDenseMatrix]: """Convert a Mathics matrix to one that can be used by Sympy. None is returned if we can't convert to a Sympy matrix. @@ -144,8 +153,8 @@ def __new__(cls, *exprs): elif len(exprs) == 1 and isinstance(exprs[0], Expression): # called with Mathics argument expr = exprs[0] - sympy_head = expr.head.to_sympy() - sympy_elements = [element.to_sympy() for element in expr.elements] + sympy_head = to_sympy(expr.head) + sympy_elements = [to_sympy(element) for element in expr.elements] if sympy_head is None or None in sympy_elements: return None obj = BasicSympy.__new__(cls, sympy_head, *sympy_elements) @@ -219,15 +228,24 @@ def expression_to_sympy(expr: Expression, **kwargs): Convert `expr` to its sympy form. """ + def as_sympy_function(expr, **kwargs) -> Optional[sympy.Function]: + sym_args = [to_sympy(element, **kwargs) for element in expr._elements] + + if None in sym_args: + return None + + f = sympy.Function(str(sympy_symbol_prefix + expr.get_head_name())) + return f(*sym_args) + if "convert_all_global_functions" in kwargs: if len(expr.elements) > 0 and kwargs["convert_all_global_functions"]: if expr.get_head_name().startswith("Global`"): - return expr._as_sympy_function(**kwargs) + return as_sympy_function(expr, **kwargs) if "converted_functions" in kwargs: functions = kwargs["converted_functions"] if len(expr._elements) > 0 and expr.get_head_name() in functions: - sym_args = [element.to_sympy() for element in expr._elements] + sym_args = [to_sympy(element) for element in expr._elements] if None in sym_args: return None func = sympy.Function(str(sympy_symbol_prefix + expr.get_head_name()))( @@ -276,7 +294,7 @@ def to_numeric_sympy_args(mathics_args: Type[BaseElement], evaluation) -> list: sympy_args = [mathics_args.value] else: args = numerify(mathics_args, evaluation).get_sequence() - sympy_args = [a.to_sympy() for a in args] + sympy_args = [to_sympy(a) for a in args] return sympy_args diff --git a/mathics/core/element.py b/mathics/core/element.py index 23b6ba8c7..db35c1113 100644 --- a/mathics/core/element.py +++ b/mathics/core/element.py @@ -425,9 +425,6 @@ def to_python(self, *args, **kwargs): def to_mpmath(self): raise NotImplementedError - def to_sympy(self, **kwargs): - raise NotImplementedError - class EvalMixin: """ diff --git a/mathics/core/expression.py b/mathics/core/expression.py index 098e385a0..e2c59082c 100644 --- a/mathics/core/expression.py +++ b/mathics/core/expression.py @@ -251,17 +251,6 @@ def __str__(self) -> str: ", ".join([str(element) for element in self.elements]), ) - def _as_sympy_function(self, **kwargs) -> Optional[sympy.Function]: - from mathics.core.convert.sympy import sympy_symbol_prefix - - sym_args = [element.to_sympy(**kwargs) for element in self._elements] - - if None in sym_args: - return None - - f = sympy.Function(str(sympy_symbol_prefix + self.get_head_name())) - return f(*sym_args) - # Note: this function is called a *lot* so it needs to be fast. def _build_elements_properties(self): """ @@ -1497,11 +1486,6 @@ def to_python(self, *args, **kwargs): # instead of a builtin native object. return self - def to_sympy(self, **kwargs): - from mathics.core.convert.sympy import expression_to_sympy - - return expression_to_sympy(self, **kwargs) - def process_style_box(self, options): if self.has_form("StyleBox", 1, None): rules = self._elements[1:] diff --git a/mathics/core/symbols.py b/mathics/core/symbols.py index adfe063e9..41f842ddd 100644 --- a/mathics/core/symbols.py +++ b/mathics/core/symbols.py @@ -621,11 +621,6 @@ def to_python(self, *args, python_form: bool = False, **kwargs): # dictionaries. return self.name - def to_sympy(self, **kwargs): - from mathics.core.convert.sympy import symbol_to_sympy - - return symbol_to_sympy(self, **kwargs) - class SymbolConstant(Symbol): """ diff --git a/mathics/eval/arithmetic.py b/mathics/eval/arithmetic.py index 035dff801..84b3ab86d 100644 --- a/mathics/eval/arithmetic.py +++ b/mathics/eval/arithmetic.py @@ -27,7 +27,7 @@ Real, ) from mathics.core.convert.mpmath import from_mpmath -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy from mathics.core.element import BaseElement, ElementsProperties from mathics.core.expression import Expression from mathics.core.number import FP_MANTISA_BINARY_DIGITS, SpecialValueError, min_prec @@ -152,7 +152,7 @@ def eval_Exp(exp: BaseElement) -> BaseElement: # use sympy. if not exp.is_inexact(): - exp_sp = exp.to_sympy() + exp_sp = to_sympy(exp) if exp_sp is None: return None return from_sympy(sympy.Exp(exp_sp)) @@ -377,7 +377,7 @@ def append_last(): if item.has_form("Times", None): for element in item.elements: if isinstance(element, Number): - count = element.to_sympy() + count = to_sympy(element) rest = item.get_mutable_elements() rest.remove(element) if len(rest) == 1: @@ -442,7 +442,7 @@ def eval_Power_sympy() -> Optional[Number]: """ # This function is called just if useful native rules # are available. - result = from_sympy(sympy.Pow(base.to_sympy(), exp.to_sympy())) + result = from_sympy(sympy.Pow(to_sympy(base), to_sympy(exp))) if result.has_form("Power", 2): # If the expression didnĀ“t change, return None if result.elements[0].sameQ(base): @@ -670,7 +670,7 @@ def eval_add_numbers( number = mpmath.fsum(terms) return from_mpmath(number, precision=prec) else: - return from_sympy(sum(item.to_sympy() for item in numbers)) + return from_sympy(sum(to_sympy(item) for item in numbers)) def eval_inverse_number(n: Number) -> Number: @@ -715,7 +715,7 @@ def eval_multiply_numbers(*numbers: Number) -> Number: number = mpmath.fprod(factors) return from_mpmath(number, prec) else: - return from_sympy(sympy.Mul(*(item.to_sympy() for item in numbers))) + return from_sympy(sympy.Mul(*(to_sympy(item) for item in numbers))) def eval_negate_number(n: Number) -> Number: diff --git a/mathics/eval/hyperbolic.py b/mathics/eval/hyperbolic.py index 832a9ca53..ff7cb78bd 100644 --- a/mathics/eval/hyperbolic.py +++ b/mathics/eval/hyperbolic.py @@ -3,15 +3,15 @@ """ from sympy import Symbol as SympySymbol -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy def eval_ComplexExpand(expr, vars): - sympy_expr = expr.to_sympy() + sympy_expr = to_sympy(expr) if hasattr(vars, "elements"): - sympy_vars = {v.to_sympy() for v in vars.elements} + sympy_vars = {to_sympy(v) for v in vars.elements} else: - sympy_vars = {vars.to_sympy()} + sympy_vars = {to_sympy(vars)} # All vars are assumed to be real replaces = [ (fs, SympySymbol(fs.name, real=True)) diff --git a/mathics/eval/math_ops.py b/mathics/eval/math_ops.py index 9fd133a3e..0d491df4e 100644 --- a/mathics/eval/math_ops.py +++ b/mathics/eval/math_ops.py @@ -1,7 +1,7 @@ from typing import Callable, Optional from mathics.core.atoms import Integer, Real, String -from mathics.core.convert.sympy import from_sympy, to_sympy_matrix +from mathics.core.convert.sympy import from_sympy, to_sympy, to_sympy_matrix from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.symbols import Symbol @@ -29,13 +29,13 @@ def eval_Norm_p( Norm[m, p] evaluation function - the p-norm of matrix m. """ if isinstance(p, Symbol): - sympy_p = p.to_sympy() + sympy_p = to_sympy(p) elif isinstance(p, String): sympy_p = p.value if sympy_p == "Frobenius": sympy_p = "fro" elif isinstance(p, (Real, Integer)) and p.to_python() >= 1: - sympy_p = p.to_sympy() + sympy_p = to_sympy(p) else: if show_message: show_message("Norm", "ptype", p) diff --git a/mathics/eval/numbers.py b/mathics/eval/numbers.py index 7389ac8d3..b8d24e014 100644 --- a/mathics/eval/numbers.py +++ b/mathics/eval/numbers.py @@ -4,7 +4,7 @@ import sympy from mathics.core.atoms import Complex, MachineReal, PrecisionReal -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy from mathics.core.element import BaseElement from mathics.core.expression import Expression from mathics.core.number import MACHINE_PRECISION_VALUE, ZERO_MACHINE_ACCURACY, dps @@ -115,7 +115,7 @@ def cancel(expr): return Expression(SymbolPlus, *[cancel(element) for element in expr.elements]) else: try: - result = expr.to_sympy() + result = to_sympy(expr) if result is None: return None diff --git a/mathics/eval/testing_expressions.py b/mathics/eval/testing_expressions.py index 4046d0c8c..faae44136 100644 --- a/mathics/eval/testing_expressions.py +++ b/mathics/eval/testing_expressions.py @@ -3,6 +3,7 @@ import sympy from mathics.core.atoms import Complex, Integer0, Integer1, IntegerM1 +from mathics.core.convert.sympy import to_sympy from mathics.core.expression import Expression from mathics.core.systemsymbols import SymbolDirectedInfinity @@ -17,8 +18,8 @@ def do_cmp(x1, x2) -> Optional[int]: ): return None - s1 = x1.to_sympy() - s2 = x2.to_sympy() + s1 = to_sympy(x1) + s2 = to_sympy(x2) # Use internal comparisons only for Real which is uses # WL's interpretation of equal (which allows for slop diff --git a/test/core/convert/test_sympy.py b/test/core/convert/test_sympy.py index 319274366..26c1eb08c 100644 --- a/test/core/convert/test_sympy.py +++ b/test/core/convert/test_sympy.py @@ -19,7 +19,7 @@ Real, String, ) -from mathics.core.convert.sympy import from_sympy, sympy_singleton_to_mathics +from mathics.core.convert.sympy import from_sympy, sympy_singleton_to_mathics, to_sympy from mathics.core.expression import Expression from mathics.core.expression_predefined import ( MATHICS3_COMPLEX_INFINITY, @@ -78,7 +78,7 @@ def test_from_to_sympy_invariant(expr): """ Check if the conversion back and forward is consistent. """ - result_sympy = expr.to_sympy() + result_sympy = to_sympy(expr) back_to_mathics = from_sympy(result_sympy) print([expr, result_sympy, back_to_mathics]) assert expr.sameQ(back_to_mathics) @@ -122,9 +122,9 @@ def test_from_to_sympy_change(expr, result, msg): """ print([expr, result]) if msg: - assert result.sameQ(from_sympy(expr.to_sympy())), msg + assert result.sameQ(from_sympy(to_sympy(expr))), msg else: - assert result.sameQ(from_sympy(expr.to_sympy())) + assert result.sameQ(from_sympy(to_sympy(expr))) def test_convert_sympy_singletons(): @@ -139,6 +139,6 @@ def test_convert_sympy_singletons(): print(" -> ", res) assert from_sympy(key).sameQ(val) - res = val.to_sympy() + res = to_sympy(val) print(res, " <- ") assert res is key diff --git a/test/core/test_sympy_python_convert.py b/test/core/test_sympy_python_convert.py index 1cfa65d6f..9f20b3e8b 100644 --- a/test/core/test_sympy_python_convert.py +++ b/test/core/test_sympy_python_convert.py @@ -17,7 +17,7 @@ String, ) from mathics.core.convert.python import from_python -from mathics.core.convert.sympy import from_sympy +from mathics.core.convert.sympy import from_sympy, to_sympy from mathics.core.expression import Expression from mathics.core.list import ListExpression from mathics.core.symbols import Symbol, SymbolPlus @@ -32,7 +32,7 @@ class SympyConvert(unittest.TestCase): def compare_to_sympy(self, mathics_expr, sympy_expr, **kwargs): - mathics_expr.to_sympy(**kwargs) == sympy_expr + to_sympy(mathics_expr, **kwargs) == sympy_expr def compare_to_mathics(self, mathics_expr, sympy_expr, **kwargs): mathics_expr == from_sympy(sympy_expr, **kwargs) @@ -76,7 +76,7 @@ def testComplex(self): ) def testString(self): - String("abc").to_sympy() is None + to_sympy(String("abc")) is None def testAdd(self): self.compare(