Repository: sympy/sympy
Pull request: Improved code of sympy.core.power.Pow
<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->

#### References to other Issues or PRs
<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234". See
https://github.com/blog/1506-closing-issues-via-pull-requests . Please also
write a comment on that issue linking back to this pull request once it is
open. -->
Fixes #16332 


#### Brief description of what is fixed or changed


#### Other comments


#### Release Notes

<!-- Write the release notes for this release below. See
https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more information
on how to write release notes. The bot will check your release notes
automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->
NO ENTRY
<!-- END RELEASE NOTES -->


Problem statement:
S(0)**real(!=0) should be (0 or zoo) and hence non-positive. 
Consider the following code from master:
```py
>>> from sympy import symbols, ask, Q
>>> from sympy.abc import x,y,z
>>> p = symbols('p', real=True, zero=False)
>>> q = symbols('q', zero=True)
>>> (q**p).is_positive
>>>
```
Since `0**a`(where a is real and non-zero) should always be (0 or `zoo`). Therefore, the result should have been `False`.

Hints from issue discussion:
Also in the master, the following code segment works:
```py
In [7]: from sympy import symbols

In [8]: p = symbols('p', zero=True)

In [9]: q = symbols('q', odd=True)

In [10]: (p**q).is_positive
Out[10]: False
```

Commit message: remove extra whitespace

Patch to review:
diff --git a/sympy/core/power.py b/sympy/core/power.py
index 13b4b560f7a9..f15f67a3c7ca 100644
--- a/sympy/core/power.py
+++ b/sympy/core/power.py
@@ -437,6 +437,9 @@ def _eval_is_positive(self):
                 return True
             if self.exp.is_odd:
                 return False
+        elif self.base.is_zero:
+            if self.exp.is_real:
+                return self.exp.is_zero
         elif self.base.is_nonpositive:
             if self.exp.is_odd:
                 return False
@@ -459,6 +462,9 @@ def _eval_is_negative(self):
         elif self.base.is_positive:
             if self.exp.is_real:
                 return False
+        elif self.base.is_zero:
+            if self.exp.is_real:
+                return self.exp.is_zero and False
         elif self.base.is_nonnegative:
             if self.exp.is_nonnegative:
                 return False
diff --git a/sympy/core/tests/test_assumptions.py b/sympy/core/tests/test_assumptions.py
index 4d174adfc49e..3e0940b6a8f0 100644
--- a/sympy/core/tests/test_assumptions.py
+++ b/sympy/core/tests/test_assumptions.py
@@ -786,6 +786,32 @@ def test_Mul_is_prime_composite():
     assert ( (x+1)*(y+1) ).is_prime is None
     assert ( (x+1)*(y+1) ).is_composite is None
 
+
+def test_Pow_is_pos_neg():
+    z = Symbol('z', real=True)
+    w = Symbol('w', nonpositive=True)
+
+    assert (S(-1)**S(2)).is_positive is True
+    assert (S(1)**z).is_positive is True
+    assert (S(-1)**S(3)).is_positive is False
+    assert (S(0)**S(0)).is_positive is True  # 0**0 is 1
+    assert (w**S(3)).is_positive is False
+    assert (w**S(2)).is_positive is None
+    assert (I**2).is_positive is False
+    assert (I**4).is_positive is True
+
+    # tests emerging from #16332 issue
+    p = Symbol('p', zero=True)
+    q = Symbol('q', zero=False, real=True)
+    j = Symbol('j', zero=False, even=True)
+    x = Symbol('x', zero=True)
+    y = Symbol('y', zero=True)
+    assert (p**q).is_positive is False
+    assert (p**q).is_negative is False
+    assert (p**j).is_positive is False
+    assert (x**y).is_positive is True   # 0**0
+    assert (x**y).is_negative is False
+
 def test_Pow_is_prime_composite():
     from sympy import Pow
     x = Symbol('x', positive=True, integer=True)


Code review comments:
diff_hunk: @@ -459,6 +462,9 @@ def _eval_is_negative(self):
         elif self.base.is_positive:
             if self.exp.is_real:
                 return False
+        elif self.base.is_zero:
+            if self.exp.is_real:
+                return self.exp.is_zero and False
path: sympy/core/power.py
text: @user1:
do you mean simply: `elif self.base.is_zero: return False`? It will never be negative. A test would be
```python
>>> (Dummy(zero=True)**Dummy()).is_negative
False
```


@author:
I don't think this should be the case since,
```py
>>> (0**zoo).is_negative  # nan.is_negative
>>>
```
But thanks I think I can simplify it more to the following
```
elif self.base.is_zero:
    return self.exp.is_real and False
```

@user1:
`return self.exp.is_real and False` will always be False

@user1:
so you could do
```python
elif self.base.is_zero:
    if self.exp.is_real:
        return False
```    

@user1:
or 
```python
elif fuzzy_and(self.base.is_zero, self.exp.is_real):
    return False
```

@author:
Actually Pythonically `True and False => False, False and False => False, None and False => None`.
But after thinking more I got that the result should be
`return not self.exp.is_real and None`, it would result `False` when `self.exp.is_real` is `True` and `None` in the other cases.

@author:
Or I can just use
```py
if self.exp.is_real:
    return False
```

@author:
> so you could do
> 
> ```python
> elif self.base.is_zero:
>     if self.exp.is_real:
>         return False
> ```
This is enough and I would change it so.


@author:
Thanks @user1 for pointing out.