/

# Source code for sympy.assumptions.handlers.sets

"""
Handlers for predicates related to set membership: integer, rational, etc.
"""
from sympy.assumptions import Q, ask
from sympy.assumptions.handlers import CommonHandler

[docs]class AskIntegerHandler(CommonHandler):
"""
Handler for Q.integer
Test that an expression belongs to the field of integer numbers
"""

@staticmethod
def _number(expr, assumptions):
# helper method
try:
i = int(expr.round())
if not (expr - i).equals(0):
raise TypeError
return True
except TypeError:
return False

@staticmethod
[docs]    def Add(expr, assumptions):
"""
Integer + Integer       -> Integer
Integer + !Integer      -> !Integer
!Integer + !Integer -> ?
"""
if expr.is_number:
return AskIntegerHandler._number(expr, assumptions)
return test_closed_group(expr, assumptions, Q.integer)

@staticmethod
[docs]    def Mul(expr, assumptions):
"""
Integer*Integer      -> Integer
Integer*Irrational   -> !Integer
Odd/Even             -> !Integer
Integer*Rational     -> ?
"""
if expr.is_number:
return AskIntegerHandler._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
else:
return _output

Pow = Add

@staticmethod
def int(expr, assumptions):
return True

@staticmethod
def Integer(expr, assumptions):
return True

@staticmethod
def Rational(expr, assumptions):
# rationals with denominator one get
# evaluated to Integers
return False

@staticmethod
def Float(expr, assumptions):
return int(expr) == expr

@staticmethod
def Pi(expr, assumptions):
return False

@staticmethod
def Exp1(expr, assumptions):
return False

@staticmethod
def Infinity(expr, assumptions):
return False

@staticmethod
def NegativeInfinity(expr, assumptions):
return False

@staticmethod
def ImaginaryUnit(expr, assumptions):
return False

@staticmethod
def Abs(expr, assumptions):
return ask(Q.integer(expr.args[0]), assumptions)

[docs]class AskRationalHandler(CommonHandler):
"""
Handler for Q.rational
Test that an expression belongs to the field of rational numbers
"""

@staticmethod
[docs]    def Add(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)

Mul = Add

@staticmethod
[docs]    def Pow(expr, assumptions):
"""
Rational ** Integer      -> Rational
Irrational ** Rational   -> Irrational
Rational ** Irrational   -> ?
"""
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

@staticmethod
def Rational(expr, assumptions):
return True

@staticmethod
def Float(expr, assumptions):
# it's finite-precision
return True

@staticmethod
def ImaginaryUnit(expr, assumptions):
return False

@staticmethod
def Infinity(expr, assumptions):
return False

@staticmethod
def NegativeInfinity(expr, assumptions):
return False

@staticmethod
def Pi(expr, assumptions):
return False

@staticmethod
def Exp1(expr, assumptions):
return False

class AskIrrationalHandler(CommonHandler):

@staticmethod
def Basic(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

[docs]class AskRealHandler(CommonHandler):
"""
Handler for Q.real
Test that an expression belongs to the field of real numbers
"""

@staticmethod
def _number(expr, assumptions):
return not expr.as_real_imag()[1]

@staticmethod
[docs]    def Add(expr, assumptions):
"""
Real + Real              -> Real
Real + (Complex & !Real) -> !Real
"""
if expr.is_number:
return AskRealHandler._number(expr, assumptions)
return test_closed_group(expr, assumptions, Q.real)

@staticmethod
[docs]    def Mul(expr, assumptions):
"""
Real*Real               -> Real
Real*Imaginary          -> !Real
Imaginary*Imaginary     -> Real
"""
if expr.is_number:
return AskRealHandler._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

@staticmethod
[docs]    def Pow(expr, assumptions):
"""
Real**Integer         -> Real
Positive**Real        -> Real
Real**(Integer/Even)  -> Real if base is nonnegative
Real**(Integer/Odd)   -> Real
"""
if expr.is_number:
return AskRealHandler._number(expr, assumptions)
if ask(Q.real(expr.base), assumptions):
if ask(Q.integer(expr.exp), assumptions):
return True
elif expr.exp.is_Rational:
if (expr.exp.q % 2 == 0):
return ask(Q.real(expr.base), assumptions) and \
not ask(Q.negative(expr.base), assumptions)
else: return True
elif ask(Q.real(expr.exp), assumptions):
if ask(Q.positive(expr.base), assumptions):
return True

@staticmethod
def Rational(expr, assumptions):
return True

@staticmethod
def Float(expr, assumptions):
return True

@staticmethod
def Pi(expr, assumptions):
return True

@staticmethod
def Exp1(expr, assumptions):
return True

@staticmethod
def Abs(expr, assumptions):
return True

@staticmethod
def re(expr, assumptions):
return True

im = re

@staticmethod
def ImaginaryUnit(expr, assumptions):
return False

@staticmethod
def Infinity(expr, assumptions):
return False

@staticmethod
def NegativeInfinity(expr, assumptions):
return False

@staticmethod
def sin(expr, assumptions):
if ask(Q.real(expr.args[0]), assumptions):
return True

cos, exp = sin, sin

[docs]class AskExtendedRealHandler(AskRealHandler):
"""
Handler for Q.extended_real
Test that an expression belongs to the field of extended real numbers,
that is real numbers union {Infinity, -Infinity}
"""

@staticmethod
def Add(expr, assumptions):
return test_closed_group(expr, assumptions, Q.extended_real)

Mul, Pow = Add, Add

@staticmethod
def Infinity(expr, assumptions):
return True

@staticmethod
def NegativeInfinity(expr, assumptions):
return True

[docs]class AskHermitianHandler(AskRealHandler):
"""
Handler for Q.hermitian
Test that an expression belongs to the field of Hermitian operators
"""

@staticmethod
[docs]    def Add(expr, assumptions):
"""
Hermitian + Hermitian  -> Hermitian
Hermitian + !Hermitian -> !Hermitian
"""
if expr.is_number:
return AskRealHandler._number(expr, assumptions)
return test_closed_group(expr, assumptions, Q.hermitian)

@staticmethod
[docs]    def Mul(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:
return AskRealHandler._number(expr, assumptions)
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

@staticmethod
[docs]    def Pow(expr, assumptions):
"""
Hermitian**Integer -> Hermitian
"""
if expr.is_number:
return AskRealHandler._number(expr, assumptions)
if ask(Q.hermitian(expr.base), assumptions):
if ask(Q.integer(expr.exp), assumptions):
return True

@staticmethod
def sin(expr, assumptions):
if ask(Q.hermitian(expr.args[0]), assumptions):
return True

cos, exp = sin, sin

[docs]class AskComplexHandler(CommonHandler):
"""
Handler for Q.complex
Test that an expression belongs to the field of complex numbers
"""

@staticmethod
def Add(expr, assumptions):
return test_closed_group(expr, assumptions, Q.complex)

Mul, Pow = Add, Add

@staticmethod
def Number(expr, assumptions):
return True

@staticmethod
def NumberSymbol(expr, assumptions):
return True

@staticmethod
def Abs(expr, assumptions):
return True

@staticmethod
def ImaginaryUnit(expr, assumptions):
return True

@staticmethod
def Infinity(expr, assumptions):
return False

@staticmethod
def NegativeInfinity(expr, assumptions):
return False

sin, cos, exp, re, im = [Abs]*5 # they are all complex functions

[docs]class AskImaginaryHandler(CommonHandler):
"""
Handler for Q.imaginary
Test that an expression belongs to the field of imaginary numbers,
that is, numbers in the form x*I, where x is real
"""

@staticmethod
def _number(expr, assumptions):
# helper method
return not expr.as_real_imag()[0]

@staticmethod
[docs]    def Add(expr, assumptions):
"""
Imaginary + Imaginary -> Imaginary
Imaginary + Complex   -> ?
Imaginary + Real      -> !Imaginary
"""
if expr.is_number:
return AskImaginaryHandler._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 == 1 or (len(expr.args) == reals):
# two reals could sum 0 thus giving an imaginary
return False

@staticmethod
[docs]    def Mul(expr, assumptions):
"""
Real*Imaginary      -> Imaginary
Imaginary*Imaginary -> Real
"""
if expr.is_number:
return AskImaginaryHandler._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

Pow = Add

@staticmethod
def Number(expr, assumptions):
return not (expr.as_real_imag()[1] == 0)

NumberSymbol = Number

@staticmethod
def ImaginaryUnit(expr, assumptions):
return True

[docs]class AskAntiHermitianHandler(AskImaginaryHandler):
"""
Handler for Q.antihermitian
Test that an expression belongs to the field of anti-Hermitian operators,
that is, operators in the form x*I, where x is Hermitian
"""

@staticmethod
[docs]    def Add(expr, assumptions):
"""
Antihermitian + Antihermitian  -> Antihermitian
Antihermitian + !Antihermitian -> !Antihermitian
"""
if expr.is_number:
return AskImaginaryHandler._number(expr, assumptions)
return test_closed_group(expr, assumptions, Q.antihermitian)

@staticmethod
[docs]    def Mul(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:
return AskImaginaryHandler._number(expr, assumptions)
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

@staticmethod
[docs]    def Pow(expr, assumptions):
"""
Hermitian**Integer  -> !Antihermitian
Antihermitian**Even -> !Antihermitian
Antihermitian**Odd  -> Antihermitian
"""
if expr.is_number:
return AskImaginaryHandler._number(expr, assumptions)
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

[docs]class AskAlgebraicHandler(CommonHandler):
"""Handler for Q.algebraic key. """

@staticmethod
def Add(expr, assumptions):
return test_closed_group(expr, assumptions, Q.algebraic)

@staticmethod
def Mul(expr, assumptions):
return test_closed_group(expr, assumptions, Q.algebraic)

@staticmethod
def Pow(expr, assumptions):
return expr.exp.is_Rational and ask(Q.algebraic(expr.base), assumptions)

@staticmethod
def Number(expr, assumptions):
return False

@staticmethod
def Rational(expr, assumptions):
return expr.q != 0

@staticmethod
def ImaginaryUnit(expr, assumptions):
return True

@staticmethod
def AlgebraicNumber(expr, assumptions):
return True

#### Helper methods

[docs]def test_closed_group(expr, assumptions, key):
"""
Test for membership in a group with respect
to the current operation
"""
result = True
for arg in expr.args:
_out = ask(key(arg), assumptions)
if _out is None: break
elif _out is False:
if result: result = False
else: break
else:
return result