|
""" |
|
Handlers related to order relations: positive, negative, etc. |
|
""" |
|
|
|
from sympy.assumptions import Q, ask |
|
from sympy.core import Add, Basic, Expr, Mul, Pow, S |
|
from sympy.core.logic import fuzzy_not, fuzzy_and, fuzzy_or |
|
from sympy.core.numbers import E, ImaginaryUnit, NaN, I, pi |
|
from sympy.functions import Abs, acos, acot, asin, atan, exp, factorial, log |
|
from sympy.matrices import Determinant, Trace |
|
from sympy.matrices.expressions.matexpr import MatrixElement |
|
|
|
from sympy.multipledispatch import MDNotImplementedError |
|
|
|
from ..predicates.order import (NegativePredicate, NonNegativePredicate, |
|
NonZeroPredicate, ZeroPredicate, NonPositivePredicate, PositivePredicate, |
|
ExtendedNegativePredicate, ExtendedNonNegativePredicate, |
|
ExtendedNonPositivePredicate, ExtendedNonZeroPredicate, |
|
ExtendedPositivePredicate,) |
|
|
|
|
|
|
|
|
|
def _NegativePredicate_number(expr, assumptions): |
|
r, i = expr.as_real_imag() |
|
|
|
if r == S.NaN or i == S.NaN: |
|
return None |
|
|
|
|
|
|
|
|
|
|
|
if not i: |
|
r = r.evalf(2) |
|
if r._prec != 1: |
|
return r < 0 |
|
else: |
|
i = i.evalf(2) |
|
if i._prec != 1: |
|
if i != 0: |
|
return False |
|
r = r.evalf(2) |
|
if r._prec != 1: |
|
return r < 0 |
|
|
|
@NegativePredicate.register(Basic) |
|
def _(expr, assumptions): |
|
if expr.is_number: |
|
return _NegativePredicate_number(expr, assumptions) |
|
|
|
@NegativePredicate.register(Expr) |
|
def _(expr, assumptions): |
|
ret = expr.is_negative |
|
if ret is None: |
|
raise MDNotImplementedError |
|
return ret |
|
|
|
@NegativePredicate.register(Add) |
|
def _(expr, assumptions): |
|
""" |
|
Positive + Positive -> Positive, |
|
Negative + Negative -> Negative |
|
""" |
|
if expr.is_number: |
|
return _NegativePredicate_number(expr, assumptions) |
|
|
|
r = ask(Q.real(expr), assumptions) |
|
if r is not True: |
|
return r |
|
|
|
nonpos = 0 |
|
for arg in expr.args: |
|
if ask(Q.negative(arg), assumptions) is not True: |
|
if ask(Q.positive(arg), assumptions) is False: |
|
nonpos += 1 |
|
else: |
|
break |
|
else: |
|
if nonpos < len(expr.args): |
|
return True |
|
|
|
@NegativePredicate.register(Mul) |
|
def _(expr, assumptions): |
|
if expr.is_number: |
|
return _NegativePredicate_number(expr, assumptions) |
|
result = None |
|
for arg in expr.args: |
|
if result is None: |
|
result = False |
|
if ask(Q.negative(arg), assumptions): |
|
result = not result |
|
elif ask(Q.positive(arg), assumptions): |
|
pass |
|
else: |
|
return |
|
return result |
|
|
|
@NegativePredicate.register(Pow) |
|
def _(expr, assumptions): |
|
""" |
|
Real ** Even -> NonNegative |
|
Real ** Odd -> same_as_base |
|
NonNegative ** Positive -> NonNegative |
|
""" |
|
if expr.base == E: |
|
|
|
if ask(Q.real(expr.exp), assumptions): |
|
return False |
|
return |
|
|
|
if expr.is_number: |
|
return _NegativePredicate_number(expr, assumptions) |
|
if ask(Q.real(expr.base), assumptions): |
|
if ask(Q.positive(expr.base), assumptions): |
|
if ask(Q.real(expr.exp), assumptions): |
|
return False |
|
if ask(Q.even(expr.exp), assumptions): |
|
return False |
|
if ask(Q.odd(expr.exp), assumptions): |
|
return ask(Q.negative(expr.base), assumptions) |
|
|
|
@NegativePredicate.register_many(Abs, ImaginaryUnit) |
|
def _(expr, assumptions): |
|
return False |
|
|
|
@NegativePredicate.register(exp) |
|
def _(expr, assumptions): |
|
if ask(Q.real(expr.exp), assumptions): |
|
return False |
|
raise MDNotImplementedError |
|
|
|
|
|
|
|
|
|
@NonNegativePredicate.register(Basic) |
|
def _(expr, assumptions): |
|
if expr.is_number: |
|
notnegative = fuzzy_not(_NegativePredicate_number(expr, assumptions)) |
|
if notnegative: |
|
return ask(Q.real(expr), assumptions) |
|
else: |
|
return notnegative |
|
|
|
@NonNegativePredicate.register(Expr) |
|
def _(expr, assumptions): |
|
ret = expr.is_nonnegative |
|
if ret is None: |
|
raise MDNotImplementedError |
|
return ret |
|
|
|
|
|
|
|
|
|
@NonZeroPredicate.register(Expr) |
|
def _(expr, assumptions): |
|
ret = expr.is_nonzero |
|
if ret is None: |
|
raise MDNotImplementedError |
|
return ret |
|
|
|
@NonZeroPredicate.register(Basic) |
|
def _(expr, assumptions): |
|
if ask(Q.real(expr)) is False: |
|
return False |
|
if expr.is_number: |
|
|
|
i = expr.evalf(2) |
|
def nonz(i): |
|
if i._prec != 1: |
|
return i != 0 |
|
return fuzzy_or(nonz(i) for i in i.as_real_imag()) |
|
|
|
@NonZeroPredicate.register(Add) |
|
def _(expr, assumptions): |
|
if all(ask(Q.positive(x), assumptions) for x in expr.args) \ |
|
or all(ask(Q.negative(x), assumptions) for x in expr.args): |
|
return True |
|
|
|
@NonZeroPredicate.register(Mul) |
|
def _(expr, assumptions): |
|
for arg in expr.args: |
|
result = ask(Q.nonzero(arg), assumptions) |
|
if result: |
|
continue |
|
return result |
|
return True |
|
|
|
@NonZeroPredicate.register(Pow) |
|
def _(expr, assumptions): |
|
return ask(Q.nonzero(expr.base), assumptions) |
|
|
|
@NonZeroPredicate.register(Abs) |
|
def _(expr, assumptions): |
|
return ask(Q.nonzero(expr.args[0]), assumptions) |
|
|
|
@NonZeroPredicate.register(NaN) |
|
def _(expr, assumptions): |
|
return None |
|
|
|
|
|
|
|
|
|
@ZeroPredicate.register(Expr) |
|
def _(expr, assumptions): |
|
ret = expr.is_zero |
|
if ret is None: |
|
raise MDNotImplementedError |
|
return ret |
|
|
|
@ZeroPredicate.register(Basic) |
|
def _(expr, assumptions): |
|
return fuzzy_and([fuzzy_not(ask(Q.nonzero(expr), assumptions)), |
|
ask(Q.real(expr), assumptions)]) |
|
|
|
@ZeroPredicate.register(Mul) |
|
def _(expr, assumptions): |
|
|
|
return fuzzy_or(ask(Q.zero(arg), assumptions) for arg in expr.args) |
|
|
|
|
|
|
|
|
|
@NonPositivePredicate.register(Expr) |
|
def _(expr, assumptions): |
|
ret = expr.is_nonpositive |
|
if ret is None: |
|
raise MDNotImplementedError |
|
return ret |
|
|
|
@NonPositivePredicate.register(Basic) |
|
def _(expr, assumptions): |
|
if expr.is_number: |
|
notpositive = fuzzy_not(_PositivePredicate_number(expr, assumptions)) |
|
if notpositive: |
|
return ask(Q.real(expr), assumptions) |
|
else: |
|
return notpositive |
|
|
|
|
|
|
|
|
|
def _PositivePredicate_number(expr, assumptions): |
|
r, i = expr.as_real_imag() |
|
|
|
|
|
|
|
|
|
if not i: |
|
r = r.evalf(2) |
|
if r._prec != 1: |
|
return r > 0 |
|
else: |
|
i = i.evalf(2) |
|
if i._prec != 1: |
|
if i != 0: |
|
return False |
|
r = r.evalf(2) |
|
if r._prec != 1: |
|
return r > 0 |
|
|
|
@PositivePredicate.register(Expr) |
|
def _(expr, assumptions): |
|
ret = expr.is_positive |
|
if ret is None: |
|
raise MDNotImplementedError |
|
return ret |
|
|
|
@PositivePredicate.register(Basic) |
|
def _(expr, assumptions): |
|
if expr.is_number: |
|
return _PositivePredicate_number(expr, assumptions) |
|
|
|
@PositivePredicate.register(Mul) |
|
def _(expr, assumptions): |
|
if expr.is_number: |
|
return _PositivePredicate_number(expr, assumptions) |
|
result = True |
|
for arg in expr.args: |
|
if ask(Q.positive(arg), assumptions): |
|
continue |
|
elif ask(Q.negative(arg), assumptions): |
|
result = result ^ True |
|
else: |
|
return |
|
return result |
|
|
|
@PositivePredicate.register(Add) |
|
def _(expr, assumptions): |
|
if expr.is_number: |
|
return _PositivePredicate_number(expr, assumptions) |
|
|
|
r = ask(Q.real(expr), assumptions) |
|
if r is not True: |
|
return r |
|
|
|
nonneg = 0 |
|
for arg in expr.args: |
|
if ask(Q.positive(arg), assumptions) is not True: |
|
if ask(Q.negative(arg), assumptions) is False: |
|
nonneg += 1 |
|
else: |
|
break |
|
else: |
|
if nonneg < len(expr.args): |
|
return True |
|
|
|
@PositivePredicate.register(Pow) |
|
def _(expr, assumptions): |
|
if expr.base == E: |
|
if ask(Q.real(expr.exp), assumptions): |
|
return True |
|
if ask(Q.imaginary(expr.exp), assumptions): |
|
return ask(Q.even(expr.exp/(I*pi)), assumptions) |
|
return |
|
|
|
if expr.is_number: |
|
return _PositivePredicate_number(expr, assumptions) |
|
if ask(Q.positive(expr.base), assumptions): |
|
if ask(Q.real(expr.exp), assumptions): |
|
return True |
|
if ask(Q.negative(expr.base), assumptions): |
|
if ask(Q.even(expr.exp), assumptions): |
|
return True |
|
if ask(Q.odd(expr.exp), assumptions): |
|
return False |
|
|
|
@PositivePredicate.register(exp) |
|
def _(expr, assumptions): |
|
if ask(Q.real(expr.exp), assumptions): |
|
return True |
|
if ask(Q.imaginary(expr.exp), assumptions): |
|
return ask(Q.even(expr.exp/(I*pi)), assumptions) |
|
|
|
@PositivePredicate.register(log) |
|
def _(expr, assumptions): |
|
r = ask(Q.real(expr.args[0]), assumptions) |
|
if r is not True: |
|
return r |
|
if ask(Q.positive(expr.args[0] - 1), assumptions): |
|
return True |
|
if ask(Q.negative(expr.args[0] - 1), assumptions): |
|
return False |
|
|
|
@PositivePredicate.register(factorial) |
|
def _(expr, assumptions): |
|
x = expr.args[0] |
|
if ask(Q.integer(x) & Q.positive(x), assumptions): |
|
return True |
|
|
|
@PositivePredicate.register(ImaginaryUnit) |
|
def _(expr, assumptions): |
|
return False |
|
|
|
@PositivePredicate.register(Abs) |
|
def _(expr, assumptions): |
|
return ask(Q.nonzero(expr), assumptions) |
|
|
|
@PositivePredicate.register(Trace) |
|
def _(expr, assumptions): |
|
if ask(Q.positive_definite(expr.arg), assumptions): |
|
return True |
|
|
|
@PositivePredicate.register(Determinant) |
|
def _(expr, assumptions): |
|
if ask(Q.positive_definite(expr.arg), assumptions): |
|
return True |
|
|
|
@PositivePredicate.register(MatrixElement) |
|
def _(expr, assumptions): |
|
if (expr.i == expr.j |
|
and ask(Q.positive_definite(expr.parent), assumptions)): |
|
return True |
|
|
|
@PositivePredicate.register(atan) |
|
def _(expr, assumptions): |
|
return ask(Q.positive(expr.args[0]), assumptions) |
|
|
|
@PositivePredicate.register(asin) |
|
def _(expr, assumptions): |
|
x = expr.args[0] |
|
if ask(Q.positive(x) & Q.nonpositive(x - 1), assumptions): |
|
return True |
|
if ask(Q.negative(x) & Q.nonnegative(x + 1), assumptions): |
|
return False |
|
|
|
@PositivePredicate.register(acos) |
|
def _(expr, assumptions): |
|
x = expr.args[0] |
|
if ask(Q.nonpositive(x - 1) & Q.nonnegative(x + 1), assumptions): |
|
return True |
|
|
|
@PositivePredicate.register(acot) |
|
def _(expr, assumptions): |
|
return ask(Q.real(expr.args[0]), assumptions) |
|
|
|
@PositivePredicate.register(NaN) |
|
def _(expr, assumptions): |
|
return None |
|
|
|
|
|
|
|
|
|
@ExtendedNegativePredicate.register(object) |
|
def _(expr, assumptions): |
|
return ask(Q.negative(expr) | Q.negative_infinite(expr), assumptions) |
|
|
|
|
|
|
|
|
|
@ExtendedPositivePredicate.register(object) |
|
def _(expr, assumptions): |
|
return ask(Q.positive(expr) | Q.positive_infinite(expr), assumptions) |
|
|
|
|
|
|
|
|
|
@ExtendedNonZeroPredicate.register(object) |
|
def _(expr, assumptions): |
|
return ask( |
|
Q.negative_infinite(expr) | Q.negative(expr) | Q.positive(expr) | Q.positive_infinite(expr), |
|
assumptions) |
|
|
|
|
|
|
|
|
|
@ExtendedNonPositivePredicate.register(object) |
|
def _(expr, assumptions): |
|
return ask( |
|
Q.negative_infinite(expr) | Q.negative(expr) | Q.zero(expr), |
|
assumptions) |
|
|
|
|
|
|
|
|
|
@ExtendedNonNegativePredicate.register(object) |
|
def _(expr, assumptions): |
|
return ask( |
|
Q.zero(expr) | Q.positive(expr) | Q.positive_infinite(expr), |
|
assumptions) |
|
|