From: Fabian Seoane <fab...@fseoane.net>

implemented factoring on negative roots, now (-8)**Rational(1,3) returns
2*(-1)**Rational(1,3). This is important, for example, in solve, so that
it doesen't return uneecesarry long roots

removed unnecesary nesting, renamed variables b -> base, e -> exp
---
 sympy/core/numbers.py            |  189 ++++++++++++++++++++------------------
 sympy/core/power.py              |    7 +-
 sympy/core/tests/test_eval.py    |    6 +
 sympy/core/tests/test_numbers.py |    4 -
 4 files changed, 109 insertions(+), 97 deletions(-)

diff --git a/sympy/core/numbers.py b/sympy/core/numbers.py
index 865bce9..73daa51 100644
--- a/sympy/core/numbers.py
+++ b/sympy/core/numbers.py
@@ -894,100 +894,107 @@ class Integer(Rational):
     def _eval_is_odd(self):
         return bool(self.p % 2)
 
-    def _eval_power(b, e):
-        if isinstance(e, Number):
-            if e is S.NaN: return S.NaN
-            if isinstance(e, Real):
-                return b._eval_evalf(e._prec) ** e
-            if e.is_negative:
-                # (3/4)**-2 -> (4/3)**2
-                ne = -e
-                if ne is S.One:
-                    return Rational(1, b.p)
-                return Rational(1, b.p) ** ne
-            if e is S.Infinity:
-                if b.p > 1:
-                    # (3)**oo -> oo
-                    return S.Infinity
-                if b.p < -1:
-                    # (-3)**oo -> oo + I*oo
-                    return S.Infinity + S.Infinity * S.ImaginaryUnit
-                return S.Zero
-            if isinstance(e, Integer):
-                # (4/3)**2 -> 4**2 / 3**2
-                return Integer(b.p ** e.p)
-            if isinstance(e, Rational):
-                if b == -1:  # any one has tested this ???
-                    # calculate the roots of -1
-                    if e.q.is_odd:
-                        return -1
-                    r = cos(pi/e.q) + S.ImaginaryUnit*sin(pi/e.q)
-                    return r**e.p
-                if b >= 0:
-                    x, xexact = integer_nthroot(b.p, e.q)
-                    if xexact:
-                        res = Integer(x ** abs(e.p))
-                        if e >= 0:
-                            return res
-                        else:
-                            return 1/res
-                    else:
-                        if b > 2**32: #Prevent from factorizing too big 
integers:
-                            for i in xrange(2, e.q//2 + 1): #OLD CODE
-                                if e.q % i == 0:
-                                    x, xexact = integer_nthroot(b.p, i)
-                                    if xexact:
-                                        return Integer(x)**(e * i)
-                            # Try to get some part of the base out, if 
exponent > 1
-                            if e.p > e.q:
-                                i = e.p // e.q
-                                r = e.p % e.q
-                                return b**i * b**Rational(r, e.q)
-                            return
-
-
-                        dict = b.factors()
-
-                        out_int = 1
-                        sqr_int = 1
-                        sqr_gcd = 0
-
-                        sqr_dict = {}
-
-                        for prime,exponent in dict.iteritems():
-                            exponent *= e.p
-                            div_e = exponent // e.q
-                            div_m = exponent % e.q
-
-                            if div_e > 0:
-                                out_int *= prime**div_e
-                            if div_m > 0:
-                                sqr_dict[prime] = div_m
-
-                        for p,ex in sqr_dict.iteritems():
-                            if sqr_gcd == 0:
-                                sqr_gcd = ex
-                            else:
-                                sqr_gcd = igcd(sqr_gcd, ex)
-
-                        for k,v in sqr_dict.iteritems():
-                            sqr_int *= k**(v // sqr_gcd)
-
-                        if sqr_int == b.p and out_int == 1:
-                            return None
-
-                        return out_int * Pow(sqr_int , Rational(sqr_gcd, e.q))
+    def _eval_power(base, exp):
+        """
+        Tries to do some simplifications on base ** exp, where base is
+        an instance of Rational
+
+        Returns None if no further simplifications can be done
+
+        When exponent is a fraction (so we have for example a square root),
+        we try to find the simplest possible representation, so that
+          - 4**Rational(1,2) becomes 2
+          - (-4)**Rational(1,2) becomes 2*I
+        """
+
+        MAX_INT_FACTOR = 4294967296 # Prevent from factorizing too big integers
+        if not isinstance(exp, Number):
+            c,t = base.as_coeff_terms()
+            if exp.is_even and isinstance(c, Number) and c < 0:
+                return (-c * Mul(*t)) ** exp
+        if exp is S.NaN: return S.NaN
+        if isinstance(exp, Real):
+            return base._eval_evalf(exp._prec) ** exp
+        if exp.is_negative:
+            # (3/4)**-2 -> (4/3)**2
+            ne = -exp
+            if ne is S.One:
+                return Rational(1, base.p)
+            return Rational(1, base.p) ** ne
+        if exp is S.Infinity:
+            if base.p > 1:
+                # (3)**oo -> oo
+                return S.Infinity
+            if base.p < -1:
+                # (-3)**oo -> oo + I*oo
+                return S.Infinity + S.Infinity * S.ImaginaryUnit
+            return S.Zero
+        if isinstance(exp, Integer):
+            # (4/3)**2 -> 4**2 / 3**2
+            return Integer(base.p ** exp.p)
+        if exp == S.Half and base.is_negative:
+            # sqrt(-2) -> I*sqrt(2)
+            return S.ImaginaryUnit * ((-base)**exp)
+        if isinstance(exp, Rational):
+            # 4**Rational(1,2) -> 2
+            result = None
+            x, xexact = integer_nthroot(abs(base.p), exp.q)
+            if xexact:
+                res = Integer(x ** abs(exp.p))
+                if exp >= 0:
+                    result = res
                 else:
-                    if e.q == 2:
-                        return S.ImaginaryUnit ** e.p * (-b)**e
+                    result = 1/res
+            else:
+                if base > MAX_INT_FACTOR:
+                    for i in xrange(2, exp.q//2 + 1): #OLD CODE
+                        if exp.q % i == 0:
+                            x, xexact = integer_nthroot(abs(base.p), i)
+                            if xexact:
+                                result = Integer(x)**(e * i)
+                                break
+                    # Try to get some part of the base out, if exponent > 1
+                    if exp.p > exp.q:
+                        i = exp.p // exp.q
+                        r = exp.p % exp.q
+                        result = base**i * b**Rational(r, exp.q)
+                    return
+
+                dict = base.factors()
+                out_int = 1
+                sqr_int = 1
+                sqr_gcd = 0
+                sqr_dict = {}
+                for prime,exponent in dict.iteritems():
+                    exponent *= exp.p
+                    div_e = exponent // exp.q
+                    div_m = exponent % exp.q
+                    if div_e > 0:
+                        out_int *= prime**div_e
+                    if div_m > 0:
+                        sqr_dict[prime] = div_m
+                for p,ex in sqr_dict.iteritems():
+                    if sqr_gcd == 0:
+                        sqr_gcd = ex
                     else:
-                        return None
-
-        c,t = b.as_coeff_terms()
-        if e.is_even and isinstance(c, Number) and c < 0:
-            return (-c * Mul(*t)) ** e
+                        sqr_gcd = igcd(sqr_gcd, ex)
+                for k,v in sqr_dict.iteritems():
+                    sqr_int *= k**(v // sqr_gcd)
+                if sqr_int == base.p and out_int == 1:
+                    result = None
+                else:
+                    result = out_int * Pow(sqr_int , Rational(sqr_gcd, exp.q))
 
-        return
+            if result is not None:
+                if base.is_positive:
+                    return result
+                elif exp.q == 2:
+                    return result * S.ImaginaryUnit
+                else:
+                    return result * ((-1)**exp)
+            else:
+                if exp == S.Half and base.is_negative:
+                    return S.ImaginaryUnit * Pow(-base, exp)
 
     def _eval_is_prime(self):
         if self.p < 0:
diff --git a/sympy/core/power.py b/sympy/core/power.py
index 893f614..aefdd4c 100644
--- a/sympy/core/power.py
+++ b/sympy/core/power.py
@@ -141,9 +141,12 @@ class Pow(Basic):
 
     def _eval_is_integer(self):
         c1 = self.base.is_integer
-        if c1 is None: return
         c2 = self.exp.is_integer
-        if c2 is None: return
+        if c1 is None or c2 is None:
+            return None
+        if not c1:
+            if self.exp.is_nonnegative:
+                return False
         if c1 and c2:
             if self.exp.is_nonnegative or self.exp.is_positive:
                 return True
diff --git a/sympy/core/tests/test_eval.py b/sympy/core/tests/test_eval.py
index 15e5fc4..1e9eb67 100644
--- a/sympy/core/tests/test_eval.py
+++ b/sympy/core/tests/test_eval.py
@@ -34,12 +34,18 @@ def test_pow_eval():
     assert sqrt(-4) == 2*I
     assert sqrt( 4) == 2
     assert (8)**Rational(1,3) == 2
+    assert (-8)**Rational(1,3) == 2*((-1)**Rational(1,3))
 
     assert sqrt(-2) == I*sqrt(2)
     assert (-1)**Rational(1,3) != I
     assert (-10)**Rational(1,3) != I*((10)**Rational(1,3))
     assert (-2)**Rational(1,4) != (2)**Rational(1,4)
 
+    assert 64**(Rational(1)/3) == 4
+    assert 64**(Rational(2)/3) == 16
+    assert 24*64**(-Rational(1)/2) == 3
+    assert (-27)**Rational(1,3) == 3*(-1)**Rational(1,3)
+
     assert (cos(2) / tan(2))**2 == (cos(2) / tan(2))**2
 
 @XFAIL
diff --git a/sympy/core/tests/test_numbers.py b/sympy/core/tests/test_numbers.py
index 44f4bf5..894101c 100644
--- a/sympy/core/tests/test_numbers.py
+++ b/sympy/core/tests/test_numbers.py
@@ -172,10 +172,6 @@ def test_powers():
     assert integer_nthroot(c2+1, 2) == (c, False)
     assert integer_nthroot(c2-1, 2) == (c-1, False)
 
-    assert 64**(Rational(1)/3)==4
-    assert 64**(Rational(2)/3)==16
-    assert 24*64**(-Rational(1)/2)==3
-
     assert Rational(5**3, 8**3)**Rational(4,3) == Rational(5**4, 8**4)
     assert Rational(-4,7)**Rational(1,2) == I*Rational(4,7)**Rational(1,2)
 
-- 
1.6.0.2


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sympy-patches" group.
To post to this group, send email to sympy-patches@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