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.

Reply via email to