wrapper.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. """
  2. Functions and wrapper object to call assumption property and predicate
  3. query with same syntax.
  4. In SymPy, there are two assumption systems. Old assumption system is
  5. defined in sympy/core/assumptions, and it can be accessed by attribute
  6. such as ``x.is_even``. New assumption system is defined in
  7. sympy/assumptions, and it can be accessed by predicates such as
  8. ``Q.even(x)``.
  9. Old assumption is fast, while new assumptions can freely take local facts.
  10. In general, old assumption is used in evaluation method and new assumption
  11. is used in refinement method.
  12. In most cases, both evaluation and refinement follow the same process, and
  13. the only difference is which assumption system is used. This module provides
  14. ``is_[...]()`` functions and ``AssumptionsWrapper()`` class which allows
  15. using two systems with same syntax so that parallel code implementation can be
  16. avoided.
  17. Examples
  18. ========
  19. For multiple use, use ``AssumptionsWrapper()``.
  20. >>> from sympy import Q, Symbol
  21. >>> from sympy.assumptions.wrapper import AssumptionsWrapper
  22. >>> x = Symbol('x')
  23. >>> _x = AssumptionsWrapper(x, Q.even(x))
  24. >>> _x.is_integer
  25. True
  26. >>> _x.is_odd
  27. False
  28. For single use, use ``is_[...]()`` functions.
  29. >>> from sympy.assumptions.wrapper import is_infinite
  30. >>> a = Symbol('a')
  31. >>> print(is_infinite(a))
  32. None
  33. >>> is_infinite(a, Q.finite(a))
  34. False
  35. """
  36. from sympy.assumptions import ask, Q
  37. from sympy.core.basic import Basic
  38. from sympy.core.sympify import _sympify
  39. def make_eval_method(fact):
  40. def getit(self):
  41. pred = getattr(Q, fact)
  42. ret = ask(pred(self.expr), self.assumptions)
  43. return ret
  44. return getit
  45. # we subclass Basic to use the fact deduction and caching
  46. class AssumptionsWrapper(Basic):
  47. """
  48. Wrapper over ``Basic`` instances to call predicate query by
  49. ``.is_[...]`` property
  50. Parameters
  51. ==========
  52. expr : Basic
  53. assumptions : Boolean, optional
  54. Examples
  55. ========
  56. >>> from sympy import Q, Symbol
  57. >>> from sympy.assumptions.wrapper import AssumptionsWrapper
  58. >>> x = Symbol('x', even=True)
  59. >>> AssumptionsWrapper(x).is_integer
  60. True
  61. >>> y = Symbol('y')
  62. >>> AssumptionsWrapper(y, Q.even(y)).is_integer
  63. True
  64. With ``AssumptionsWrapper``, both evaluation and refinement can be supported
  65. by single implementation.
  66. >>> from sympy import Function
  67. >>> class MyAbs(Function):
  68. ... @classmethod
  69. ... def eval(cls, x, assumptions=True):
  70. ... _x = AssumptionsWrapper(x, assumptions)
  71. ... if _x.is_nonnegative:
  72. ... return x
  73. ... if _x.is_negative:
  74. ... return -x
  75. ... def _eval_refine(self, assumptions):
  76. ... return MyAbs.eval(self.args[0], assumptions)
  77. >>> MyAbs(x)
  78. MyAbs(x)
  79. >>> MyAbs(x).refine(Q.positive(x))
  80. x
  81. >>> MyAbs(Symbol('y', negative=True))
  82. -y
  83. """
  84. def __new__(cls, expr, assumptions=None):
  85. if assumptions is None:
  86. return expr
  87. obj = super().__new__(cls, expr, _sympify(assumptions))
  88. obj.expr = expr
  89. obj.assumptions = assumptions
  90. return obj
  91. _eval_is_algebraic = make_eval_method("algebraic")
  92. _eval_is_antihermitian = make_eval_method("antihermitian")
  93. _eval_is_commutative = make_eval_method("commutative")
  94. _eval_is_complex = make_eval_method("complex")
  95. _eval_is_composite = make_eval_method("composite")
  96. _eval_is_even = make_eval_method("even")
  97. _eval_is_extended_negative = make_eval_method("extended_negative")
  98. _eval_is_extended_nonnegative = make_eval_method("extended_nonnegative")
  99. _eval_is_extended_nonpositive = make_eval_method("extended_nonpositive")
  100. _eval_is_extended_nonzero = make_eval_method("extended_nonzero")
  101. _eval_is_extended_positive = make_eval_method("extended_positive")
  102. _eval_is_extended_real = make_eval_method("extended_real")
  103. _eval_is_finite = make_eval_method("finite")
  104. _eval_is_hermitian = make_eval_method("hermitian")
  105. _eval_is_imaginary = make_eval_method("imaginary")
  106. _eval_is_infinite = make_eval_method("infinite")
  107. _eval_is_integer = make_eval_method("integer")
  108. _eval_is_irrational = make_eval_method("irrational")
  109. _eval_is_negative = make_eval_method("negative")
  110. _eval_is_noninteger = make_eval_method("noninteger")
  111. _eval_is_nonnegative = make_eval_method("nonnegative")
  112. _eval_is_nonpositive = make_eval_method("nonpositive")
  113. _eval_is_nonzero = make_eval_method("nonzero")
  114. _eval_is_odd = make_eval_method("odd")
  115. _eval_is_polar = make_eval_method("polar")
  116. _eval_is_positive = make_eval_method("positive")
  117. _eval_is_prime = make_eval_method("prime")
  118. _eval_is_rational = make_eval_method("rational")
  119. _eval_is_real = make_eval_method("real")
  120. _eval_is_transcendental = make_eval_method("transcendental")
  121. _eval_is_zero = make_eval_method("zero")
  122. # one shot functions which are faster than AssumptionsWrapper
  123. def is_infinite(obj, assumptions=None):
  124. if assumptions is None:
  125. return obj.is_infinite
  126. return ask(Q.infinite(obj), assumptions)
  127. def is_extended_real(obj, assumptions=None):
  128. if assumptions is None:
  129. return obj.is_extended_real
  130. return ask(Q.extended_real(obj), assumptions)
  131. def is_extended_nonnegative(obj, assumptions=None):
  132. if assumptions is None:
  133. return obj.is_extended_nonnegative
  134. return ask(Q.extended_nonnegative(obj), assumptions)