ntheory.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. """
  2. Handlers for keys related to number theory: prime, even, odd, etc.
  3. """
  4. from sympy.assumptions import Q, ask
  5. from sympy.core import Add, Basic, Expr, Float, Mul, Pow, S
  6. from sympy.core.numbers import (ImaginaryUnit, Infinity, Integer, NaN,
  7. NegativeInfinity, NumberSymbol, Rational)
  8. from sympy.functions import Abs, im, re
  9. from sympy.ntheory import isprime
  10. from sympy.multipledispatch import MDNotImplementedError
  11. from ..predicates.ntheory import (PrimePredicate, CompositePredicate,
  12. EvenPredicate, OddPredicate)
  13. # PrimePredicate
  14. def _PrimePredicate_number(expr, assumptions):
  15. # helper method
  16. exact = not expr.atoms(Float)
  17. try:
  18. i = int(expr.round())
  19. if (expr - i).equals(0) is False:
  20. raise TypeError
  21. except TypeError:
  22. return False
  23. if exact:
  24. return isprime(i)
  25. # when not exact, we won't give a True or False
  26. # since the number represents an approximate value
  27. @PrimePredicate.register(Expr)
  28. def _(expr, assumptions):
  29. ret = expr.is_prime
  30. if ret is None:
  31. raise MDNotImplementedError
  32. return ret
  33. @PrimePredicate.register(Basic)
  34. def _(expr, assumptions):
  35. if expr.is_number:
  36. return _PrimePredicate_number(expr, assumptions)
  37. @PrimePredicate.register(Mul)
  38. def _(expr, assumptions):
  39. if expr.is_number:
  40. return _PrimePredicate_number(expr, assumptions)
  41. for arg in expr.args:
  42. if not ask(Q.integer(arg), assumptions):
  43. return None
  44. for arg in expr.args:
  45. if arg.is_number and arg.is_composite:
  46. return False
  47. @PrimePredicate.register(Pow)
  48. def _(expr, assumptions):
  49. """
  50. Integer**Integer -> !Prime
  51. """
  52. if expr.is_number:
  53. return _PrimePredicate_number(expr, assumptions)
  54. if ask(Q.integer(expr.exp), assumptions) and \
  55. ask(Q.integer(expr.base), assumptions):
  56. return False
  57. @PrimePredicate.register(Integer)
  58. def _(expr, assumptions):
  59. return isprime(expr)
  60. @PrimePredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit)
  61. def _(expr, assumptions):
  62. return False
  63. @PrimePredicate.register(Float)
  64. def _(expr, assumptions):
  65. return _PrimePredicate_number(expr, assumptions)
  66. @PrimePredicate.register(NumberSymbol)
  67. def _(expr, assumptions):
  68. return _PrimePredicate_number(expr, assumptions)
  69. @PrimePredicate.register(NaN)
  70. def _(expr, assumptions):
  71. return None
  72. # CompositePredicate
  73. @CompositePredicate.register(Expr)
  74. def _(expr, assumptions):
  75. ret = expr.is_composite
  76. if ret is None:
  77. raise MDNotImplementedError
  78. return ret
  79. @CompositePredicate.register(Basic)
  80. def _(expr, assumptions):
  81. _positive = ask(Q.positive(expr), assumptions)
  82. if _positive:
  83. _integer = ask(Q.integer(expr), assumptions)
  84. if _integer:
  85. _prime = ask(Q.prime(expr), assumptions)
  86. if _prime is None:
  87. return
  88. # Positive integer which is not prime is not
  89. # necessarily composite
  90. if expr.equals(1):
  91. return False
  92. return not _prime
  93. else:
  94. return _integer
  95. else:
  96. return _positive
  97. # EvenPredicate
  98. def _EvenPredicate_number(expr, assumptions):
  99. # helper method
  100. try:
  101. i = int(expr.round())
  102. if not (expr - i).equals(0):
  103. raise TypeError
  104. except TypeError:
  105. return False
  106. if isinstance(expr, (float, Float)):
  107. return False
  108. return i % 2 == 0
  109. @EvenPredicate.register(Expr)
  110. def _(expr, assumptions):
  111. ret = expr.is_even
  112. if ret is None:
  113. raise MDNotImplementedError
  114. return ret
  115. @EvenPredicate.register(Basic)
  116. def _(expr, assumptions):
  117. if expr.is_number:
  118. return _EvenPredicate_number(expr, assumptions)
  119. @EvenPredicate.register(Mul)
  120. def _(expr, assumptions):
  121. """
  122. Even * Integer -> Even
  123. Even * Odd -> Even
  124. Integer * Odd -> ?
  125. Odd * Odd -> Odd
  126. Even * Even -> Even
  127. Integer * Integer -> Even if Integer + Integer = Odd
  128. otherwise -> ?
  129. """
  130. if expr.is_number:
  131. return _EvenPredicate_number(expr, assumptions)
  132. even, odd, irrational, acc = False, 0, False, 1
  133. for arg in expr.args:
  134. # check for all integers and at least one even
  135. if ask(Q.integer(arg), assumptions):
  136. if ask(Q.even(arg), assumptions):
  137. even = True
  138. elif ask(Q.odd(arg), assumptions):
  139. odd += 1
  140. elif not even and acc != 1:
  141. if ask(Q.odd(acc + arg), assumptions):
  142. even = True
  143. elif ask(Q.irrational(arg), assumptions):
  144. # one irrational makes the result False
  145. # two makes it undefined
  146. if irrational:
  147. break
  148. irrational = True
  149. else:
  150. break
  151. acc = arg
  152. else:
  153. if irrational:
  154. return False
  155. if even:
  156. return True
  157. if odd == len(expr.args):
  158. return False
  159. @EvenPredicate.register(Add)
  160. def _(expr, assumptions):
  161. """
  162. Even + Odd -> Odd
  163. Even + Even -> Even
  164. Odd + Odd -> Even
  165. """
  166. if expr.is_number:
  167. return _EvenPredicate_number(expr, assumptions)
  168. _result = True
  169. for arg in expr.args:
  170. if ask(Q.even(arg), assumptions):
  171. pass
  172. elif ask(Q.odd(arg), assumptions):
  173. _result = not _result
  174. else:
  175. break
  176. else:
  177. return _result
  178. @EvenPredicate.register(Pow)
  179. def _(expr, assumptions):
  180. if expr.is_number:
  181. return _EvenPredicate_number(expr, assumptions)
  182. if ask(Q.integer(expr.exp), assumptions):
  183. if ask(Q.positive(expr.exp), assumptions):
  184. return ask(Q.even(expr.base), assumptions)
  185. elif ask(~Q.negative(expr.exp) & Q.odd(expr.base), assumptions):
  186. return False
  187. elif expr.base is S.NegativeOne:
  188. return False
  189. @EvenPredicate.register(Integer)
  190. def _(expr, assumptions):
  191. return not bool(expr.p & 1)
  192. @EvenPredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit)
  193. def _(expr, assumptions):
  194. return False
  195. @EvenPredicate.register(NumberSymbol)
  196. def _(expr, assumptions):
  197. return _EvenPredicate_number(expr, assumptions)
  198. @EvenPredicate.register(Abs)
  199. def _(expr, assumptions):
  200. if ask(Q.real(expr.args[0]), assumptions):
  201. return ask(Q.even(expr.args[0]), assumptions)
  202. @EvenPredicate.register(re)
  203. def _(expr, assumptions):
  204. if ask(Q.real(expr.args[0]), assumptions):
  205. return ask(Q.even(expr.args[0]), assumptions)
  206. @EvenPredicate.register(im)
  207. def _(expr, assumptions):
  208. if ask(Q.real(expr.args[0]), assumptions):
  209. return True
  210. @EvenPredicate.register(NaN)
  211. def _(expr, assumptions):
  212. return None
  213. # OddPredicate
  214. @OddPredicate.register(Expr)
  215. def _(expr, assumptions):
  216. ret = expr.is_odd
  217. if ret is None:
  218. raise MDNotImplementedError
  219. return ret
  220. @OddPredicate.register(Basic)
  221. def _(expr, assumptions):
  222. _integer = ask(Q.integer(expr), assumptions)
  223. if _integer:
  224. _even = ask(Q.even(expr), assumptions)
  225. if _even is None:
  226. return None
  227. return not _even
  228. return _integer