Before, 'refine_Pow' would simplify (-1)**exp only if 'exp' as a whole couold 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 discarded. After the even terms have been discarded, we check the remaining terms for pairs that are even. This fixes another pair of doctests: >>> refine_Pow((-1)**(x+y+z+1), Assume(x, Q.odd)) (-1)**(y + z) >>> refine_Pow((-1)**(x+y+z), Assume(x, Q.odd) & Assume(z, Q.odd)) (-1)**y These doctests are included in the patch. --- sympy/assumptions/refine.py | 41 +++++++++++++++++++++++++++++++++++++++-- 1 files changed, 39 insertions(+), 2 deletions(-) diff --git a/sympy/assumptions/refine.py b/sympy/assumptions/refine.py index a3ffd18..42d58c7 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,23 @@ 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+z+1), Assume(x, Q.odd)) + (-1)**(y + z) + + """ from sympy.core import Pow, Rational from sympy.functions import sign @@ -82,6 +92,33 @@ def refine_Pow(expr, assumptions): if isinstance(expr.exp, Rational): 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: + + # see if we can remove single terms in the exponent + terms = expr.exp.args + removable_terms = set([]) + for t in terms: + if ask(t, Q.even, assumptions): + removable_terms.add(t) + if len(removable_terms) > 0: + terms = list(set(terms)-removable_terms) + + # see if we can remove terms pairwise + len_args = len(terms) + removable_terms.clear() + for i in range(0, len_args-1): + for j in range(i+1, len_args): + if ask(terms[i]+terms[j], Q.even, assumptions): + removable_terms.add(terms[i]) + removable_terms.add(terms[j]) + + if len(removable_terms) > 0: + terms = list(set(terms)-removable_terms) + + if len(expr.exp.args) > len(terms): + return expr.base**(Add(*terms)) + def refine_exp(expr, assumptions): """ -- 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.