# Source code for sympy.assumptions.handlers.sets

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

"""
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
"""
Integer + Integer       -> Integer
Integer + !Integer      -> !Integer
!Integer + !Integer -> ?
"""
if expr.is_number:
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:
_output = True
for arg in expr.args:
if arg.is_Rational:
if arg.q == 2:
if ~(arg.q & 1):
return None
if _output:
_output = False
else:
return
else:
return
else:
return _output

int, Integer = [staticmethod(CommonHandler.AlwaysTrue)]*2

Pi, Exp1, GoldenRatio, Infinity, NegativeInfinity, ImaginaryUnit = \
[staticmethod(CommonHandler.AlwaysFalse)]*6

@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 Abs(expr, assumptions):

@staticmethod
def MatrixElement(expr, assumptions):

Determinant = Trace = MatrixElement

"""
Handler for Q.rational
Test that an expression belongs to the field of rational numbers
"""

@staticmethod
"""
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)

@staticmethod
[docs]    def Pow(expr, assumptions):
"""
Rational ** Integer      -> Rational
Irrational ** Rational   -> Irrational
Rational ** Irrational   -> ?
"""
return False

Rational, Float = \
[staticmethod(CommonHandler.AlwaysTrue)]*2 # Float is finite-precision

ImaginaryUnit, Infinity, NegativeInfinity, Pi, Exp1, GoldenRatio = \
[staticmethod(CommonHandler.AlwaysFalse)]*6

@staticmethod
def exp(expr, assumptions):
x = expr.args[0]

@staticmethod
def cot(expr, assumptions):
x = expr.args[0]
return False

@staticmethod
def log(expr, assumptions):
x = expr.args[0]

sin, cos, tan, asin, atan = [exp]*5
acos, acot = log, cot

@staticmethod
def Basic(expr, assumptions):
if _real:
if _rational is None:
return None
return not _rational
else:
return _real

"""
Handler for Q.real
Test that an expression belongs to the field of real numbers
"""

@staticmethod
def _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

@staticmethod
"""
Real + Real              -> Real
Real + (Complex & !Real) -> !Real
"""
if expr.is_number:
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:
result = True
for arg in expr.args:
pass
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
Real**Imaginary       -> ?
Imaginary**Real       -> ?
Real**Real            -> ?
"""
if expr.is_number:
return False
return True
if expr.exp.is_Rational and \
return True
return True
return False

Rational, Float, Pi, Exp1, GoldenRatio, Abs, re, im = \
[staticmethod(CommonHandler.AlwaysTrue)]*8

ImaginaryUnit, Infinity, NegativeInfinity = \
[staticmethod(CommonHandler.AlwaysFalse)]*3

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

cos, exp = [sin]*2

@staticmethod
def MatrixElement(expr, assumptions):

Determinant = Trace = MatrixElement

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

"""
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
return test_closed_group(expr, assumptions, Q.extended_real)

Infinity, NegativeInfinity = [staticmethod(CommonHandler.AlwaysTrue)]*2

"""
Handler for Q.hermitian
Test that an expression belongs to the field of Hermitian operators
"""

@staticmethod
"""
Hermitian + Hermitian  -> Hermitian
Hermitian + !Hermitian -> !Hermitian
"""
if expr.is_number:
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:
nccount = 0
result = True
for arg in expr.args:
result = result ^ True
break
nccount += 1
if nccount > 1:
break
else:
return result

@staticmethod
[docs]    def Pow(expr, assumptions):
"""
Hermitian**Integer -> Hermitian
"""
if expr.is_number:
return True

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

cos, exp = [sin]*2

"""
Handler for Q.complex
Test that an expression belongs to the field of complex numbers
"""

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

Number, sin, cos, exp, re, im, NumberSymbol, Abs, ImaginaryUnit = \
[staticmethod(CommonHandler.AlwaysTrue)]*9 # they are all complex functions or expressions

Infinity, NegativeInfinity = [staticmethod(CommonHandler.AlwaysFalse)]*2

@staticmethod
def MatrixElement(expr, assumptions):

Determinant = Trace = MatrixElement

"""
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].evalf()

@staticmethod
"""
Imaginary + Imaginary -> Imaginary
Imaginary + Complex   -> ?
Imaginary + Real      -> !Imaginary
"""
if expr.is_number:
reals = 0
for arg in expr.args:
pass
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:
result = False
reals = 0
for arg in expr.args:
result = result ^ True
break
else:
if reals == len(expr.args):
return False
return result

@staticmethod
[docs]    def Pow(expr, assumptions):
"""
Imaginary**integer -> Imaginary if integer % 2 == 1
Imaginary**integer -> real if integer % 2 == 0
Imaginary**Imaginary    -> ?
Imaginary**Real         -> ?
"""
if expr.is_number:
return True
return False
if expr.exp.is_Rational and \
return False
return False
return True

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

NumberSymbol = Number

ImaginaryUnit = staticmethod(CommonHandler.AlwaysTrue)

"""
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
"""
Antihermitian + Antihermitian  -> Antihermitian
Antihermitian + !Antihermitian -> !Antihermitian
"""
if expr.is_number:
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:
nccount = 0
result = False
for arg in expr.args:
result = result ^ True
break
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 False
return False
return True

"""Handler for Q.algebraic key. """

@staticmethod
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):
Q.algebraic(expr.base), assumptions)

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

Float, GoldenRatio, ImaginaryUnit, AlgebraicNumber = \
[staticmethod(CommonHandler.AlwaysTrue)]*4

Infinity, NegativeInfinity, ComplexInfinity, Pi, Exp1 = \
[staticmethod(CommonHandler.AlwaysFalse)]*5

@staticmethod
def exp(expr, assumptions):
x = expr.args[0]

@staticmethod
def cot(expr, assumptions):
x = expr.args[0]