Before, 'refine_Pow' would simplify (-1)**exp only if 'exp' as a whole could be determined as even or odd. A doctest like,
>>> refine_Pow((-1)**(x+y), Assume(x, Q.even)) (-1)**y would fail. This patch fixes that by treating powers of S.NegativeOne as a special case. Every term in the exponent is checked, and even terms are simply discarded. Odd terms are collected to an even quantity and then discarded, possibly introducing a new term +1 in the exponent. Finally, a number N is replaced with N % 2. We are now able to refine: >>> refine_Pow((-1)**(x+y+z), Assume(x, Q.odd) & Assume(z, Q.odd)) (-1)**y >>> refine_Pow((-1)**(x+y+2), Assume(x, Q.odd)) (-1)**(1 + y) >>> refine((-1)**(x+3)) (-1)**(x+1) These examples are implemented as doctests and regular tests. --- sympy/assumptions/refine.py | 50 ++++++++++++++++++++++++++++++- sympy/assumptions/tests/test_refine.py | 10 ++++++- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/sympy/assumptions/refine.py b/sympy/assumptions/refine.py index a3ffd18..d81d817 100644 --- a/sympy/assumptions/refine.py +++ b/sympy/assumptions/refine.py @@ -1,4 +1,4 @@ -from sympy.core import S, Symbol, sympify +from sympy.core import S, Symbol, sympify, Add from sympy.utilities.source import get_class from sympy.assumptions import Q, ask from sympy.logic.boolalg import fuzzy_not @@ -63,13 +63,25 @@ def refine_Pow(expr, assumptions): >>> from sympy import Symbol, Assume, Q >>> from sympy.assumptions.refine import refine_Pow - >>> from sympy.abc import x + >>> from sympy.abc import x,y,z >>> refine_Pow((-1)**x, Assume(x, Q.real)) >>> refine_Pow((-1)**x, Assume(x, Q.even)) 1 >>> refine_Pow((-1)**x, Assume(x, Q.odd)) -1 + For powers of -1, even parts of the exponent can be simplified: + + >>> refine_Pow((-1)**(x+y), Assume(x, Q.even)) + (-1)**y + >>> refine_Pow((-1)**(x+y+z), Assume(x, Q.odd) & Assume(z, Q.odd)) + (-1)**y + >>> refine_Pow((-1)**(x+y+2), Assume(x, Q.odd)) + (-1)**(1 + y) + >>> refine_Pow((-1)**(x+3), True) + (-1)**(1 + x) + + """ from sympy.core import Pow, Rational from sympy.functions import sign @@ -83,6 +95,40 @@ def refine_Pow(expr, assumptions): if type(expr.base) is Pow: return abs(expr.base.base) ** (expr.base.exp * expr.exp) + if expr.base is S.NegativeOne: + if expr.exp.is_Add: + + # For powers of (-1) we can remove + # - even terms + # - pairs of odd terms + # - a single odd term + 1 + # - A numerical constant N can be replaced with mod(N,2) + + coeff, terms = expr.exp.as_coeff_factors() + terms = set(terms) + even_terms = set([]) + odd_terms = set([]) + initial_number_of_terms = len(terms) + + for t in terms: + if ask(t, Q.even, assumptions): + even_terms.add(t) + elif ask(t, Q.odd, assumptions): + odd_terms.add(t) + + terms -= even_terms + if len(odd_terms)%2: + terms -= odd_terms + new_coeff = (coeff + S.One) % 2 + else: + terms -= odd_terms + new_coeff = coeff % 2 + + if new_coeff != coeff or len(terms) < initial_number_of_terms: + terms.add(new_coeff) + return expr.base**(Add(*terms)) + + def refine_exp(expr, assumptions): """ Handler for exponential function. diff --git a/sympy/assumptions/tests/test_refine.py b/sympy/assumptions/tests/test_refine.py index 58b24b8..59a6dc0 100644 --- a/sympy/assumptions/tests/test_refine.py +++ b/sympy/assumptions/tests/test_refine.py @@ -12,7 +12,7 @@ def test_abs(): assert refine(abs(x**2), Assume(x, Q.real)) == x**2 def test_pow(): - x, y = symbols('x y') + x, y, z = symbols('x y z') assert refine((-1)**x, Assume(x, Q.even)) == 1 assert refine((-1)**x, Assume(x, Q.odd)) == -1 assert refine((-2)**x, Assume(x, Q.even)) == 2**x @@ -30,6 +30,14 @@ def test_pow(): assert refine(sqrt(1/x), Assume(x, Q.real)) != 1/sqrt(x) assert refine(sqrt(1/x), Assume(x, Q.positive)) == 1/sqrt(x) + # powers of (-1) + assert refine((-1)**(x+y), Assume(x, Q.even)) == (-1)**y + assert refine((-1)**(x+y+z), Assume(x, Q.odd)&Assume(z, Q.odd))==(-1)**y + assert refine((-1)**(x+y+1), Assume(x, Q.odd))==(-1)**y + assert refine((-1)**(x+y+2), Assume(x, Q.odd))==(-1)**(y+1) + assert refine((-1)**(x+3)) == (-1)**(x+1) + + def test_exp(): x = symbols('x') assert refine(exp(pi*I*2*x), Assume(x, Q.integer)) == 1 -- 1.6.5 -- You received this message because you are subscribed to the Google Groups "sympy-patches" group. To post to this group, send email to sympy-patc...@googlegroups.com. To unsubscribe from this group, send email to sympy-patches+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sympy-patches?hl=en.