Kano001's picture
Upload 3077 files
6a86ad5 verified
raw
history blame
7.27 kB
"""
Handlers for keys related to number theory: prime, even, odd, etc.
"""
from sympy.assumptions import Q, ask
from sympy.core import Add, Basic, Expr, Float, Mul, Pow, S
from sympy.core.numbers import (ImaginaryUnit, Infinity, Integer, NaN,
NegativeInfinity, NumberSymbol, Rational, int_valued)
from sympy.functions import Abs, im, re
from sympy.ntheory import isprime
from sympy.multipledispatch import MDNotImplementedError
from ..predicates.ntheory import (PrimePredicate, CompositePredicate,
EvenPredicate, OddPredicate)
# PrimePredicate
def _PrimePredicate_number(expr, assumptions):
# helper method
exact = not expr.atoms(Float)
try:
i = int(expr.round())
if (expr - i).equals(0) is False:
raise TypeError
except TypeError:
return False
if exact:
return isprime(i)
# when not exact, we won't give a True or False
# since the number represents an approximate value
@PrimePredicate.register(Expr)
def _(expr, assumptions):
ret = expr.is_prime
if ret is None:
raise MDNotImplementedError
return ret
@PrimePredicate.register(Basic)
def _(expr, assumptions):
if expr.is_number:
return _PrimePredicate_number(expr, assumptions)
@PrimePredicate.register(Mul)
def _(expr, assumptions):
if expr.is_number:
return _PrimePredicate_number(expr, assumptions)
for arg in expr.args:
if not ask(Q.integer(arg), assumptions):
return None
for arg in expr.args:
if arg.is_number and arg.is_composite:
return False
@PrimePredicate.register(Pow)
def _(expr, assumptions):
"""
Integer**Integer -> !Prime
"""
if expr.is_number:
return _PrimePredicate_number(expr, assumptions)
if ask(Q.integer(expr.exp), assumptions) and \
ask(Q.integer(expr.base), assumptions):
return False
@PrimePredicate.register(Integer)
def _(expr, assumptions):
return isprime(expr)
@PrimePredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit)
def _(expr, assumptions):
return False
@PrimePredicate.register(Float)
def _(expr, assumptions):
return _PrimePredicate_number(expr, assumptions)
@PrimePredicate.register(NumberSymbol)
def _(expr, assumptions):
return _PrimePredicate_number(expr, assumptions)
@PrimePredicate.register(NaN)
def _(expr, assumptions):
return None
# CompositePredicate
@CompositePredicate.register(Expr)
def _(expr, assumptions):
ret = expr.is_composite
if ret is None:
raise MDNotImplementedError
return ret
@CompositePredicate.register(Basic)
def _(expr, assumptions):
_positive = ask(Q.positive(expr), assumptions)
if _positive:
_integer = ask(Q.integer(expr), assumptions)
if _integer:
_prime = ask(Q.prime(expr), assumptions)
if _prime is None:
return
# Positive integer which is not prime is not
# necessarily composite
if expr.equals(1):
return False
return not _prime
else:
return _integer
else:
return _positive
# EvenPredicate
def _EvenPredicate_number(expr, assumptions):
# helper method
if isinstance(expr, (float, Float)):
if int_valued(expr):
return None
return False
try:
i = int(expr.round())
except TypeError:
return False
if not (expr - i).equals(0):
return False
return i % 2 == 0
@EvenPredicate.register(Expr)
def _(expr, assumptions):
ret = expr.is_even
if ret is None:
raise MDNotImplementedError
return ret
@EvenPredicate.register(Basic)
def _(expr, assumptions):
if expr.is_number:
return _EvenPredicate_number(expr, assumptions)
@EvenPredicate.register(Mul)
def _(expr, assumptions):
"""
Even * Integer -> Even
Even * Odd -> Even
Integer * Odd -> ?
Odd * Odd -> Odd
Even * Even -> Even
Integer * Integer -> Even if Integer + Integer = Odd
otherwise -> ?
"""
if expr.is_number:
return _EvenPredicate_number(expr, assumptions)
even, odd, irrational, acc = False, 0, False, 1
for arg in expr.args:
# check for all integers and at least one even
if ask(Q.integer(arg), assumptions):
if ask(Q.even(arg), assumptions):
even = True
elif ask(Q.odd(arg), assumptions):
odd += 1
elif not even and acc != 1:
if ask(Q.odd(acc + arg), assumptions):
even = True
elif ask(Q.irrational(arg), assumptions):
# one irrational makes the result False
# two makes it undefined
if irrational:
break
irrational = True
else:
break
acc = arg
else:
if irrational:
return False
if even:
return True
if odd == len(expr.args):
return False
@EvenPredicate.register(Add)
def _(expr, assumptions):
"""
Even + Odd -> Odd
Even + Even -> Even
Odd + Odd -> Even
"""
if expr.is_number:
return _EvenPredicate_number(expr, assumptions)
_result = True
for arg in expr.args:
if ask(Q.even(arg), assumptions):
pass
elif ask(Q.odd(arg), assumptions):
_result = not _result
else:
break
else:
return _result
@EvenPredicate.register(Pow)
def _(expr, assumptions):
if expr.is_number:
return _EvenPredicate_number(expr, assumptions)
if ask(Q.integer(expr.exp), assumptions):
if ask(Q.positive(expr.exp), assumptions):
return ask(Q.even(expr.base), assumptions)
elif ask(~Q.negative(expr.exp) & Q.odd(expr.base), assumptions):
return False
elif expr.base is S.NegativeOne:
return False
@EvenPredicate.register(Integer)
def _(expr, assumptions):
return not bool(expr.p & 1)
@EvenPredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit)
def _(expr, assumptions):
return False
@EvenPredicate.register(NumberSymbol)
def _(expr, assumptions):
return _EvenPredicate_number(expr, assumptions)
@EvenPredicate.register(Abs)
def _(expr, assumptions):
if ask(Q.real(expr.args[0]), assumptions):
return ask(Q.even(expr.args[0]), assumptions)
@EvenPredicate.register(re)
def _(expr, assumptions):
if ask(Q.real(expr.args[0]), assumptions):
return ask(Q.even(expr.args[0]), assumptions)
@EvenPredicate.register(im)
def _(expr, assumptions):
if ask(Q.real(expr.args[0]), assumptions):
return True
@EvenPredicate.register(NaN)
def _(expr, assumptions):
return None
# OddPredicate
@OddPredicate.register(Expr)
def _(expr, assumptions):
ret = expr.is_odd
if ret is None:
raise MDNotImplementedError
return ret
@OddPredicate.register(Basic)
def _(expr, assumptions):
_integer = ask(Q.integer(expr), assumptions)
if _integer:
_even = ask(Q.even(expr), assumptions)
if _even is None:
return None
return not _even
return _integer