ntheory.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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, int_valued)
  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. prime_base = ask(Q.prime(expr.base), assumptions)
  57. if prime_base is False:
  58. return False
  59. is_exp_one = ask(Q.eq(expr.exp, 1), assumptions)
  60. if is_exp_one is False:
  61. return False
  62. if prime_base is True and is_exp_one is True:
  63. return True
  64. @PrimePredicate.register(Integer)
  65. def _(expr, assumptions):
  66. return isprime(expr)
  67. @PrimePredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit)
  68. def _(expr, assumptions):
  69. return False
  70. @PrimePredicate.register(Float)
  71. def _(expr, assumptions):
  72. return _PrimePredicate_number(expr, assumptions)
  73. @PrimePredicate.register(NumberSymbol)
  74. def _(expr, assumptions):
  75. return _PrimePredicate_number(expr, assumptions)
  76. @PrimePredicate.register(NaN)
  77. def _(expr, assumptions):
  78. return None
  79. # CompositePredicate
  80. @CompositePredicate.register(Expr)
  81. def _(expr, assumptions):
  82. ret = expr.is_composite
  83. if ret is None:
  84. raise MDNotImplementedError
  85. return ret
  86. @CompositePredicate.register(Basic)
  87. def _(expr, assumptions):
  88. _positive = ask(Q.positive(expr), assumptions)
  89. if _positive:
  90. _integer = ask(Q.integer(expr), assumptions)
  91. if _integer:
  92. _prime = ask(Q.prime(expr), assumptions)
  93. if _prime is None:
  94. return
  95. # Positive integer which is not prime is not
  96. # necessarily composite
  97. _is_one = ask(Q.eq(expr, 1), assumptions)
  98. if _is_one:
  99. return False
  100. if _is_one is None:
  101. return None
  102. return not _prime
  103. else:
  104. return _integer
  105. else:
  106. return _positive
  107. # EvenPredicate
  108. def _EvenPredicate_number(expr, assumptions):
  109. # helper method
  110. if isinstance(expr, (float, Float)):
  111. if int_valued(expr):
  112. return None
  113. return False
  114. try:
  115. i = int(expr.round())
  116. except TypeError:
  117. return False
  118. if not (expr - i).equals(0):
  119. return False
  120. return i % 2 == 0
  121. @EvenPredicate.register(Expr)
  122. def _(expr, assumptions):
  123. ret = expr.is_even
  124. if ret is None:
  125. raise MDNotImplementedError
  126. return ret
  127. @EvenPredicate.register(Basic)
  128. def _(expr, assumptions):
  129. if expr.is_number:
  130. return _EvenPredicate_number(expr, assumptions)
  131. @EvenPredicate.register(Mul)
  132. def _(expr, assumptions):
  133. """
  134. Even * Integer -> Even
  135. Even * Odd -> Even
  136. Integer * Odd -> ?
  137. Odd * Odd -> Odd
  138. Even * Even -> Even
  139. Integer * Integer -> Even if Integer + Integer = Odd
  140. otherwise -> ?
  141. """
  142. if expr.is_number:
  143. return _EvenPredicate_number(expr, assumptions)
  144. even, odd, irrational, acc = False, 0, False, 1
  145. for arg in expr.args:
  146. # check for all integers and at least one even
  147. if ask(Q.integer(arg), assumptions):
  148. if ask(Q.even(arg), assumptions):
  149. even = True
  150. elif ask(Q.odd(arg), assumptions):
  151. odd += 1
  152. elif not even and acc != 1:
  153. if ask(Q.odd(acc + arg), assumptions):
  154. even = True
  155. elif ask(Q.irrational(arg), assumptions):
  156. # one irrational makes the result False
  157. # two makes it undefined
  158. if irrational:
  159. break
  160. irrational = True
  161. else:
  162. break
  163. acc = arg
  164. else:
  165. if irrational:
  166. return False
  167. if even:
  168. return True
  169. if odd == len(expr.args):
  170. return False
  171. @EvenPredicate.register(Add)
  172. def _(expr, assumptions):
  173. """
  174. Even + Odd -> Odd
  175. Even + Even -> Even
  176. Odd + Odd -> Even
  177. """
  178. if expr.is_number:
  179. return _EvenPredicate_number(expr, assumptions)
  180. _result = True
  181. for arg in expr.args:
  182. if ask(Q.even(arg), assumptions):
  183. pass
  184. elif ask(Q.odd(arg), assumptions):
  185. _result = not _result
  186. else:
  187. break
  188. else:
  189. return _result
  190. @EvenPredicate.register(Pow)
  191. def _(expr, assumptions):
  192. if expr.is_number:
  193. return _EvenPredicate_number(expr, assumptions)
  194. if ask(Q.integer(expr.exp), assumptions):
  195. if ask(Q.positive(expr.exp), assumptions):
  196. return ask(Q.even(expr.base), assumptions)
  197. elif ask(~Q.negative(expr.exp) & Q.odd(expr.base), assumptions):
  198. return False
  199. elif expr.base is S.NegativeOne:
  200. return False
  201. @EvenPredicate.register(Integer)
  202. def _(expr, assumptions):
  203. return not bool(expr.p & 1)
  204. @EvenPredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit)
  205. def _(expr, assumptions):
  206. return False
  207. @EvenPredicate.register(NumberSymbol)
  208. def _(expr, assumptions):
  209. return _EvenPredicate_number(expr, assumptions)
  210. @EvenPredicate.register(Abs)
  211. def _(expr, assumptions):
  212. if ask(Q.real(expr.args[0]), assumptions):
  213. return ask(Q.even(expr.args[0]), assumptions)
  214. @EvenPredicate.register(re)
  215. def _(expr, assumptions):
  216. if ask(Q.real(expr.args[0]), assumptions):
  217. return ask(Q.even(expr.args[0]), assumptions)
  218. @EvenPredicate.register(im)
  219. def _(expr, assumptions):
  220. if ask(Q.real(expr.args[0]), assumptions):
  221. return True
  222. @EvenPredicate.register(NaN)
  223. def _(expr, assumptions):
  224. return None
  225. # OddPredicate
  226. @OddPredicate.register(Expr)
  227. def _(expr, assumptions):
  228. ret = expr.is_odd
  229. if ret is None:
  230. raise MDNotImplementedError
  231. return ret
  232. @OddPredicate.register(Basic)
  233. def _(expr, assumptions):
  234. _integer = ask(Q.integer(expr), assumptions)
  235. if _integer:
  236. _even = ask(Q.even(expr), assumptions)
  237. if _even is None:
  238. return None
  239. return not _even
  240. return _integer