test_satask.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. from sympy.assumptions.ask import Q
  2. from sympy.assumptions.assume import assuming
  3. from sympy.core.numbers import (I, pi)
  4. from sympy.core.relational import (Eq, Gt)
  5. from sympy.core.singleton import S
  6. from sympy.core.symbol import symbols
  7. from sympy.functions.elementary.complexes import Abs
  8. from sympy.logic.boolalg import Implies
  9. from sympy.matrices.expressions.matexpr import MatrixSymbol
  10. from sympy.assumptions.cnf import CNF, Literal
  11. from sympy.assumptions.satask import (satask, extract_predargs,
  12. get_relevant_clsfacts)
  13. from sympy.testing.pytest import raises, XFAIL
  14. x, y, z = symbols('x y z')
  15. def test_satask():
  16. # No relevant facts
  17. assert satask(Q.real(x), Q.real(x)) is True
  18. assert satask(Q.real(x), ~Q.real(x)) is False
  19. assert satask(Q.real(x)) is None
  20. assert satask(Q.real(x), Q.positive(x)) is True
  21. assert satask(Q.positive(x), Q.real(x)) is None
  22. assert satask(Q.real(x), ~Q.positive(x)) is None
  23. assert satask(Q.positive(x), ~Q.real(x)) is False
  24. raises(ValueError, lambda: satask(Q.real(x), Q.real(x) & ~Q.real(x)))
  25. with assuming(Q.positive(x)):
  26. assert satask(Q.real(x)) is True
  27. assert satask(~Q.positive(x)) is False
  28. raises(ValueError, lambda: satask(Q.real(x), ~Q.positive(x)))
  29. assert satask(Q.zero(x), Q.nonzero(x)) is False
  30. assert satask(Q.positive(x), Q.zero(x)) is False
  31. assert satask(Q.real(x), Q.zero(x)) is True
  32. assert satask(Q.zero(x), Q.zero(x*y)) is None
  33. assert satask(Q.zero(x*y), Q.zero(x))
  34. def test_zero():
  35. """
  36. Everything in this test doesn't work with the ask handlers, and most
  37. things would be very difficult or impossible to make work under that
  38. model.
  39. """
  40. assert satask(Q.zero(x) | Q.zero(y), Q.zero(x*y)) is True
  41. assert satask(Q.zero(x*y), Q.zero(x) | Q.zero(y)) is True
  42. assert satask(Implies(Q.zero(x), Q.zero(x*y))) is True
  43. # This one in particular requires computing the fixed-point of the
  44. # relevant facts, because going from Q.nonzero(x*y) -> ~Q.zero(x*y) and
  45. # Q.zero(x*y) -> Equivalent(Q.zero(x*y), Q.zero(x) | Q.zero(y)) takes two
  46. # steps.
  47. assert satask(Q.zero(x) | Q.zero(y), Q.nonzero(x*y)) is False
  48. assert satask(Q.zero(x), Q.zero(x**2)) is True
  49. def test_zero_positive():
  50. assert satask(Q.zero(x + y), Q.positive(x) & Q.positive(y)) is False
  51. assert satask(Q.positive(x) & Q.positive(y), Q.zero(x + y)) is False
  52. assert satask(Q.nonzero(x + y), Q.positive(x) & Q.positive(y)) is True
  53. assert satask(Q.positive(x) & Q.positive(y), Q.nonzero(x + y)) is None
  54. # This one requires several levels of forward chaining
  55. assert satask(Q.zero(x*(x + y)), Q.positive(x) & Q.positive(y)) is False
  56. assert satask(Q.positive(pi*x*y + 1), Q.positive(x) & Q.positive(y)) is True
  57. assert satask(Q.positive(pi*x*y - 5), Q.positive(x) & Q.positive(y)) is None
  58. def test_zero_pow():
  59. assert satask(Q.zero(x**y), Q.zero(x) & Q.positive(y)) is True
  60. assert satask(Q.zero(x**y), Q.nonzero(x) & Q.zero(y)) is False
  61. assert satask(Q.zero(x), Q.zero(x**y)) is True
  62. assert satask(Q.zero(x**y), Q.zero(x)) is None
  63. @XFAIL
  64. # Requires correct Q.square calculation first
  65. def test_invertible():
  66. A = MatrixSymbol('A', 5, 5)
  67. B = MatrixSymbol('B', 5, 5)
  68. assert satask(Q.invertible(A*B), Q.invertible(A) & Q.invertible(B)) is True
  69. assert satask(Q.invertible(A), Q.invertible(A*B)) is True
  70. assert satask(Q.invertible(A) & Q.invertible(B), Q.invertible(A*B)) is True
  71. def test_prime():
  72. assert satask(Q.prime(5)) is True
  73. assert satask(Q.prime(6)) is False
  74. assert satask(Q.prime(-5)) is False
  75. assert satask(Q.prime(x*y), Q.integer(x) & Q.integer(y)) is None
  76. assert satask(Q.prime(x*y), Q.prime(x) & Q.prime(y)) is False
  77. def test_old_assump():
  78. assert satask(Q.positive(1)) is True
  79. assert satask(Q.positive(-1)) is False
  80. assert satask(Q.positive(0)) is False
  81. assert satask(Q.positive(I)) is False
  82. assert satask(Q.positive(pi)) is True
  83. assert satask(Q.negative(1)) is False
  84. assert satask(Q.negative(-1)) is True
  85. assert satask(Q.negative(0)) is False
  86. assert satask(Q.negative(I)) is False
  87. assert satask(Q.negative(pi)) is False
  88. assert satask(Q.zero(1)) is False
  89. assert satask(Q.zero(-1)) is False
  90. assert satask(Q.zero(0)) is True
  91. assert satask(Q.zero(I)) is False
  92. assert satask(Q.zero(pi)) is False
  93. assert satask(Q.nonzero(1)) is True
  94. assert satask(Q.nonzero(-1)) is True
  95. assert satask(Q.nonzero(0)) is False
  96. assert satask(Q.nonzero(I)) is False
  97. assert satask(Q.nonzero(pi)) is True
  98. assert satask(Q.nonpositive(1)) is False
  99. assert satask(Q.nonpositive(-1)) is True
  100. assert satask(Q.nonpositive(0)) is True
  101. assert satask(Q.nonpositive(I)) is False
  102. assert satask(Q.nonpositive(pi)) is False
  103. assert satask(Q.nonnegative(1)) is True
  104. assert satask(Q.nonnegative(-1)) is False
  105. assert satask(Q.nonnegative(0)) is True
  106. assert satask(Q.nonnegative(I)) is False
  107. assert satask(Q.nonnegative(pi)) is True
  108. def test_rational_irrational():
  109. assert satask(Q.irrational(2)) is False
  110. assert satask(Q.rational(2)) is True
  111. assert satask(Q.irrational(pi)) is True
  112. assert satask(Q.rational(pi)) is False
  113. assert satask(Q.irrational(I)) is False
  114. assert satask(Q.rational(I)) is False
  115. assert satask(Q.irrational(x*y*z), Q.irrational(x) & Q.irrational(y) &
  116. Q.rational(z)) is None
  117. assert satask(Q.irrational(x*y*z), Q.irrational(x) & Q.rational(y) &
  118. Q.rational(z)) is True
  119. assert satask(Q.irrational(pi*x*y), Q.rational(x) & Q.rational(y)) is True
  120. assert satask(Q.irrational(x + y + z), Q.irrational(x) & Q.irrational(y) &
  121. Q.rational(z)) is None
  122. assert satask(Q.irrational(x + y + z), Q.irrational(x) & Q.rational(y) &
  123. Q.rational(z)) is True
  124. assert satask(Q.irrational(pi + x + y), Q.rational(x) & Q.rational(y)) is True
  125. assert satask(Q.irrational(x*y*z), Q.rational(x) & Q.rational(y) &
  126. Q.rational(z)) is False
  127. assert satask(Q.rational(x*y*z), Q.rational(x) & Q.rational(y) &
  128. Q.rational(z)) is True
  129. assert satask(Q.irrational(x + y + z), Q.rational(x) & Q.rational(y) &
  130. Q.rational(z)) is False
  131. assert satask(Q.rational(x + y + z), Q.rational(x) & Q.rational(y) &
  132. Q.rational(z)) is True
  133. def test_even_satask():
  134. assert satask(Q.even(2)) is True
  135. assert satask(Q.even(3)) is False
  136. assert satask(Q.even(x*y), Q.even(x) & Q.odd(y)) is True
  137. assert satask(Q.even(x*y), Q.even(x) & Q.integer(y)) is True
  138. assert satask(Q.even(x*y), Q.even(x) & Q.even(y)) is True
  139. assert satask(Q.even(x*y), Q.odd(x) & Q.odd(y)) is False
  140. assert satask(Q.even(x*y), Q.even(x)) is None
  141. assert satask(Q.even(x*y), Q.odd(x) & Q.integer(y)) is None
  142. assert satask(Q.even(x*y), Q.odd(x) & Q.odd(y)) is False
  143. assert satask(Q.even(abs(x)), Q.even(x)) is True
  144. assert satask(Q.even(abs(x)), Q.odd(x)) is False
  145. assert satask(Q.even(x), Q.even(abs(x))) is None # x could be complex
  146. def test_odd_satask():
  147. assert satask(Q.odd(2)) is False
  148. assert satask(Q.odd(3)) is True
  149. assert satask(Q.odd(x*y), Q.even(x) & Q.odd(y)) is False
  150. assert satask(Q.odd(x*y), Q.even(x) & Q.integer(y)) is False
  151. assert satask(Q.odd(x*y), Q.even(x) & Q.even(y)) is False
  152. assert satask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) is True
  153. assert satask(Q.odd(x*y), Q.even(x)) is None
  154. assert satask(Q.odd(x*y), Q.odd(x) & Q.integer(y)) is None
  155. assert satask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) is True
  156. assert satask(Q.odd(abs(x)), Q.even(x)) is False
  157. assert satask(Q.odd(abs(x)), Q.odd(x)) is True
  158. assert satask(Q.odd(x), Q.odd(abs(x))) is None # x could be complex
  159. def test_integer():
  160. assert satask(Q.integer(1)) is True
  161. assert satask(Q.integer(S.Half)) is False
  162. assert satask(Q.integer(x + y), Q.integer(x) & Q.integer(y)) is True
  163. assert satask(Q.integer(x + y), Q.integer(x)) is None
  164. assert satask(Q.integer(x + y), Q.integer(x) & ~Q.integer(y)) is False
  165. assert satask(Q.integer(x + y + z), Q.integer(x) & Q.integer(y) &
  166. ~Q.integer(z)) is False
  167. assert satask(Q.integer(x + y + z), Q.integer(x) & ~Q.integer(y) &
  168. ~Q.integer(z)) is None
  169. assert satask(Q.integer(x + y + z), Q.integer(x) & ~Q.integer(y)) is None
  170. assert satask(Q.integer(x + y), Q.integer(x) & Q.irrational(y)) is False
  171. assert satask(Q.integer(x*y), Q.integer(x) & Q.integer(y)) is True
  172. assert satask(Q.integer(x*y), Q.integer(x)) is None
  173. assert satask(Q.integer(x*y), Q.integer(x) & ~Q.integer(y)) is None
  174. assert satask(Q.integer(x*y), Q.integer(x) & ~Q.rational(y)) is False
  175. assert satask(Q.integer(x*y*z), Q.integer(x) & Q.integer(y) &
  176. ~Q.rational(z)) is False
  177. assert satask(Q.integer(x*y*z), Q.integer(x) & ~Q.rational(y) &
  178. ~Q.rational(z)) is None
  179. assert satask(Q.integer(x*y*z), Q.integer(x) & ~Q.rational(y)) is None
  180. assert satask(Q.integer(x*y), Q.integer(x) & Q.irrational(y)) is False
  181. def test_abs():
  182. assert satask(Q.nonnegative(abs(x))) is True
  183. assert satask(Q.positive(abs(x)), ~Q.zero(x)) is True
  184. assert satask(Q.zero(x), ~Q.zero(abs(x))) is False
  185. assert satask(Q.zero(x), Q.zero(abs(x))) is True
  186. assert satask(Q.nonzero(x), ~Q.zero(abs(x))) is None # x could be complex
  187. assert satask(Q.zero(abs(x)), Q.zero(x)) is True
  188. def test_imaginary():
  189. assert satask(Q.imaginary(2*I)) is True
  190. assert satask(Q.imaginary(x*y), Q.imaginary(x)) is None
  191. assert satask(Q.imaginary(x*y), Q.imaginary(x) & Q.real(y)) is True
  192. assert satask(Q.imaginary(x), Q.real(x)) is False
  193. assert satask(Q.imaginary(1)) is False
  194. assert satask(Q.imaginary(x*y), Q.real(x) & Q.real(y)) is False
  195. assert satask(Q.imaginary(x + y), Q.real(x) & Q.real(y)) is False
  196. def test_real():
  197. assert satask(Q.real(x*y), Q.real(x) & Q.real(y)) is True
  198. assert satask(Q.real(x + y), Q.real(x) & Q.real(y)) is True
  199. assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y) & Q.real(z)) is True
  200. assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y)) is None
  201. assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y) & Q.imaginary(z)) is False
  202. assert satask(Q.real(x + y + z), Q.real(x) & Q.real(y) & Q.real(z)) is True
  203. assert satask(Q.real(x + y + z), Q.real(x) & Q.real(y)) is None
  204. def test_pos_neg():
  205. assert satask(~Q.positive(x), Q.negative(x)) is True
  206. assert satask(~Q.negative(x), Q.positive(x)) is True
  207. assert satask(Q.positive(x + y), Q.positive(x) & Q.positive(y)) is True
  208. assert satask(Q.negative(x + y), Q.negative(x) & Q.negative(y)) is True
  209. assert satask(Q.positive(x + y), Q.negative(x) & Q.negative(y)) is False
  210. assert satask(Q.negative(x + y), Q.positive(x) & Q.positive(y)) is False
  211. def test_pow_pos_neg():
  212. assert satask(Q.nonnegative(x**2), Q.positive(x)) is True
  213. assert satask(Q.nonpositive(x**2), Q.positive(x)) is False
  214. assert satask(Q.positive(x**2), Q.positive(x)) is True
  215. assert satask(Q.negative(x**2), Q.positive(x)) is False
  216. assert satask(Q.real(x**2), Q.positive(x)) is True
  217. assert satask(Q.nonnegative(x**2), Q.negative(x)) is True
  218. assert satask(Q.nonpositive(x**2), Q.negative(x)) is False
  219. assert satask(Q.positive(x**2), Q.negative(x)) is True
  220. assert satask(Q.negative(x**2), Q.negative(x)) is False
  221. assert satask(Q.real(x**2), Q.negative(x)) is True
  222. assert satask(Q.nonnegative(x**2), Q.nonnegative(x)) is True
  223. assert satask(Q.nonpositive(x**2), Q.nonnegative(x)) is None
  224. assert satask(Q.positive(x**2), Q.nonnegative(x)) is None
  225. assert satask(Q.negative(x**2), Q.nonnegative(x)) is False
  226. assert satask(Q.real(x**2), Q.nonnegative(x)) is True
  227. assert satask(Q.nonnegative(x**2), Q.nonpositive(x)) is True
  228. assert satask(Q.nonpositive(x**2), Q.nonpositive(x)) is None
  229. assert satask(Q.positive(x**2), Q.nonpositive(x)) is None
  230. assert satask(Q.negative(x**2), Q.nonpositive(x)) is False
  231. assert satask(Q.real(x**2), Q.nonpositive(x)) is True
  232. assert satask(Q.nonnegative(x**3), Q.positive(x)) is True
  233. assert satask(Q.nonpositive(x**3), Q.positive(x)) is False
  234. assert satask(Q.positive(x**3), Q.positive(x)) is True
  235. assert satask(Q.negative(x**3), Q.positive(x)) is False
  236. assert satask(Q.real(x**3), Q.positive(x)) is True
  237. assert satask(Q.nonnegative(x**3), Q.negative(x)) is False
  238. assert satask(Q.nonpositive(x**3), Q.negative(x)) is True
  239. assert satask(Q.positive(x**3), Q.negative(x)) is False
  240. assert satask(Q.negative(x**3), Q.negative(x)) is True
  241. assert satask(Q.real(x**3), Q.negative(x)) is True
  242. assert satask(Q.nonnegative(x**3), Q.nonnegative(x)) is True
  243. assert satask(Q.nonpositive(x**3), Q.nonnegative(x)) is None
  244. assert satask(Q.positive(x**3), Q.nonnegative(x)) is None
  245. assert satask(Q.negative(x**3), Q.nonnegative(x)) is False
  246. assert satask(Q.real(x**3), Q.nonnegative(x)) is True
  247. assert satask(Q.nonnegative(x**3), Q.nonpositive(x)) is None
  248. assert satask(Q.nonpositive(x**3), Q.nonpositive(x)) is True
  249. assert satask(Q.positive(x**3), Q.nonpositive(x)) is False
  250. assert satask(Q.negative(x**3), Q.nonpositive(x)) is None
  251. assert satask(Q.real(x**3), Q.nonpositive(x)) is True
  252. # If x is zero, x**negative is not real.
  253. assert satask(Q.nonnegative(x**-2), Q.nonpositive(x)) is None
  254. assert satask(Q.nonpositive(x**-2), Q.nonpositive(x)) is None
  255. assert satask(Q.positive(x**-2), Q.nonpositive(x)) is None
  256. assert satask(Q.negative(x**-2), Q.nonpositive(x)) is None
  257. assert satask(Q.real(x**-2), Q.nonpositive(x)) is None
  258. # We could deduce things for negative powers if x is nonzero, but it
  259. # isn't implemented yet.
  260. def test_prime_composite():
  261. assert satask(Q.prime(x), Q.composite(x)) is False
  262. assert satask(Q.composite(x), Q.prime(x)) is False
  263. assert satask(Q.composite(x), ~Q.prime(x)) is None
  264. assert satask(Q.prime(x), ~Q.composite(x)) is None
  265. # since 1 is neither prime nor composite the following should hold
  266. assert satask(Q.prime(x), Q.integer(x) & Q.positive(x) & ~Q.composite(x)) is None
  267. assert satask(Q.prime(2)) is True
  268. assert satask(Q.prime(4)) is False
  269. assert satask(Q.prime(1)) is False
  270. assert satask(Q.composite(1)) is False
  271. def test_extract_predargs():
  272. props = CNF.from_prop(Q.zero(Abs(x*y)) & Q.zero(x*y))
  273. assump = CNF.from_prop(Q.zero(x))
  274. context = CNF.from_prop(Q.zero(y))
  275. assert extract_predargs(props) == {Abs(x*y), x*y}
  276. assert extract_predargs(props, assump) == {Abs(x*y), x*y, x}
  277. assert extract_predargs(props, assump, context) == {Abs(x*y), x*y, x, y}
  278. props = CNF.from_prop(Eq(x, y))
  279. assump = CNF.from_prop(Gt(y, z))
  280. assert extract_predargs(props, assump) == {x, y, z}
  281. def test_get_relevant_clsfacts():
  282. exprs = {Abs(x*y)}
  283. exprs, facts = get_relevant_clsfacts(exprs)
  284. assert exprs == {x*y}
  285. assert facts.clauses == \
  286. {frozenset({Literal(Q.odd(Abs(x*y)), False), Literal(Q.odd(x*y), True)}),
  287. frozenset({Literal(Q.zero(Abs(x*y)), False), Literal(Q.zero(x*y), True)}),
  288. frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.even(x*y), True)}),
  289. frozenset({Literal(Q.zero(Abs(x*y)), True), Literal(Q.zero(x*y), False)}),
  290. frozenset({Literal(Q.even(Abs(x*y)), False),
  291. Literal(Q.odd(Abs(x*y)), False),
  292. Literal(Q.odd(x*y), True)}),
  293. frozenset({Literal(Q.even(Abs(x*y)), False),
  294. Literal(Q.even(x*y), True),
  295. Literal(Q.odd(Abs(x*y)), False)}),
  296. frozenset({Literal(Q.positive(Abs(x*y)), False),
  297. Literal(Q.zero(Abs(x*y)), False)})}