From 826b727a07dd9b64c7b04b6b9d2cabfdd2499e6d Mon Sep 17 00:00:00 2001 From: mmatera Date: Sun, 25 Apr 2021 11:45:02 -0300 Subject: [PATCH 1/2] fixing and improving Expand and ExpandAll --- CHANGES.rst | 7 +- mathics/builtin/algebra.py | 200 +++++++++++++++++++++++++++------- mathics/builtin/arithmetic.py | 1 + mathics/core/expression.py | 2 +- 4 files changed, 169 insertions(+), 41 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 126cdb7c54..eeea0cce2b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -22,6 +22,8 @@ Enhancements * ``ColorNegate`` for colors is supported. * ``D`` and ``Derivative`` improvements. +* ``Expand`` and ``ExpandAll`` now support a second parameter ``patt`` (#1301) +* ``Expand`` and ``ExpandAll`` works with hyperbolic functions (`Sinh`, `Cosh`, `Tanh`, `Coth`) * ``FileNames`` returns a sorted list (#1250). * ``FindRoot`` now receives several optional parameters like ``Method`` and ``MaxIterations``. * ``FixedPoint`` now supports the ``SameTest`` option. @@ -29,8 +31,9 @@ Enhancements * ``StringTake`` now accepts form containing a list of strings and specification (#1297). * ``Table`` [*expr*, *n*] is supported. * ``ToString`` accepts an optional *form* parameter. -* ``ToExpression`` handles multi-line string input -* The implementation of Streams was redone. +* ``ToExpression`` handles multi-line string input. +* The implementation of Streams was redone. + Bug fixes +++++++++ diff --git a/mathics/builtin/algebra.py b/mathics/builtin/algebra.py index 81929074dc..da64f48b41 100644 --- a/mathics/builtin/algebra.py +++ b/mathics/builtin/algebra.py @@ -10,6 +10,7 @@ Atom, Expression, Integer, + Integer0, Integer1, Number, Symbol, @@ -18,6 +19,7 @@ SymbolTrue, ) from mathics.core.convert import from_sympy, sympy_symbol_prefix +from mathics.core.rules import Pattern import sympy @@ -61,49 +63,104 @@ def _expand(expr): return expand(expr, numer=numer, denom=denom, deep=deep, **kwargs) if kwargs["modulus"] is not None and kwargs["modulus"] <= 0: - return Integer(0) + return Integer0 + target_pat = kwargs.get("pattern", None) + if target_pat: + evaluation = kwargs["evaluation"] # A special case for trigonometric functions if "trig" in kwargs and kwargs["trig"]: - if expr.has_form("Sin", 1): + if expr.has_form( + ("Sin", "Cos", "Tan", "Cot", "Sinh", "Cosh", "Tanh", "Coth"), 1 + ): + head = expr.get_head() theta = expr.leaves[0] + if (target_pat is not None) and theta.is_free(target_pat, evaluation): + return expr + if deep: + theta = _expand(theta) if theta.has_form("Plus", 2, None): x, y = theta.leaves[0], Expression("Plus", *theta.leaves[1:]) + if head == Symbol("Sin"): + a = Expression( + "Times", + _expand(Expression("Sin", x)), + _expand(Expression("Cos", y)), + ) - a = Expression( - "Times", - _expand(Expression("Sin", x)), - _expand(Expression("Cos", y)), - ) - - b = Expression( - "Times", - _expand(Expression("Cos", x)), - _expand(Expression("Sin", y)), - ) + b = Expression( + "Times", + _expand(Expression("Cos", x)), + _expand(Expression("Sin", y)), + ) + return _expand(Expression("Plus", a, b)) + elif head == Symbol("Cos"): + a = Expression( + "Times", + _expand(Expression("Cos", x)), + _expand(Expression("Cos", y)), + ) - return Expression("Plus", a, b) + b = Expression( + "Times", + _expand(Expression("Sin", x)), + _expand(Expression("Sin", y)), + ) - elif expr.has_form("Cos", 1): - theta = expr.leaves[0] + return _expand(Expression("Plus", a, -b)) + elif head == Symbol("Sinh"): + a = Expression( + "Times", + _expand(Expression("Sinh", x)), + _expand(Expression("Cosh", y)), + ) - if theta.has_form("Plus", 2, None): - x, y = theta.leaves[0], Expression("Plus", *theta.leaves[1:]) + b = Expression( + "Times", + _expand(Expression("Cosh", x)), + _expand(Expression("Sinh", y)), + ) - a = Expression( - "Times", - _expand(Expression("Cos", x)), - _expand(Expression("Cos", y)), - ) + return _expand(Expression("Plus", a, b)) + elif head == Symbol("Cosh"): + a = Expression( + "Times", + _expand(Expression("Cosh", x)), + _expand(Expression("Cosh", y)), + ) - b = Expression( - "Times", - _expand(Expression("Sin", x)), - _expand(Expression("Sin", y)), - ) + b = Expression( + "Times", + _expand(Expression("Sinh", x)), + _expand(Expression("Sinh", y)), + ) - return Expression("Plus", a, -b) + return _expand(Expression("Plus", a, b)) + elif head == Symbol("Tan"): + a = _expand(Expression("Sin", theta)) + b = Expression( + "Power", _expand(Expression("Cos", theta)), Integer(-1) + ) + return _expand(Expression("Times", a, b)) + elif head == Symbol("Cot"): + a = _expand(Expression("Cos", theta)) + b = Expression( + "Power", _expand(Expression("Sin", theta)), Integer(-1) + ) + return _expand(Expression("Times", a, b)) + elif head == Symbol("Tanh"): + a = _expand(Expression("Sinh", theta)) + b = Expression( + "Power", _expand(Expression("Cosh", theta)), Integer(-1) + ) + return _expand(Expression("Times", a, b)) + elif head == Symbol("Coth"): + a = _expand(Expression("Times", "Cosh", theta)) + b = Expression( + "Power", _expand(Expression("Sinh", theta)), Integer(-1) + ) + return _expand(Expression(a, b)) sub_exprs = [] @@ -123,6 +180,9 @@ def convert_sympy(expr): leaves = expr.get_leaves() if isinstance(expr, Integer): return sympy.Integer(expr.get_int_value()) + if target_pat is not None and not isinstance(expr, Number): + if expr.is_free(target_pat, evaluation): + return store_sub_expr(expr) if expr.has_form("Power", 2): # sympy won't expand `(a + b) / x` to `a / x + b / x` if denom is False # if denom is False we store negative powers to prevent this. @@ -156,7 +216,13 @@ def unconvert_subexprs(expr): if not sub_expr.is_atom(): head = _expand(sub_expr.head) # also expand head leaves = sub_expr.get_leaves() - leaves = [_expand(leaf) for leaf in leaves] + if target_pat: + leaves = [ + leaf if leaf.is_free(target_pat, evaluation) else _expand(leaf) + for leaf in leaves + ] + else: + leaves = [_expand(leaf) for leaf in leaves] sub_exprs[i] = Expression(head, *leaves) else: # thread over Lists etc. @@ -165,7 +231,15 @@ def unconvert_subexprs(expr): for head in threaded_heads: if sub_expr.has_form(head, None): leaves = sub_expr.get_leaves() - leaves = [_expand(leaf) for leaf in leaves] + if target_pat: + leaves = [ + leaf + if leaf.is_free(target_pat, evaluation) + else _expand(leaf) + for leaf in leaves + ] + else: + leaves = [_expand(leaf) for leaf in leaves] sub_exprs[i] = Expression(head, *leaves) break @@ -494,8 +568,8 @@ class FactorTermsList(Builtin): def apply_list(self, expr, vars, evaluation): "FactorTermsList[expr_, vars_List]" - if expr == Integer(0): - return Expression("List", Integer1, Integer(0)) + if expr == Integer0: + return Expression("List", Integer1, Integer0) elif isinstance(expr, Number): return Expression("List", expr, Integer1) @@ -657,6 +731,8 @@ class Expand(_Expand):
'Expand[$expr$]'
expands out positive integer powers and products of sums in $expr$, as well as trigonometric identities. +
Expand[$expr$, $target$] +
just expands those parts involving $target$. >> Expand[(x + y) ^ 3] @@ -679,11 +755,17 @@ class Expand(_Expand): 'Expand' expands trigonometric identities >> Expand[Sin[x + y], Trig -> True] = Cos[x] Sin[y] + Cos[y] Sin[x] + >> Expand[Tanh[x + y], Trig -> True] + = Cosh[x] Sinh[y] / (Cosh[x] Cosh[y] + Sinh[x] Sinh[y]) + Cosh[y] Sinh[x] / (Cosh[x] Cosh[y] + Sinh[x] Sinh[y]) 'Expand' does not change any other expression. >> Expand[Sin[x (1 + y)]] = Sin[x (1 + y)] + Using the second argument, the expression only + expands those subexpressions containing $pat$: + >> Expand[(x+a)^2+(y+a)^2+(x+y)(x+a), y] + = a ^ 2 + 2 a y + x (a + x) + y (a + x) + y ^ 2 + (a + x) ^ 2 'Expand' also works in Galois fields >> Expand[(1 + a)^12, Modulus -> 3] = 1 + a ^ 3 + a ^ 9 + a ^ 12 @@ -703,11 +785,28 @@ class Expand(_Expand): #> (y^2)^(1/2)/(2x+2y)//Expand = Sqrt[y ^ 2] / (2 x + 2 y) - ## This caused a program crash! + #> 2(3+2x)^2/(5+x^2+3x)^3 // Expand = 24 x / (5 + 3 x + x ^ 2) ^ 3 + 8 x ^ 2 / (5 + 3 x + x ^ 2) ^ 3 + 18 / (5 + 3 x + x ^ 2) ^ 3 """ + def apply_patt(self, expr, target, evaluation, options): + "Expand[expr_, target_, OptionsPattern[Expand]]" + + if target.get_head_name() in ("System`Rule", "System`DelayedRule"): + optname = target.leaves[0].get_name() + options[optname] = target.leaves[1] + target = None + + kwargs = self.convert_options(options, evaluation) + if kwargs is None: + return + + if target: + kwargs["pattern"] = Pattern.create(target) + kwargs["evaluation"] = evaluation + return expand(expr, True, False, **kwargs) + def apply(self, expr, evaluation, options): "Expand[expr_, OptionsPattern[Expand]]" @@ -752,6 +851,8 @@ class ExpandAll(_Expand):
'ExpandAll[$expr$]'
expands out negative integer powers and products of sums in $expr$. +
'ExpandAll[$expr$, $target$]' +
just expands those parts involving $target$.
>> ExpandAll[(a + b) ^ 2 / (c + d)^2] @@ -761,6 +862,12 @@ class ExpandAll(_Expand): >> ExpandAll[(a + Sin[x (1 + y)])^2] = 2 a Sin[x + x y] + a ^ 2 + Sin[x + x y] ^ 2 + >> ExpandAll[Sin[(x+y)^2]] + = Sin[x ^ 2 + 2 x y + y ^ 2] + + >> ExpandAll[Sin[(x+y)^2], Trig->True] + = -Sin[x ^ 2] Sin[2 x y] Sin[y ^ 2] + Cos[x ^ 2] Cos[2 x y] Sin[y ^ 2] + Cos[x ^ 2] Cos[y ^ 2] Sin[2 x y] + Cos[2 x y] Cos[y ^ 2] Sin[x ^ 2] + 'ExpandAll' also expands heads >> ExpandAll[((1 + x)(1 + y))[x]] = (1 + x + y + x y)[x] @@ -768,8 +875,25 @@ class ExpandAll(_Expand): 'ExpandAll' can also work in finite fields >> ExpandAll[(1 + a) ^ 6 / (x + y)^3, Modulus -> 3] = (1 + 2 a ^ 3 + a ^ 6) / (x ^ 3 + y ^ 3) + """ + def apply_patt(self, expr, target, evaluation, options): + "ExpandAll[expr_, target_, OptionsPattern[Expand]]" + if target.get_head_name() in ("System`Rule", "System`DelayedRule"): + optname = target.leaves[0].get_name() + options[optname] = target.leaves[1] + target = None + + kwargs = self.convert_options(options, evaluation) + if kwargs is None: + return + + if target: + kwargs["pattern"] = Pattern.create(target) + kwargs["evaluation"] = evaluation + return expand(expr, numer=True, denom=True, deep=True, **kwargs) + def apply(self, expr, evaluation, options): "ExpandAll[expr_, OptionsPattern[ExpandAll]]" @@ -1047,7 +1171,7 @@ def apply(self, expr, v, evaluation): # Get a coefficient of form in an expression def _coefficient(name, expr, form, n, evaluation): if expr == SymbolNull or form == SymbolNull or n == SymbolNull: - return Integer(0) + return Integer0 if not (isinstance(form, Symbol)) and not (isinstance(form, Expression)): return evaluation.message(name, "ivar", form) @@ -1254,10 +1378,10 @@ def apply(self, expr, form, evaluation): # special cases for expr and form e_null = expr == SymbolNull f_null = form == SymbolNull - if expr == Integer(0): + if expr == Integer0: return Expression("List") elif e_null and f_null: - return Expression("List", Integer(0), Integer0) + return Expression("List", Integer0, Integer0) elif e_null and not f_null: return Expression("List", SymbolNull) elif f_null: @@ -1403,7 +1527,7 @@ def apply_novar(self, expr, evaluation): def apply(self, expr, form, h, evaluation): "Exponent[expr_, form_, h_]" - if expr == Integer(0): + if expr == Integer0: return Expression("DirectedInfinity", Integer(-1)) if not form.has_form("List", None): diff --git a/mathics/builtin/arithmetic.py b/mathics/builtin/arithmetic.py index e38ff24adf..d02cb03c93 100644 --- a/mathics/builtin/arithmetic.py +++ b/mathics/builtin/arithmetic.py @@ -48,6 +48,7 @@ from mathics.builtin.lists import _IterationFunction from mathics.core.convert import from_sympy, SympyExpression +from mathics.core.rules import Pattern @lru_cache(maxsize=1024) diff --git a/mathics/core/expression.py b/mathics/core/expression.py index b93373a801..37d622fcfb 100644 --- a/mathics/core/expression.py +++ b/mathics/core/expression.py @@ -2258,7 +2258,7 @@ def __neg__(self) -> "Integer": def is_zero(self) -> bool: return self.value == 0 - +Integer0 = Integer(0) Integer1 = Integer(1) From 2c0e66f741d738a32b5aa2256f1c537c6ab9dc42 Mon Sep 17 00:00:00 2001 From: mmatera Date: Sun, 25 Apr 2021 11:45:02 -0300 Subject: [PATCH 2/2] fixing and improving Expand and ExpandAll --- CHANGES.rst | 11 +- mathics/builtin/arithmetic.py | 1 + mathics/builtin/numbers/algebra.py | 185 ++++++++++++++++++++++++----- mathics/core/expression.py | 1 - 4 files changed, 161 insertions(+), 37 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 74d8186e20..d65cb88a54 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -26,9 +26,11 @@ Enhancements * ``Attributes`` accepts a string parameter. * ``ColorNegate`` for colors is supported. * ``D`` and ``Derivative`` improvements. +* ``Expand`` and ``ExpandAll`` now support a second parameter ``patt`` (#1301) +* ``Expand`` and ``ExpandAll`` works with hyperbolic functions (`Sinh`, `Cosh`, `Tanh`, `Coth`) * ``FileNames`` returns a sorted list (#1250). * ``FindRoot`` now receives several optional parameters like ``Method`` and ``MaxIterations``. -* ``FixedPoint`` now supports the ``SameTest`` option. +* ``FixedPoint`` now supports the ``SameTest`` option. * ``Prime`` and ``PrimePi`` now accept a list parameter and have the ``NumericFunction`` attribute. * ``ReplaceRepeated`` and ``FixedPoint`` now supports the ``MaxIteration`` option (#1260). * ``Simplify`` performs a more sophisticated set of simplifications. @@ -36,9 +38,8 @@ Enhancements * ``StringTake`` now accepts form containing a list of strings and specification (#1297). * ``Table`` [*expr*, *n*] is supported. * ``ToString`` accepts an optional *form* parameter. -* ``ToExpression`` handles multi-line string input -* The implementation of Streams was redone. - +* ``ToExpression`` handles multi-line string input. +* The implementation of Streams was redone. Bug fixes @@ -54,7 +55,7 @@ Internal changes ---------------- * doctest accepts the option `-d` to show how long it takes to parse, evaluate and compare each individual test. - + 2.1.0 ----- diff --git a/mathics/builtin/arithmetic.py b/mathics/builtin/arithmetic.py index 5f55dc15db..8b08be6675 100644 --- a/mathics/builtin/arithmetic.py +++ b/mathics/builtin/arithmetic.py @@ -8,6 +8,7 @@ """ from mathics.version import __version__ # noqa used in loading to check consistency. + import sympy import mpmath from functools import lru_cache diff --git a/mathics/builtin/numbers/algebra.py b/mathics/builtin/numbers/algebra.py index eff42843c1..2bf0e97111 100644 --- a/mathics/builtin/numbers/algebra.py +++ b/mathics/builtin/numbers/algebra.py @@ -21,6 +21,7 @@ SymbolTrue, ) from mathics.core.convert import from_sympy, sympy_symbol_prefix +from mathics.core.rules import Pattern from mathics.builtin.scoping import dynamic_scoping from mathics.builtin.inference import evaluate_predicate @@ -68,47 +69,102 @@ def _expand(expr): if kwargs["modulus"] is not None and kwargs["modulus"] <= 0: return Integer0 + target_pat = kwargs.get("pattern", None) + if target_pat: + evaluation = kwargs["evaluation"] # A special case for trigonometric functions if "trig" in kwargs and kwargs["trig"]: - if expr.has_form("Sin", 1): + if expr.has_form( + ("Sin", "Cos", "Tan", "Cot", "Sinh", "Cosh", "Tanh", "Coth"), 1 + ): + head = expr.get_head() theta = expr.leaves[0] + if (target_pat is not None) and theta.is_free(target_pat, evaluation): + return expr + if deep: + theta = _expand(theta) if theta.has_form("Plus", 2, None): x, y = theta.leaves[0], Expression("Plus", *theta.leaves[1:]) + if head == Symbol("Sin"): + a = Expression( + "Times", + _expand(Expression("Sin", x)), + _expand(Expression("Cos", y)), + ) - a = Expression( - "Times", - _expand(Expression("Sin", x)), - _expand(Expression("Cos", y)), - ) - - b = Expression( - "Times", - _expand(Expression("Cos", x)), - _expand(Expression("Sin", y)), - ) + b = Expression( + "Times", + _expand(Expression("Cos", x)), + _expand(Expression("Sin", y)), + ) + return _expand(Expression("Plus", a, b)) + elif head == Symbol("Cos"): + a = Expression( + "Times", + _expand(Expression("Cos", x)), + _expand(Expression("Cos", y)), + ) - return Expression("Plus", a, b) + b = Expression( + "Times", + _expand(Expression("Sin", x)), + _expand(Expression("Sin", y)), + ) - elif expr.has_form("Cos", 1): - theta = expr.leaves[0] + return _expand(Expression("Plus", a, -b)) + elif head == Symbol("Sinh"): + a = Expression( + "Times", + _expand(Expression("Sinh", x)), + _expand(Expression("Cosh", y)), + ) - if theta.has_form("Plus", 2, None): - x, y = theta.leaves[0], Expression("Plus", *theta.leaves[1:]) + b = Expression( + "Times", + _expand(Expression("Cosh", x)), + _expand(Expression("Sinh", y)), + ) - a = Expression( - "Times", - _expand(Expression("Cos", x)), - _expand(Expression("Cos", y)), - ) + return _expand(Expression("Plus", a, b)) + elif head == Symbol("Cosh"): + a = Expression( + "Times", + _expand(Expression("Cosh", x)), + _expand(Expression("Cosh", y)), + ) - b = Expression( - "Times", - _expand(Expression("Sin", x)), - _expand(Expression("Sin", y)), - ) + b = Expression( + "Times", + _expand(Expression("Sinh", x)), + _expand(Expression("Sinh", y)), + ) - return Expression("Plus", a, -b) + return _expand(Expression("Plus", a, b)) + elif head == Symbol("Tan"): + a = _expand(Expression("Sin", theta)) + b = Expression( + "Power", _expand(Expression("Cos", theta)), Integer(-1) + ) + return _expand(Expression("Times", a, b)) + elif head == Symbol("Cot"): + a = _expand(Expression("Cos", theta)) + b = Expression( + "Power", _expand(Expression("Sin", theta)), Integer(-1) + ) + return _expand(Expression("Times", a, b)) + elif head == Symbol("Tanh"): + a = _expand(Expression("Sinh", theta)) + b = Expression( + "Power", _expand(Expression("Cosh", theta)), Integer(-1) + ) + return _expand(Expression("Times", a, b)) + elif head == Symbol("Coth"): + a = _expand(Expression("Times", "Cosh", theta)) + b = Expression( + "Power", _expand(Expression("Sinh", theta)), Integer(-1) + ) + return _expand(Expression(a, b)) sub_exprs = [] @@ -128,6 +184,9 @@ def convert_sympy(expr): leaves = expr.get_leaves() if isinstance(expr, Integer): return sympy.Integer(expr.get_int_value()) + if target_pat is not None and not isinstance(expr, Number): + if expr.is_free(target_pat, evaluation): + return store_sub_expr(expr) if expr.has_form("Power", 2): # sympy won't expand `(a + b) / x` to `a / x + b / x` if denom is False # if denom is False we store negative powers to prevent this. @@ -161,7 +220,13 @@ def unconvert_subexprs(expr): if not sub_expr.is_atom(): head = _expand(sub_expr.head) # also expand head leaves = sub_expr.get_leaves() - leaves = [_expand(leaf) for leaf in leaves] + if target_pat: + leaves = [ + leaf if leaf.is_free(target_pat, evaluation) else _expand(leaf) + for leaf in leaves + ] + else: + leaves = [_expand(leaf) for leaf in leaves] sub_exprs[i] = Expression(head, *leaves) else: # thread over Lists etc. @@ -170,7 +235,15 @@ def unconvert_subexprs(expr): for head in threaded_heads: if sub_expr.has_form(head, None): leaves = sub_expr.get_leaves() - leaves = [_expand(leaf) for leaf in leaves] + if target_pat: + leaves = [ + leaf + if leaf.is_free(target_pat, evaluation) + else _expand(leaf) + for leaf in leaves + ] + else: + leaves = [_expand(leaf) for leaf in leaves] sub_exprs[i] = Expression(head, *leaves) break @@ -721,6 +794,8 @@ class Expand(_Expand):
'Expand[$expr$]'
expands out positive integer powers and products of sums in $expr$, as well as trigonometric identities. +
Expand[$expr$, $target$] +
just expands those parts involving $target$. >> Expand[(x + y) ^ 3] @@ -743,11 +818,17 @@ class Expand(_Expand): 'Expand' expands trigonometric identities >> Expand[Sin[x + y], Trig -> True] = Cos[x] Sin[y] + Cos[y] Sin[x] + >> Expand[Tanh[x + y], Trig -> True] + = Cosh[x] Sinh[y] / (Cosh[x] Cosh[y] + Sinh[x] Sinh[y]) + Cosh[y] Sinh[x] / (Cosh[x] Cosh[y] + Sinh[x] Sinh[y]) 'Expand' does not change any other expression. >> Expand[Sin[x (1 + y)]] = Sin[x (1 + y)] + Using the second argument, the expression only + expands those subexpressions containing $pat$: + >> Expand[(x+a)^2+(y+a)^2+(x+y)(x+a), y] + = a ^ 2 + 2 a y + x (a + x) + y (a + x) + y ^ 2 + (a + x) ^ 2 'Expand' also works in Galois fields >> Expand[(1 + a)^12, Modulus -> 3] = 1 + a ^ 3 + a ^ 9 + a ^ 12 @@ -767,11 +848,28 @@ class Expand(_Expand): #> (y^2)^(1/2)/(2x+2y)//Expand = Sqrt[y ^ 2] / (2 x + 2 y) - ## This caused a program crash! + #> 2(3+2x)^2/(5+x^2+3x)^3 // Expand = 24 x / (5 + 3 x + x ^ 2) ^ 3 + 8 x ^ 2 / (5 + 3 x + x ^ 2) ^ 3 + 18 / (5 + 3 x + x ^ 2) ^ 3 """ + def apply_patt(self, expr, target, evaluation, options): + "Expand[expr_, target_, OptionsPattern[Expand]]" + + if target.get_head_name() in ("System`Rule", "System`DelayedRule"): + optname = target.leaves[0].get_name() + options[optname] = target.leaves[1] + target = None + + kwargs = self.convert_options(options, evaluation) + if kwargs is None: + return + + if target: + kwargs["pattern"] = Pattern.create(target) + kwargs["evaluation"] = evaluation + return expand(expr, True, False, **kwargs) + def apply(self, expr, evaluation, options): "Expand[expr_, OptionsPattern[Expand]]" @@ -816,6 +914,8 @@ class ExpandAll(_Expand):
'ExpandAll[$expr$]'
expands out negative integer powers and products of sums in $expr$. +
'ExpandAll[$expr$, $target$]' +
just expands those parts involving $target$.
>> ExpandAll[(a + b) ^ 2 / (c + d)^2] @@ -825,6 +925,12 @@ class ExpandAll(_Expand): >> ExpandAll[(a + Sin[x (1 + y)])^2] = 2 a Sin[x + x y] + a ^ 2 + Sin[x + x y] ^ 2 + >> ExpandAll[Sin[(x+y)^2]] + = Sin[x ^ 2 + 2 x y + y ^ 2] + + >> ExpandAll[Sin[(x+y)^2], Trig->True] + = -Sin[x ^ 2] Sin[2 x y] Sin[y ^ 2] + Cos[x ^ 2] Cos[2 x y] Sin[y ^ 2] + Cos[x ^ 2] Cos[y ^ 2] Sin[2 x y] + Cos[2 x y] Cos[y ^ 2] Sin[x ^ 2] + 'ExpandAll' also expands heads >> ExpandAll[((1 + x)(1 + y))[x]] = (1 + x + y + x y)[x] @@ -832,8 +938,25 @@ class ExpandAll(_Expand): 'ExpandAll' can also work in finite fields >> ExpandAll[(1 + a) ^ 6 / (x + y)^3, Modulus -> 3] = (1 + 2 a ^ 3 + a ^ 6) / (x ^ 3 + y ^ 3) + """ + def apply_patt(self, expr, target, evaluation, options): + "ExpandAll[expr_, target_, OptionsPattern[Expand]]" + if target.get_head_name() in ("System`Rule", "System`DelayedRule"): + optname = target.leaves[0].get_name() + options[optname] = target.leaves[1] + target = None + + kwargs = self.convert_options(options, evaluation) + if kwargs is None: + return + + if target: + kwargs["pattern"] = Pattern.create(target) + kwargs["evaluation"] = evaluation + return expand(expr, numer=True, denom=True, deep=True, **kwargs) + def apply(self, expr, evaluation, options): "ExpandAll[expr_, OptionsPattern[ExpandAll]]" diff --git a/mathics/core/expression.py b/mathics/core/expression.py index a83a1ef268..a9e90680ff 100644 --- a/mathics/core/expression.py +++ b/mathics/core/expression.py @@ -2263,7 +2263,6 @@ def __neg__(self) -> "Integer": def is_zero(self) -> bool: return self.value == 0 - Integer0 = Integer(0) Integer1 = Integer(1)