Repository: sympy/sympy

Issue:
ask(Q.nonnegative(x**2), Q.positive(x)) gives None
```
In [1]: ask(Q.nonnegative(x**2), Q.positive(x))

In [2]: ask(Q.negative(x**2), Q.positive(x))
Out[2]: False

In [3]: ask(Q.real(x**2), Q.positive(x))
Out[3]: True
```

The relevant fact(s) would probably have to be implemented in satask to make this work. 

Discussion:

Patch:
diff --git a/sympy/assumptions/sathandlers.py b/sympy/assumptions/sathandlers.py
index 9297bb4138..56aeb6a544 100644
--- a/sympy/assumptions/sathandlers.py
+++ b/sympy/assumptions/sathandlers.py
@@ -304,6 +304,12 @@ def register_fact(klass, fact, registry=fact_registry):
     (Mul, Implies(AllArgs(Q.positive), Q.positive)),
     (Mul, Implies(AllArgs(Q.commutative), Q.commutative)),
     (Mul, Implies(AllArgs(Q.real), Q.commutative)),
+
+    (Pow, CustomLambda(lambda power: Implies(Q.real(power.base) &
+    Q.even(power.exp) & Q.nonnegative(power.exp), Q.nonnegative(power)))),
+    (Pow, CustomLambda(lambda power: Implies(Q.nonnegative(power.base) & Q.odd(power.exp) & Q.nonnegative(power.exp), Q.nonnegative(power)))),
+    (Pow, CustomLambda(lambda power: Implies(Q.nonpositive(power.base) & Q.odd(power.exp) & Q.nonnegative(power.exp), Q.nonpositive(power)))),
+
     # This one can still be made easier to read. I think we need basic pattern
     # matching, so that we can just write Equivalent(Q.zero(x**y), Q.zero(x) & Q.positive(y))
     (Pow, CustomLambda(lambda power: Equivalent(Q.zero(power), Q.zero(power.base) & Q.positive(power.exp)))),
@@ -316,7 +322,7 @@ def register_fact(klass, fact, registry=fact_registry):
     (Mul, Implies(AllArgs(Q.imaginary | Q.real), Implies(ExactlyOneArg(Q.imaginary), Q.imaginary))),
     (Mul, Implies(AllArgs(Q.real), Q.real)),
     (Add, Implies(AllArgs(Q.real), Q.real)),
-    #General Case: Odd number of imaginary args implies mul is imaginary(To be implemented)
+    # General Case: Odd number of imaginary args implies mul is imaginary(To be implemented)
     (Mul, Implies(AllArgs(Q.real), Implies(ExactlyOneArg(Q.irrational),
         Q.irrational))),
     (Add, Implies(AllArgs(Q.real), Implies(ExactlyOneArg(Q.irrational),


Test patch:
diff --git a/sympy/assumptions/tests/test_satask.py b/sympy/assumptions/tests/test_satask.py
index 8e42d09474..0fbe727117 100644
--- a/sympy/assumptions/tests/test_satask.py
+++ b/sympy/assumptions/tests/test_satask.py
@@ -262,3 +262,62 @@ def test_pos_neg():
     assert satask(Q.negative(x + y), Q.negative(x) & Q.negative(y)) is True
     assert satask(Q.positive(x + y), Q.negative(x) & Q.negative(y)) is False
     assert satask(Q.negative(x + y), Q.positive(x) & Q.positive(y)) is False
+
+def test_pow_pos_neg():
+    assert satask(Q.nonnegative(x**2), Q.positive(x)) is True
+    assert satask(Q.nonpositive(x**2), Q.positive(x)) is False
+    assert satask(Q.positive(x**2), Q.positive(x)) is True
+    assert satask(Q.negative(x**2), Q.positive(x)) is False
+    assert satask(Q.real(x**2), Q.positive(x)) is True
+
+    assert satask(Q.nonnegative(x**2), Q.negative(x)) is True
+    assert satask(Q.nonpositive(x**2), Q.negative(x)) is False
+    assert satask(Q.positive(x**2), Q.negative(x)) is True
+    assert satask(Q.negative(x**2), Q.negative(x)) is False
+    assert satask(Q.real(x**2), Q.negative(x)) is True
+
+    assert satask(Q.nonnegative(x**2), Q.nonnegative(x)) is True
+    assert satask(Q.nonpositive(x**2), Q.nonnegative(x)) is None
+    assert satask(Q.positive(x**2), Q.nonnegative(x)) is None
+    assert satask(Q.negative(x**2), Q.nonnegative(x)) is False
+    assert satask(Q.real(x**2), Q.nonnegative(x)) is True
+
+    assert satask(Q.nonnegative(x**2), Q.nonpositive(x)) is True
+    assert satask(Q.nonpositive(x**2), Q.nonpositive(x)) is None
+    assert satask(Q.positive(x**2), Q.nonpositive(x)) is None
+    assert satask(Q.negative(x**2), Q.nonpositive(x)) is False
+    assert satask(Q.real(x**2), Q.nonpositive(x)) is True
+
+    assert satask(Q.nonnegative(x**3), Q.positive(x)) is True
+    assert satask(Q.nonpositive(x**3), Q.positive(x)) is False
+    assert satask(Q.positive(x**3), Q.positive(x)) is True
+    assert satask(Q.negative(x**3), Q.positive(x)) is False
+    assert satask(Q.real(x**3), Q.positive(x)) is True
+
+    assert satask(Q.nonnegative(x**3), Q.negative(x)) is False
+    assert satask(Q.nonpositive(x**3), Q.negative(x)) is True
+    assert satask(Q.positive(x**3), Q.negative(x)) is False
+    assert satask(Q.negative(x**3), Q.negative(x)) is True
+    assert satask(Q.real(x**3), Q.negative(x)) is True
+
+    assert satask(Q.nonnegative(x**3), Q.nonnegative(x)) is True
+    assert satask(Q.nonpositive(x**3), Q.nonnegative(x)) is None
+    assert satask(Q.positive(x**3), Q.nonnegative(x)) is None
+    assert satask(Q.negative(x**3), Q.nonnegative(x)) is False
+    assert satask(Q.real(x**3), Q.nonnegative(x)) is True
+
+    assert satask(Q.nonnegative(x**3), Q.nonpositive(x)) is None
+    assert satask(Q.nonpositive(x**3), Q.nonpositive(x)) is True
+    assert satask(Q.positive(x**3), Q.nonpositive(x)) is False
+    assert satask(Q.negative(x**3), Q.nonpositive(x)) is None
+    assert satask(Q.real(x**3), Q.nonpositive(x)) is True
+
+    # If x is zero, x**negative is not real.
+    assert satask(Q.nonnegative(x**-2), Q.nonpositive(x)) is None
+    assert satask(Q.nonpositive(x**-2), Q.nonpositive(x)) is None
+    assert satask(Q.positive(x**-2), Q.nonpositive(x)) is None
+    assert satask(Q.negative(x**-2), Q.nonpositive(x)) is None
+    assert satask(Q.real(x**-2), Q.nonpositive(x)) is None
+
+    # We could deduce things for negative powers if x is nonzero, but it
+    # isn't implemented yet.