123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772 |
- """
- Handlers for predicates related to set membership: integer, rational, etc.
- """
- from sympy.assumptions import Q, ask
- from sympy.core import Add, Basic, Expr, Mul, Pow, S
- from sympy.core.numbers import (AlgebraicNumber, ComplexInfinity, Exp1, Float,
- GoldenRatio, ImaginaryUnit, Infinity, Integer, NaN, NegativeInfinity,
- Number, NumberSymbol, Pi, pi, Rational, TribonacciConstant, E)
- from sympy.core.logic import fuzzy_bool
- from sympy.functions import (Abs, acos, acot, asin, atan, cos, cot, exp, im,
- log, re, sin, tan)
- from sympy.core.numbers import I
- from sympy.core.relational import Eq
- from sympy.functions.elementary.complexes import conjugate
- from sympy.matrices import Determinant, MatrixBase, Trace
- from sympy.matrices.expressions.matexpr import MatrixElement
- from sympy.multipledispatch import MDNotImplementedError
- from .common import test_closed_group
- from ..predicates.sets import (IntegerPredicate, RationalPredicate,
- IrrationalPredicate, RealPredicate, ExtendedRealPredicate,
- HermitianPredicate, ComplexPredicate, ImaginaryPredicate,
- AntihermitianPredicate, AlgebraicPredicate)
- # IntegerPredicate
- def _IntegerPredicate_number(expr, assumptions):
- # helper function
- try:
- i = int(expr.round())
- if not (expr - i).equals(0):
- raise TypeError
- return True
- except TypeError:
- return False
- @IntegerPredicate.register_many(int, Integer) # type:ignore
- def _(expr, assumptions):
- return True
- @IntegerPredicate.register_many(Exp1, GoldenRatio, ImaginaryUnit, Infinity,
- NegativeInfinity, Pi, Rational, TribonacciConstant)
- def _(expr, assumptions):
- return False
- @IntegerPredicate.register(Expr)
- def _(expr, assumptions):
- ret = expr.is_integer
- if ret is None:
- raise MDNotImplementedError
- return ret
- @IntegerPredicate.register_many(Add, Pow)
- def _(expr, assumptions):
- """
- * Integer + Integer -> Integer
- * Integer + !Integer -> !Integer
- * !Integer + !Integer -> ?
- """
- if expr.is_number:
- return _IntegerPredicate_number(expr, assumptions)
- return test_closed_group(expr, assumptions, Q.integer)
- @IntegerPredicate.register(Mul)
- def _(expr, assumptions):
- """
- * Integer*Integer -> Integer
- * Integer*Irrational -> !Integer
- * Odd/Even -> !Integer
- * Integer*Rational -> ?
- """
- if expr.is_number:
- return _IntegerPredicate_number(expr, assumptions)
- _output = True
- for arg in expr.args:
- if not ask(Q.integer(arg), assumptions):
- if arg.is_Rational:
- if arg.q == 2:
- return ask(Q.even(2*expr), assumptions)
- if ~(arg.q & 1):
- return None
- elif ask(Q.irrational(arg), assumptions):
- if _output:
- _output = False
- else:
- return
- else:
- return
- return _output
- @IntegerPredicate.register(Abs)
- def _(expr, assumptions):
- return ask(Q.integer(expr.args[0]), assumptions)
- @IntegerPredicate.register_many(Determinant, MatrixElement, Trace)
- def _(expr, assumptions):
- return ask(Q.integer_elements(expr.args[0]), assumptions)
- # RationalPredicate
- @RationalPredicate.register(Rational)
- def _(expr, assumptions):
- return True
- @RationalPredicate.register(Float)
- def _(expr, assumptions):
- return None
- @RationalPredicate.register_many(Exp1, GoldenRatio, ImaginaryUnit, Infinity,
- NegativeInfinity, Pi, TribonacciConstant)
- def _(expr, assumptions):
- return False
- @RationalPredicate.register(Expr)
- def _(expr, assumptions):
- ret = expr.is_rational
- if ret is None:
- raise MDNotImplementedError
- return ret
- @RationalPredicate.register_many(Add, Mul)
- def _(expr, assumptions):
- """
- * Rational + Rational -> Rational
- * Rational + !Rational -> !Rational
- * !Rational + !Rational -> ?
- """
- if expr.is_number:
- if expr.as_real_imag()[1]:
- return False
- return test_closed_group(expr, assumptions, Q.rational)
- @RationalPredicate.register(Pow)
- def _(expr, assumptions):
- """
- * Rational ** Integer -> Rational
- * Irrational ** Rational -> Irrational
- * Rational ** Irrational -> ?
- """
- if expr.base == E:
- x = expr.exp
- if ask(Q.rational(x), assumptions):
- return ask(~Q.nonzero(x), assumptions)
- return
- if ask(Q.integer(expr.exp), assumptions):
- return ask(Q.rational(expr.base), assumptions)
- elif ask(Q.rational(expr.exp), assumptions):
- if ask(Q.prime(expr.base), assumptions):
- return False
- @RationalPredicate.register_many(asin, atan, cos, sin, tan)
- def _(expr, assumptions):
- x = expr.args[0]
- if ask(Q.rational(x), assumptions):
- return ask(~Q.nonzero(x), assumptions)
- @RationalPredicate.register(exp)
- def _(expr, assumptions):
- x = expr.exp
- if ask(Q.rational(x), assumptions):
- return ask(~Q.nonzero(x), assumptions)
- @RationalPredicate.register_many(acot, cot)
- def _(expr, assumptions):
- x = expr.args[0]
- if ask(Q.rational(x), assumptions):
- return False
- @RationalPredicate.register_many(acos, log)
- def _(expr, assumptions):
- x = expr.args[0]
- if ask(Q.rational(x), assumptions):
- return ask(~Q.nonzero(x - 1), assumptions)
- # IrrationalPredicate
- @IrrationalPredicate.register(Expr)
- def _(expr, assumptions):
- ret = expr.is_irrational
- if ret is None:
- raise MDNotImplementedError
- return ret
- @IrrationalPredicate.register(Basic)
- def _(expr, assumptions):
- _real = ask(Q.real(expr), assumptions)
- if _real:
- _rational = ask(Q.rational(expr), assumptions)
- if _rational is None:
- return None
- return not _rational
- else:
- return _real
- # RealPredicate
- def _RealPredicate_number(expr, assumptions):
- # let as_real_imag() work first since the expression may
- # be simpler to evaluate
- i = expr.as_real_imag()[1].evalf(2)
- if i._prec != 1:
- return not i
- # allow None to be returned if we couldn't show for sure
- # that i was 0
- @RealPredicate.register_many(Abs, Exp1, Float, GoldenRatio, im, Pi, Rational,
- re, TribonacciConstant)
- def _(expr, assumptions):
- return True
- @RealPredicate.register_many(ImaginaryUnit, Infinity, NegativeInfinity)
- def _(expr, assumptions):
- return False
- @RealPredicate.register(Expr)
- def _(expr, assumptions):
- ret = expr.is_real
- if ret is None:
- raise MDNotImplementedError
- return ret
- @RealPredicate.register(Add)
- def _(expr, assumptions):
- """
- * Real + Real -> Real
- * Real + (Complex & !Real) -> !Real
- """
- if expr.is_number:
- return _RealPredicate_number(expr, assumptions)
- return test_closed_group(expr, assumptions, Q.real)
- @RealPredicate.register(Mul)
- def _(expr, assumptions):
- """
- * Real*Real -> Real
- * Real*Imaginary -> !Real
- * Imaginary*Imaginary -> Real
- """
- if expr.is_number:
- return _RealPredicate_number(expr, assumptions)
- result = True
- for arg in expr.args:
- if ask(Q.real(arg), assumptions):
- pass
- elif ask(Q.imaginary(arg), assumptions):
- result = result ^ True
- else:
- break
- else:
- return result
- @RealPredicate.register(Pow)
- def _(expr, assumptions):
- """
- * Real**Integer -> Real
- * Positive**Real -> Real
- * Real**(Integer/Even) -> Real if base is nonnegative
- * Real**(Integer/Odd) -> Real
- * Imaginary**(Integer/Even) -> Real
- * Imaginary**(Integer/Odd) -> not Real
- * Imaginary**Real -> ? since Real could be 0 (giving real)
- or 1 (giving imaginary)
- * b**Imaginary -> Real if log(b) is imaginary and b != 0
- and exponent != integer multiple of
- I*pi/log(b)
- * Real**Real -> ? e.g. sqrt(-1) is imaginary and
- sqrt(2) is not
- """
- if expr.is_number:
- return _RealPredicate_number(expr, assumptions)
- if expr.base == E:
- return ask(
- Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions
- )
- if expr.base.func == exp or (expr.base.is_Pow and expr.base.base == E):
- if ask(Q.imaginary(expr.base.exp), assumptions):
- if ask(Q.imaginary(expr.exp), assumptions):
- return True
- # If the i = (exp's arg)/(I*pi) is an integer or half-integer
- # multiple of I*pi then 2*i will be an integer. In addition,
- # exp(i*I*pi) = (-1)**i so the overall realness of the expr
- # can be determined by replacing exp(i*I*pi) with (-1)**i.
- i = expr.base.exp/I/pi
- if ask(Q.integer(2*i), assumptions):
- return ask(Q.real((S.NegativeOne**i)**expr.exp), assumptions)
- return
- if ask(Q.imaginary(expr.base), assumptions):
- if ask(Q.integer(expr.exp), assumptions):
- odd = ask(Q.odd(expr.exp), assumptions)
- if odd is not None:
- return not odd
- return
- if ask(Q.imaginary(expr.exp), assumptions):
- imlog = ask(Q.imaginary(log(expr.base)), assumptions)
- if imlog is not None:
- # I**i -> real, log(I) is imag;
- # (2*I)**i -> complex, log(2*I) is not imag
- return imlog
- if ask(Q.real(expr.base), assumptions):
- if ask(Q.real(expr.exp), assumptions):
- if expr.exp.is_Rational and \
- ask(Q.even(expr.exp.q), assumptions):
- return ask(Q.positive(expr.base), assumptions)
- elif ask(Q.integer(expr.exp), assumptions):
- return True
- elif ask(Q.positive(expr.base), assumptions):
- return True
- elif ask(Q.negative(expr.base), assumptions):
- return False
- @RealPredicate.register_many(cos, sin)
- def _(expr, assumptions):
- if ask(Q.real(expr.args[0]), assumptions):
- return True
- @RealPredicate.register(exp)
- def _(expr, assumptions):
- return ask(
- Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions
- )
- @RealPredicate.register(log)
- def _(expr, assumptions):
- return ask(Q.positive(expr.args[0]), assumptions)
- @RealPredicate.register_many(Determinant, MatrixElement, Trace)
- def _(expr, assumptions):
- return ask(Q.real_elements(expr.args[0]), assumptions)
- # ExtendedRealPredicate
- @ExtendedRealPredicate.register(object)
- def _(expr, assumptions):
- return ask(Q.negative_infinite(expr)
- | Q.negative(expr)
- | Q.zero(expr)
- | Q.positive(expr)
- | Q.positive_infinite(expr),
- assumptions)
- @ExtendedRealPredicate.register_many(Infinity, NegativeInfinity)
- def _(expr, assumptions):
- return True
- @ExtendedRealPredicate.register_many(Add, Mul, Pow) # type:ignore
- def _(expr, assumptions):
- return test_closed_group(expr, assumptions, Q.extended_real)
- # HermitianPredicate
- @HermitianPredicate.register(object) # type:ignore
- def _(expr, assumptions):
- if isinstance(expr, MatrixBase):
- return None
- return ask(Q.real(expr), assumptions)
- @HermitianPredicate.register(Add) # type:ignore
- def _(expr, assumptions):
- """
- * Hermitian + Hermitian -> Hermitian
- * Hermitian + !Hermitian -> !Hermitian
- """
- if expr.is_number:
- raise MDNotImplementedError
- return test_closed_group(expr, assumptions, Q.hermitian)
- @HermitianPredicate.register(Mul) # type:ignore
- def _(expr, assumptions):
- """
- As long as there is at most only one noncommutative term:
- * Hermitian*Hermitian -> Hermitian
- * Hermitian*Antihermitian -> !Hermitian
- * Antihermitian*Antihermitian -> Hermitian
- """
- if expr.is_number:
- raise MDNotImplementedError
- nccount = 0
- result = True
- for arg in expr.args:
- if ask(Q.antihermitian(arg), assumptions):
- result = result ^ True
- elif not ask(Q.hermitian(arg), assumptions):
- break
- if ask(~Q.commutative(arg), assumptions):
- nccount += 1
- if nccount > 1:
- break
- else:
- return result
- @HermitianPredicate.register(Pow) # type:ignore
- def _(expr, assumptions):
- """
- * Hermitian**Integer -> Hermitian
- """
- if expr.is_number:
- raise MDNotImplementedError
- if expr.base == E:
- if ask(Q.hermitian(expr.exp), assumptions):
- return True
- raise MDNotImplementedError
- if ask(Q.hermitian(expr.base), assumptions):
- if ask(Q.integer(expr.exp), assumptions):
- return True
- raise MDNotImplementedError
- @HermitianPredicate.register_many(cos, sin) # type:ignore
- def _(expr, assumptions):
- if ask(Q.hermitian(expr.args[0]), assumptions):
- return True
- raise MDNotImplementedError
- @HermitianPredicate.register(exp) # type:ignore
- def _(expr, assumptions):
- if ask(Q.hermitian(expr.exp), assumptions):
- return True
- raise MDNotImplementedError
- @HermitianPredicate.register(MatrixBase) # type:ignore
- def _(mat, assumptions):
- rows, cols = mat.shape
- ret_val = True
- for i in range(rows):
- for j in range(i, cols):
- cond = fuzzy_bool(Eq(mat[i, j], conjugate(mat[j, i])))
- if cond is None:
- ret_val = None
- if cond == False:
- return False
- if ret_val is None:
- raise MDNotImplementedError
- return ret_val
- # ComplexPredicate
- @ComplexPredicate.register_many(Abs, cos, exp, im, ImaginaryUnit, log, Number, # type:ignore
- NumberSymbol, re, sin)
- def _(expr, assumptions):
- return True
- @ComplexPredicate.register_many(Infinity, NegativeInfinity) # type:ignore
- def _(expr, assumptions):
- return False
- @ComplexPredicate.register(Expr) # type:ignore
- def _(expr, assumptions):
- ret = expr.is_complex
- if ret is None:
- raise MDNotImplementedError
- return ret
- @ComplexPredicate.register_many(Add, Mul) # type:ignore
- def _(expr, assumptions):
- return test_closed_group(expr, assumptions, Q.complex)
- @ComplexPredicate.register(Pow) # type:ignore
- def _(expr, assumptions):
- if expr.base == E:
- return True
- return test_closed_group(expr, assumptions, Q.complex)
- @ComplexPredicate.register_many(Determinant, MatrixElement, Trace) # type:ignore
- def _(expr, assumptions):
- return ask(Q.complex_elements(expr.args[0]), assumptions)
- @ComplexPredicate.register(NaN) # type:ignore
- def _(expr, assumptions):
- return None
- # ImaginaryPredicate
- def _Imaginary_number(expr, assumptions):
- # let as_real_imag() work first since the expression may
- # be simpler to evaluate
- r = expr.as_real_imag()[0].evalf(2)
- if r._prec != 1:
- return not r
- # allow None to be returned if we couldn't show for sure
- # that r was 0
- @ImaginaryPredicate.register(ImaginaryUnit) # type:ignore
- def _(expr, assumptions):
- return True
- @ImaginaryPredicate.register(Expr) # type:ignore
- def _(expr, assumptions):
- ret = expr.is_imaginary
- if ret is None:
- raise MDNotImplementedError
- return ret
- @ImaginaryPredicate.register(Add) # type:ignore
- def _(expr, assumptions):
- """
- * Imaginary + Imaginary -> Imaginary
- * Imaginary + Complex -> ?
- * Imaginary + Real -> !Imaginary
- """
- if expr.is_number:
- return _Imaginary_number(expr, assumptions)
- reals = 0
- for arg in expr.args:
- if ask(Q.imaginary(arg), assumptions):
- pass
- elif ask(Q.real(arg), assumptions):
- reals += 1
- else:
- break
- else:
- if reals == 0:
- return True
- if reals in (1, len(expr.args)):
- # two reals could sum 0 thus giving an imaginary
- return False
- @ImaginaryPredicate.register(Mul) # type:ignore
- def _(expr, assumptions):
- """
- * Real*Imaginary -> Imaginary
- * Imaginary*Imaginary -> Real
- """
- if expr.is_number:
- return _Imaginary_number(expr, assumptions)
- result = False
- reals = 0
- for arg in expr.args:
- if ask(Q.imaginary(arg), assumptions):
- result = result ^ True
- elif not ask(Q.real(arg), assumptions):
- break
- else:
- if reals == len(expr.args):
- return False
- return result
- @ImaginaryPredicate.register(Pow) # type:ignore
- def _(expr, assumptions):
- """
- * Imaginary**Odd -> Imaginary
- * Imaginary**Even -> Real
- * b**Imaginary -> !Imaginary if exponent is an integer
- multiple of I*pi/log(b)
- * Imaginary**Real -> ?
- * Positive**Real -> Real
- * Negative**Integer -> Real
- * Negative**(Integer/2) -> Imaginary
- * Negative**Real -> not Imaginary if exponent is not Rational
- """
- if expr.is_number:
- return _Imaginary_number(expr, assumptions)
- if expr.base == E:
- a = expr.exp/I/pi
- return ask(Q.integer(2*a) & ~Q.integer(a), assumptions)
- if expr.base.func == exp or (expr.base.is_Pow and expr.base.base == E):
- if ask(Q.imaginary(expr.base.exp), assumptions):
- if ask(Q.imaginary(expr.exp), assumptions):
- return False
- i = expr.base.exp/I/pi
- if ask(Q.integer(2*i), assumptions):
- return ask(Q.imaginary((S.NegativeOne**i)**expr.exp), assumptions)
- if ask(Q.imaginary(expr.base), assumptions):
- if ask(Q.integer(expr.exp), assumptions):
- odd = ask(Q.odd(expr.exp), assumptions)
- if odd is not None:
- return odd
- return
- if ask(Q.imaginary(expr.exp), assumptions):
- imlog = ask(Q.imaginary(log(expr.base)), assumptions)
- if imlog is not None:
- # I**i -> real; (2*I)**i -> complex ==> not imaginary
- return False
- if ask(Q.real(expr.base) & Q.real(expr.exp), assumptions):
- if ask(Q.positive(expr.base), assumptions):
- return False
- else:
- rat = ask(Q.rational(expr.exp), assumptions)
- if not rat:
- return rat
- if ask(Q.integer(expr.exp), assumptions):
- return False
- else:
- half = ask(Q.integer(2*expr.exp), assumptions)
- if half:
- return ask(Q.negative(expr.base), assumptions)
- return half
- @ImaginaryPredicate.register(log) # type:ignore
- def _(expr, assumptions):
- if ask(Q.real(expr.args[0]), assumptions):
- if ask(Q.positive(expr.args[0]), assumptions):
- return False
- return
- # XXX it should be enough to do
- # return ask(Q.nonpositive(expr.args[0]), assumptions)
- # but ask(Q.nonpositive(exp(x)), Q.imaginary(x)) -> None;
- # it should return True since exp(x) will be either 0 or complex
- if expr.args[0].func == exp or (expr.args[0].is_Pow and expr.args[0].base == E):
- if expr.args[0].exp in [I, -I]:
- return True
- im = ask(Q.imaginary(expr.args[0]), assumptions)
- if im is False:
- return False
- @ImaginaryPredicate.register(exp) # type:ignore
- def _(expr, assumptions):
- a = expr.exp/I/pi
- return ask(Q.integer(2*a) & ~Q.integer(a), assumptions)
- @ImaginaryPredicate.register_many(Number, NumberSymbol) # type:ignore
- def _(expr, assumptions):
- return not (expr.as_real_imag()[1] == 0)
- @ImaginaryPredicate.register(NaN) # type:ignore
- def _(expr, assumptions):
- return None
- # AntihermitianPredicate
- @AntihermitianPredicate.register(object) # type:ignore
- def _(expr, assumptions):
- if isinstance(expr, MatrixBase):
- return None
- if ask(Q.zero(expr), assumptions):
- return True
- return ask(Q.imaginary(expr), assumptions)
- @AntihermitianPredicate.register(Add) # type:ignore
- def _(expr, assumptions):
- """
- * Antihermitian + Antihermitian -> Antihermitian
- * Antihermitian + !Antihermitian -> !Antihermitian
- """
- if expr.is_number:
- raise MDNotImplementedError
- return test_closed_group(expr, assumptions, Q.antihermitian)
- @AntihermitianPredicate.register(Mul) # type:ignore
- def _(expr, assumptions):
- """
- As long as there is at most only one noncommutative term:
- * Hermitian*Hermitian -> !Antihermitian
- * Hermitian*Antihermitian -> Antihermitian
- * Antihermitian*Antihermitian -> !Antihermitian
- """
- if expr.is_number:
- raise MDNotImplementedError
- nccount = 0
- result = False
- for arg in expr.args:
- if ask(Q.antihermitian(arg), assumptions):
- result = result ^ True
- elif not ask(Q.hermitian(arg), assumptions):
- break
- if ask(~Q.commutative(arg), assumptions):
- nccount += 1
- if nccount > 1:
- break
- else:
- return result
- @AntihermitianPredicate.register(Pow) # type:ignore
- def _(expr, assumptions):
- """
- * Hermitian**Integer -> !Antihermitian
- * Antihermitian**Even -> !Antihermitian
- * Antihermitian**Odd -> Antihermitian
- """
- if expr.is_number:
- raise MDNotImplementedError
- if ask(Q.hermitian(expr.base), assumptions):
- if ask(Q.integer(expr.exp), assumptions):
- return False
- elif ask(Q.antihermitian(expr.base), assumptions):
- if ask(Q.even(expr.exp), assumptions):
- return False
- elif ask(Q.odd(expr.exp), assumptions):
- return True
- raise MDNotImplementedError
- @AntihermitianPredicate.register(MatrixBase) # type:ignore
- def _(mat, assumptions):
- rows, cols = mat.shape
- ret_val = True
- for i in range(rows):
- for j in range(i, cols):
- cond = fuzzy_bool(Eq(mat[i, j], -conjugate(mat[j, i])))
- if cond is None:
- ret_val = None
- if cond == False:
- return False
- if ret_val is None:
- raise MDNotImplementedError
- return ret_val
- # AlgebraicPredicate
- @AlgebraicPredicate.register_many(AlgebraicNumber, Float, GoldenRatio, # type:ignore
- ImaginaryUnit, TribonacciConstant)
- def _(expr, assumptions):
- return True
- @AlgebraicPredicate.register_many(ComplexInfinity, Exp1, Infinity, # type:ignore
- NegativeInfinity, Pi)
- def _(expr, assumptions):
- return False
- @AlgebraicPredicate.register_many(Add, Mul) # type:ignore
- def _(expr, assumptions):
- return test_closed_group(expr, assumptions, Q.algebraic)
- @AlgebraicPredicate.register(Pow) # type:ignore
- def _(expr, assumptions):
- if expr.base == E:
- if ask(Q.algebraic(expr.exp), assumptions):
- return ask(~Q.nonzero(expr.exp), assumptions)
- return
- return expr.exp.is_Rational and ask(Q.algebraic(expr.base), assumptions)
- @AlgebraicPredicate.register(Rational) # type:ignore
- def _(expr, assumptions):
- return expr.q != 0
- @AlgebraicPredicate.register_many(asin, atan, cos, sin, tan) # type:ignore
- def _(expr, assumptions):
- x = expr.args[0]
- if ask(Q.algebraic(x), assumptions):
- return ask(~Q.nonzero(x), assumptions)
- @AlgebraicPredicate.register(exp) # type:ignore
- def _(expr, assumptions):
- x = expr.exp
- if ask(Q.algebraic(x), assumptions):
- return ask(~Q.nonzero(x), assumptions)
- @AlgebraicPredicate.register_many(acot, cot) # type:ignore
- def _(expr, assumptions):
- x = expr.args[0]
- if ask(Q.algebraic(x), assumptions):
- return False
- @AlgebraicPredicate.register_many(acos, log) # type:ignore
- def _(expr, assumptions):
- x = expr.args[0]
- if ask(Q.algebraic(x), assumptions):
- return ask(~Q.nonzero(x - 1), assumptions)
|