test_rel_queries.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. from sympy.assumptions.lra_satask import lra_satask
  2. from sympy.logic.algorithms.lra_theory import UnhandledInput
  3. from sympy.assumptions.ask import Q, ask
  4. from sympy.core import symbols, Symbol
  5. from sympy.matrices.expressions.matexpr import MatrixSymbol
  6. from sympy.core.numbers import I
  7. from sympy.testing.pytest import raises, XFAIL
  8. x, y, z = symbols("x y z", real=True)
  9. def test_lra_satask():
  10. im = Symbol('im', imaginary=True)
  11. # test preprocessing of unequalities is working correctly
  12. assert lra_satask(Q.eq(x, 1), ~Q.ne(x, 0)) is False
  13. assert lra_satask(Q.eq(x, 0), ~Q.ne(x, 0)) is True
  14. assert lra_satask(~Q.ne(x, 0), Q.eq(x, 0)) is True
  15. assert lra_satask(~Q.eq(x, 0), Q.eq(x, 0)) is False
  16. assert lra_satask(Q.ne(x, 0), Q.eq(x, 0)) is False
  17. # basic tests
  18. assert lra_satask(Q.ne(x, x)) is False
  19. assert lra_satask(Q.eq(x, x)) is True
  20. assert lra_satask(Q.gt(x, 0), Q.gt(x, 1)) is True
  21. # check that True/False are handled
  22. assert lra_satask(Q.gt(x, 0), True) is None
  23. assert raises(ValueError, lambda: lra_satask(Q.gt(x, 0), False))
  24. # check imaginary numbers are correctly handled
  25. # (im * I).is_real returns True so this is an edge case
  26. raises(UnhandledInput, lambda: lra_satask(Q.gt(im * I, 0), Q.gt(im * I, 0)))
  27. # check matrix inputs
  28. X = MatrixSymbol("X", 2, 2)
  29. raises(UnhandledInput, lambda: lra_satask(Q.lt(X, 2) & Q.gt(X, 3)))
  30. def test_old_assumptions():
  31. # test unhandled old assumptions
  32. w = symbols("w")
  33. raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
  34. w = symbols("w", rational=False, real=True)
  35. raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
  36. w = symbols("w", odd=True, real=True)
  37. raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
  38. w = symbols("w", even=True, real=True)
  39. raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
  40. w = symbols("w", prime=True, real=True)
  41. raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
  42. w = symbols("w", composite=True, real=True)
  43. raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
  44. w = symbols("w", integer=True, real=True)
  45. raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
  46. w = symbols("w", integer=False, real=True)
  47. raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
  48. # test handled
  49. w = symbols("w", positive=True, real=True)
  50. assert lra_satask(Q.le(w, 0)) is False
  51. assert lra_satask(Q.gt(w, 0)) is True
  52. w = symbols("w", negative=True, real=True)
  53. assert lra_satask(Q.lt(w, 0)) is True
  54. assert lra_satask(Q.ge(w, 0)) is False
  55. w = symbols("w", zero=True, real=True)
  56. assert lra_satask(Q.eq(w, 0)) is True
  57. assert lra_satask(Q.ne(w, 0)) is False
  58. w = symbols("w", nonzero=True, real=True)
  59. assert lra_satask(Q.ne(w, 0)) is True
  60. assert lra_satask(Q.eq(w, 1)) is None
  61. w = symbols("w", nonpositive=True, real=True)
  62. assert lra_satask(Q.le(w, 0)) is True
  63. assert lra_satask(Q.gt(w, 0)) is False
  64. w = symbols("w", nonnegative=True, real=True)
  65. assert lra_satask(Q.ge(w, 0)) is True
  66. assert lra_satask(Q.lt(w, 0)) is False
  67. def test_rel_queries():
  68. assert ask(Q.lt(x, 2) & Q.gt(x, 3)) is False
  69. assert ask(Q.positive(x - z), (x > y) & (y > z)) is True
  70. assert ask(x + y > 2, (x < 0) & (y <0)) is False
  71. assert ask(x > z, (x > y) & (y > z)) is True
  72. def test_unhandled_queries():
  73. X = MatrixSymbol("X", 2, 2)
  74. assert ask(Q.lt(X, 2) & Q.gt(X, 3)) is None
  75. def test_all_pred():
  76. # test usable pred
  77. assert lra_satask(Q.extended_positive(x), (x > 2)) is True
  78. assert lra_satask(Q.positive_infinite(x)) is False
  79. assert lra_satask(Q.negative_infinite(x)) is False
  80. # test disallowed pred
  81. raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.prime(x)))
  82. raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.composite(x)))
  83. raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.odd(x)))
  84. raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.even(x)))
  85. raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.integer(x)))
  86. def test_number_line_properties():
  87. # From:
  88. # https://en.wikipedia.org/wiki/Inequality_(mathematics)#Properties_on_the_number_line
  89. a, b, c = symbols("a b c", real=True)
  90. # Transitivity
  91. # If a <= b and b <= c, then a <= c.
  92. assert ask(a <= c, (a <= b) & (b <= c)) is True
  93. # If a <= b and b < c, then a < c.
  94. assert ask(a < c, (a <= b) & (b < c)) is True
  95. # If a < b and b <= c, then a < c.
  96. assert ask(a < c, (a < b) & (b <= c)) is True
  97. # Addition and subtraction
  98. # If a <= b, then a + c <= b + c and a - c <= b - c.
  99. assert ask(a + c <= b + c, a <= b) is True
  100. assert ask(a - c <= b - c, a <= b) is True
  101. @XFAIL
  102. def test_failing_number_line_properties():
  103. # From:
  104. # https://en.wikipedia.org/wiki/Inequality_(mathematics)#Properties_on_the_number_line
  105. a, b, c = symbols("a b c", real=True)
  106. # Multiplication and division
  107. # If a <= b and c > 0, then ac <= bc and a/c <= b/c. (True for non-zero c)
  108. assert ask(a*c <= b*c, (a <= b) & (c > 0) & ~ Q.zero(c)) is True
  109. assert ask(a/c <= b/c, (a <= b) & (c > 0) & ~ Q.zero(c)) is True
  110. # If a <= b and c < 0, then ac >= bc and a/c >= b/c. (True for non-zero c)
  111. assert ask(a*c >= b*c, (a <= b) & (c < 0) & ~ Q.zero(c)) is True
  112. assert ask(a/c >= b/c, (a <= b) & (c < 0) & ~ Q.zero(c)) is True
  113. # Additive inverse
  114. # If a <= b, then -a >= -b.
  115. assert ask(-a >= -b, a <= b) is True
  116. # Multiplicative inverse
  117. # For a, b that are both negative or both positive:
  118. # If a <= b, then 1/a >= 1/b .
  119. assert ask(1/a >= 1/b, (a <= b) & Q.positive(x) & Q.positive(b)) is True
  120. assert ask(1/a >= 1/b, (a <= b) & Q.negative(x) & Q.negative(b)) is True
  121. def test_equality():
  122. # test symmetry and reflexivity
  123. assert ask(Q.eq(x, x)) is True
  124. assert ask(Q.eq(y, x), Q.eq(x, y)) is True
  125. assert ask(Q.eq(y, x), ~Q.eq(z, z) | Q.eq(x, y)) is True
  126. # test transitivity
  127. assert ask(Q.eq(x,z), Q.eq(x,y) & Q.eq(y,z)) is True
  128. @XFAIL
  129. def test_equality_failing():
  130. # Note that implementing the substitution property of equality
  131. # most likely requires a redesign of the new assumptions.
  132. # See issue #25485 for why this is the case and general ideas
  133. # about how things could be redesigned.
  134. # test substitution property
  135. assert ask(Q.prime(x), Q.eq(x, y) & Q.prime(y)) is True
  136. assert ask(Q.real(x), Q.eq(x, y) & Q.real(y)) is True
  137. assert ask(Q.imaginary(x), Q.eq(x, y) & Q.imaginary(y)) is True