diff --git a/mathics/eval/arithmetic.py b/mathics/eval/arithmetic.py index 93501af17..8c25a9dc7 100644 --- a/mathics/eval/arithmetic.py +++ b/mathics/eval/arithmetic.py @@ -463,301 +463,6 @@ def append_last(): elements_properties=ElementsProperties(False, False, True), ) - elements.sort() - return Expression( - SymbolPlus, - *elements, - elements_properties=ElementsProperties(False, False, True), - ) - - -def eval_Power_number(base: Number, exp: Number) -> Optional[Number]: - """ - Eval base^exp for `base` and `exp` two numbers. If the expression - remains the same, return None. - """ - # If both base and exponent are exact quantities, - # use sympy. - # If base or exp are inexact quantities, use - # the inexact routine. - if base.is_inexact() or exp.is_inexact(): - return eval_Power_inexact(base, exp) - - # Trivial special cases - if exp is Integer1: - return base - if exp is Integer0: - return Integer1 - if base is Integer1: - return Integer1 - - def eval_Power_sympy() -> Optional[Number]: - """ - Tries to compute x^p using sympy rules. - If the answer is again x^p, return None. - """ - # This function is called just if useful native rules - # are available. - result = from_sympy(sympy.Pow(base.to_sympy(), exp.to_sympy())) - if result.has_form("Power", 2): - # If the expression didn´t change, return None - if result.elements[0].sameQ(base): - return None - return result - - # Rational exponent - if isinstance(exp, Rational): - exp_p, exp_q = exp.value.as_numer_denom() - if abs(exp_p) > exp_q: - exp_int, exp_num = divmod(exp_p, exp_q) - exp_rem = Rational(exp_num, exp_q) - factor_1 = eval_Power_number(base, Integer(exp_int)) - factor_2 = eval_Power_number(base, exp_rem) or Expression( - SymbolPower, base, exp_rem - ) - if factor_1 is Integer1: - return factor_2 - return Expression(SymbolTimes, factor_1, factor_2) - - # Integer base - if isinstance(base, Integer): - base_value = base.value - if base_value == -1: - if isinstance(exp, Rational): - if exp.sameQ(RationalOneHalf): - return SymbolI - return None - return eval_Power_sympy() - elif base_value < 0: - neg_base = eval_negate_number(base) - candidate = eval_Power_number(neg_base, exp) - if candidate is None: - return None - sign_factor = eval_Power_number(IntegerM1, exp) - if candidate is Integer1: - return sign_factor - return Expression(SymbolTimes, candidate, sign_factor) - - # Rational base - if isinstance(base, Rational): - # If the exponent is an Integer or Rational negative value - # restate as a positive power - if ( - isinstance(exp, Integer) - and exp.value < 0 - or isinstance(exp, Rational) - and exp.value.p < 0 - ): - base, exp = eval_inverse_number(base), eval_negate_number(exp) - return eval_Power_number(base, exp) or Expression(SymbolPower, base, exp) - - p, q = (Integer(u) for u in base.value.as_numer_denom()) - p_eval, q_eval = (eval_Power_number(u, exp) for u in (p, q)) - # If neither p^exp or q^exp produced a new result, - # leave it alone - if q_eval is None and p_eval is None: - return None - # if q^exp == 1: return p_eval - # (should not happen) - if q_eval is Integer1: - return p_eval - if isinstance(q_eval, Integer): - if isinstance(p_eval, Integer): - return Rational(p_eval.value, q_eval.value) - - if p_eval is None: - p_eval = Expression(SymbolPower, p, exp) - - if q_eval is None: - q_eval = Expression(SymbolPower, q, exp) - return Expression( - SymbolTimes, p_eval, Expression(SymbolPower, q_eval, IntegerM1) - ) - # Pure imaginary base case - elif isinstance(base, Complex) and base.real.is_zero: - base = base.imag - if base.value < 0: - base = eval_negate_number(base) - phase = Expression( - SymbolPower, - IntegerM1, - eval_multiply_numbers(IntegerM1, RationalOneHalf, exp), - ) - else: - phase = Expression( - SymbolPower, IntegerM1, eval_multiply_numbers(RationalOneHalf, exp) - ) - real_factor = eval_Power_number(base, exp) - - if real_factor is None: - return None - return Expression(SymbolTimes, real_factor, phase) - - # Generic case - return eval_Power_sympy() - - -def eval_Power_inexact(base: Number, exp: Number) -> BaseElement: - """ - Eval base^exp for `base` and `exp` inexact numbers - """ - # If both base and exponent are exact quantities, - # use sympy. - prec = min_prec(base, exp) - if prec is not None: - is_machine_precision = base.is_machine_precision() or exp.is_machine_precision() - if is_machine_precision: - number = mpmath.power(base.to_mpmath(), exp.to_mpmath()) - return from_mpmath(number) - else: - with mpmath.workprec(prec): - number = mpmath.power(base.to_mpmath(), exp.to_mpmath()) - return from_mpmath(number, prec) - - -def eval_Power_number(base: Number, exp: Number) -> Optional[Number]: - """ - Eval base^exp for `base` and `exp` two numbers. If the expression - remains the same, return None. - """ - # If both base and exponent are exact quantities, - # use sympy. - # If base or exp are inexact quantities, use - # the inexact routine. - if base.is_inexact() or exp.is_inexact(): - return eval_Power_inexact(base, exp) - - # Trivial special cases - if exp is Integer1: - return base - if exp is Integer0: - return Integer1 - if base is Integer1: - return Integer1 - - def eval_Power_sympy() -> Optional[Number]: - """ - Tries to compute x^p using sympy rules. - If the answer is again x^p, return None. - """ - # This function is called just if useful native rules - # are available. - result = from_sympy(sympy.Pow(base.to_sympy(), exp.to_sympy())) - if result.has_form("Power", 2): - # If the expression didn´t change, return None - if result.elements[0].sameQ(base): - return None - return result - - # Rational exponent - if isinstance(exp, Rational): - exp_p, exp_q = exp.value.as_numer_denom() - if abs(exp_p) > exp_q: - exp_int, exp_num = divmod(exp_p, exp_q) - exp_rem = Rational(exp_num, exp_q) - factor_1 = eval_Power_number(base, Integer(exp_int)) - factor_2 = eval_Power_number(base, exp_rem) or Expression( - SymbolPower, base, exp_rem - ) - if factor_1 is Integer1: - return factor_2 - return Expression(SymbolTimes, factor_1, factor_2) - - # Integer base - if isinstance(base, Integer): - base_value = base.value - if base_value == -1: - if isinstance(exp, Rational): - if exp.sameQ(RationalOneHalf): - return SymbolI - return None - return eval_Power_sympy() - elif base_value < 0: - neg_base = eval_negate_number(base) - candidate = eval_Power_number(neg_base, exp) - if candidate is None: - return None - sign_factor = eval_Power_number(IntegerM1, exp) - if candidate is Integer1: - return sign_factor - return Expression(SymbolTimes, candidate, sign_factor) - - # Rational base - if isinstance(base, Rational): - # If the exponent is an Integer or Rational negative value - # restate as a positive power - if ( - isinstance(exp, Integer) - and exp.value < 0 - or isinstance(exp, Rational) - and exp.value.p < 0 - ): - base, exp = eval_inverse_number(base), eval_negate_number(exp) - return eval_Power_number(base, exp) or Expression(SymbolPower, base, exp) - - p, q = (Integer(u) for u in base.value.as_numer_denom()) - p_eval, q_eval = (eval_Power_number(u, exp) for u in (p, q)) - # If neither p^exp or q^exp produced a new result, - # leave it alone - if q_eval is None and p_eval is None: - return None - # if q^exp == 1: return p_eval - # (should not happen) - if q_eval is Integer1: - return p_eval - if isinstance(q_eval, Integer): - if isinstance(p_eval, Integer): - return Rational(p_eval.value, q_eval.value) - - if p_eval is None: - p_eval = Expression(SymbolPower, p, exp) - - if q_eval is None: - q_eval = Expression(SymbolPower, q, exp) - return Expression( - SymbolTimes, p_eval, Expression(SymbolPower, q_eval, IntegerM1) - ) - # Pure imaginary base case - elif isinstance(base, Complex) and base.real.is_zero: - base = base.imag - if base.value < 0: - base = eval_negate_number(base) - phase = Expression( - SymbolPower, - IntegerM1, - eval_multiply_numbers(IntegerM1, RationalOneHalf, exp), - ) - else: - phase = Expression( - SymbolPower, IntegerM1, eval_multiply_numbers(RationalOneHalf, exp) - ) - real_factor = eval_Power_number(base, exp) - - if real_factor is None: - return None - return Expression(SymbolTimes, real_factor, phase) - - # Generic case - return eval_Power_sympy() - - -def eval_Power_inexact(base: Number, exp: Number) -> BaseElement: - """ - Eval base^exp for `base` and `exp` inexact numbers - """ - # If both base and exponent are exact quantities, - # use sympy. - prec = min_prec(base, exp) - if prec is not None: - is_machine_precision = base.is_machine_precision() or exp.is_machine_precision() - if is_machine_precision: - number = mpmath.power(base.to_mpmath(), exp.to_mpmath()) - return from_mpmath(number) - else: - with mpmath.workprec(prec): - number = mpmath.power(base.to_mpmath(), exp.to_mpmath()) - return from_mpmath(number, prec) - def eval_Power_number(base: Number, exp: Number) -> Optional[Number]: """