123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- """
- Handlers related to order relations: positive, negative, etc.
- """
- from sympy.assumptions import Q, ask
- from sympy.core import Add, Basic, Expr, Mul, Pow
- 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,)
- # NegativePredicate
- def _NegativePredicate_number(expr, assumptions):
- r, i = expr.as_real_imag()
- # If the imaginary part can symbolically be shown to be zero then
- # we just evaluate the real part; otherwise we evaluate the imaginary
- # part to see if it actually evaluates to zero and if it does then
- # we make the comparison between the real part and zero.
- 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:
- # Exponential is always positive:
- 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
- @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
- @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:
- # if there are no symbols just evalf
- 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
- @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):
- # TODO: This should be deducible from the nonzero handler
- return fuzzy_or(ask(Q.zero(arg), assumptions) for arg in expr.args)
- # NonPositivePredicate
- @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
- # PositivePredicate
- def _PositivePredicate_number(expr, assumptions):
- r, i = expr.as_real_imag()
- # If the imaginary part can symbolically be shown to be zero then
- # we just evaluate the real part; otherwise we evaluate the imaginary
- # part to see if it actually evaluates to zero and if it does then
- # we make the comparison between the real part and zero.
- 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
- @ExtendedNegativePredicate.register(object)
- def _(expr, assumptions):
- return ask(Q.negative(expr) | Q.negative_infinite(expr), assumptions)
- # ExtendedPositivePredicate
- @ExtendedPositivePredicate.register(object)
- def _(expr, assumptions):
- return ask(Q.positive(expr) | Q.positive_infinite(expr), assumptions)
- # ExtendedNonZeroPredicate
- @ExtendedNonZeroPredicate.register(object)
- def _(expr, assumptions):
- return ask(
- Q.negative_infinite(expr) | Q.negative(expr) | Q.positive(expr) | Q.positive_infinite(expr),
- assumptions)
- # ExtendedNonPositivePredicate
- @ExtendedNonPositivePredicate.register(object)
- def _(expr, assumptions):
- return ask(
- Q.negative_infinite(expr) | Q.negative(expr) | Q.zero(expr),
- assumptions)
- # ExtendedNonNegativePredicate
- @ExtendedNonNegativePredicate.register(object)
- def _(expr, assumptions):
- return ask(
- Q.zero(expr) | Q.positive(expr) | Q.positive_infinite(expr),
- assumptions)
|