test_basic.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. """This tests sympy/core/basic.py with (ideally) no reference to subclasses
  2. of Basic or Atom."""
  3. import collections
  4. from sympy.assumptions.ask import Q
  5. from sympy.core.basic import (Basic, Atom, as_Basic,
  6. _atomic, _aresame)
  7. from sympy.core.containers import Tuple
  8. from sympy.core.function import Function, Lambda
  9. from sympy.core.numbers import I, pi
  10. from sympy.core.singleton import S
  11. from sympy.core.symbol import symbols, Symbol, Dummy
  12. from sympy.concrete.summations import Sum
  13. from sympy.functions.elementary.trigonometric import (cos, sin)
  14. from sympy.functions.special.gamma_functions import gamma
  15. from sympy.integrals.integrals import Integral
  16. from sympy.functions.elementary.exponential import exp
  17. from sympy.testing.pytest import raises, warns_deprecated_sympy
  18. b1 = Basic()
  19. b2 = Basic(b1)
  20. b3 = Basic(b2)
  21. b21 = Basic(b2, b1)
  22. def test__aresame():
  23. assert not _aresame(Basic(Tuple()), Basic())
  24. assert not _aresame(Basic(S(2)), Basic(S(2.)))
  25. def test_structure():
  26. assert b21.args == (b2, b1)
  27. assert b21.func(*b21.args) == b21
  28. assert bool(b1)
  29. def test_immutable():
  30. assert not hasattr(b1, '__dict__')
  31. with raises(AttributeError):
  32. b1.x = 1
  33. def test_equality():
  34. instances = [b1, b2, b3, b21, Basic(b1, b1, b1), Basic]
  35. for i, b_i in enumerate(instances):
  36. for j, b_j in enumerate(instances):
  37. assert (b_i == b_j) == (i == j)
  38. assert (b_i != b_j) == (i != j)
  39. assert Basic() != []
  40. assert not(Basic() == [])
  41. assert Basic() != 0
  42. assert not(Basic() == 0)
  43. class Foo:
  44. """
  45. Class that is unaware of Basic, and relies on both classes returning
  46. the NotImplemented singleton for equivalence to evaluate to False.
  47. """
  48. b = Basic()
  49. foo = Foo()
  50. assert b != foo
  51. assert foo != b
  52. assert not b == foo
  53. assert not foo == b
  54. class Bar:
  55. """
  56. Class that considers itself equal to any instance of Basic, and relies
  57. on Basic returning the NotImplemented singleton in order to achieve
  58. a symmetric equivalence relation.
  59. """
  60. def __eq__(self, other):
  61. if isinstance(other, Basic):
  62. return True
  63. return NotImplemented
  64. def __ne__(self, other):
  65. return not self == other
  66. bar = Bar()
  67. assert b == bar
  68. assert bar == b
  69. assert not b != bar
  70. assert not bar != b
  71. def test_matches_basic():
  72. instances = [Basic(b1, b1, b2), Basic(b1, b2, b1), Basic(b2, b1, b1),
  73. Basic(b1, b2), Basic(b2, b1), b2, b1]
  74. for i, b_i in enumerate(instances):
  75. for j, b_j in enumerate(instances):
  76. if i == j:
  77. assert b_i.matches(b_j) == {}
  78. else:
  79. assert b_i.matches(b_j) is None
  80. assert b1.match(b1) == {}
  81. def test_has():
  82. assert b21.has(b1)
  83. assert b21.has(b3, b1)
  84. assert b21.has(Basic)
  85. assert not b1.has(b21, b3)
  86. assert not b21.has()
  87. assert not b21.has(str)
  88. assert not Symbol("x").has("x")
  89. def test_subs():
  90. assert b21.subs(b2, b1) == Basic(b1, b1)
  91. assert b21.subs(b2, b21) == Basic(b21, b1)
  92. assert b3.subs(b2, b1) == b2
  93. assert b21.subs([(b2, b1), (b1, b2)]) == Basic(b2, b2)
  94. assert b21.subs({b1: b2, b2: b1}) == Basic(b2, b2)
  95. assert b21.subs(collections.ChainMap({b1: b2}, {b2: b1})) == Basic(b2, b2)
  96. assert b21.subs(collections.OrderedDict([(b2, b1), (b1, b2)])) == Basic(b2, b2)
  97. raises(ValueError, lambda: b21.subs('bad arg'))
  98. raises(ValueError, lambda: b21.subs(b1, b2, b3))
  99. # dict(b1=foo) creates a string 'b1' but leaves foo unchanged; subs
  100. # will convert the first to a symbol but will raise an error if foo
  101. # cannot be sympified; sympification is strict if foo is not string
  102. raises(ValueError, lambda: b21.subs(b1='bad arg'))
  103. assert Symbol("text").subs({"text": b1}) == b1
  104. assert Symbol("s").subs({"s": 1}) == 1
  105. def test_subs_with_unicode_symbols():
  106. expr = Symbol('var1')
  107. replaced = expr.subs('var1', 'x')
  108. assert replaced.name == 'x'
  109. replaced = expr.subs('var1', 'x')
  110. assert replaced.name == 'x'
  111. def test_atoms():
  112. assert b21.atoms() == {Basic()}
  113. def test_free_symbols_empty():
  114. assert b21.free_symbols == set()
  115. def test_doit():
  116. assert b21.doit() == b21
  117. assert b21.doit(deep=False) == b21
  118. def test_S():
  119. assert repr(S) == 'S'
  120. def test_xreplace():
  121. assert b21.xreplace({b2: b1}) == Basic(b1, b1)
  122. assert b21.xreplace({b2: b21}) == Basic(b21, b1)
  123. assert b3.xreplace({b2: b1}) == b2
  124. assert Basic(b1, b2).xreplace({b1: b2, b2: b1}) == Basic(b2, b1)
  125. assert Atom(b1).xreplace({b1: b2}) == Atom(b1)
  126. assert Atom(b1).xreplace({Atom(b1): b2}) == b2
  127. raises(TypeError, lambda: b1.xreplace())
  128. raises(TypeError, lambda: b1.xreplace([b1, b2]))
  129. for f in (exp, Function('f')):
  130. assert f.xreplace({}) == f
  131. assert f.xreplace({}, hack2=True) == f
  132. assert f.xreplace({f: b1}) == b1
  133. assert f.xreplace({f: b1}, hack2=True) == b1
  134. def test_sorted_args():
  135. x = symbols('x')
  136. assert b21._sorted_args == b21.args
  137. raises(AttributeError, lambda: x._sorted_args)
  138. def test_call():
  139. x, y = symbols('x y')
  140. # See the long history of this in issues 5026 and 5105.
  141. raises(TypeError, lambda: sin(x)({ x : 1, sin(x) : 2}))
  142. raises(TypeError, lambda: sin(x)(1))
  143. # No effect as there are no callables
  144. assert sin(x).rcall(1) == sin(x)
  145. assert (1 + sin(x)).rcall(1) == 1 + sin(x)
  146. # Effect in the pressence of callables
  147. l = Lambda(x, 2*x)
  148. assert (l + x).rcall(y) == 2*y + x
  149. assert (x**l).rcall(2) == x**4
  150. # TODO UndefinedFunction does not subclass Expr
  151. #f = Function('f')
  152. #assert (2*f)(x) == 2*f(x)
  153. assert (Q.real & Q.positive).rcall(x) == Q.real(x) & Q.positive(x)
  154. def test_rewrite():
  155. x, y, z = symbols('x y z')
  156. a, b = symbols('a b')
  157. f1 = sin(x) + cos(x)
  158. assert f1.rewrite(cos,exp) == exp(I*x)/2 + sin(x) + exp(-I*x)/2
  159. assert f1.rewrite([cos],sin) == sin(x) + sin(x + pi/2, evaluate=False)
  160. f2 = sin(x) + cos(y)/gamma(z)
  161. assert f2.rewrite(sin,exp) == -I*(exp(I*x) - exp(-I*x))/2 + cos(y)/gamma(z)
  162. assert f1.rewrite() == f1
  163. def test_literal_evalf_is_number_is_zero_is_comparable():
  164. x = symbols('x')
  165. f = Function('f')
  166. # issue 5033
  167. assert f.is_number is False
  168. # issue 6646
  169. assert f(1).is_number is False
  170. i = Integral(0, (x, x, x))
  171. # expressions that are symbolically 0 can be difficult to prove
  172. # so in case there is some easy way to know if something is 0
  173. # it should appear in the is_zero property for that object;
  174. # if is_zero is true evalf should always be able to compute that
  175. # zero
  176. assert i.n() == 0
  177. assert i.is_zero
  178. assert i.is_number is False
  179. assert i.evalf(2, strict=False) == 0
  180. # issue 10268
  181. n = sin(1)**2 + cos(1)**2 - 1
  182. assert n.is_comparable is False
  183. assert n.n(2).is_comparable is False
  184. assert n.n(2).n(2).is_comparable
  185. def test_as_Basic():
  186. assert as_Basic(1) is S.One
  187. assert as_Basic(()) == Tuple()
  188. raises(TypeError, lambda: as_Basic([]))
  189. def test_atomic():
  190. g, h = map(Function, 'gh')
  191. x = symbols('x')
  192. assert _atomic(g(x + h(x))) == {g(x + h(x))}
  193. assert _atomic(g(x + h(x)), recursive=True) == {h(x), x, g(x + h(x))}
  194. assert _atomic(1) == set()
  195. assert _atomic(Basic(S(1), S(2))) == set()
  196. def test_as_dummy():
  197. u, v, x, y, z, _0, _1 = symbols('u v x y z _0 _1')
  198. assert Lambda(x, x + 1).as_dummy() == Lambda(_0, _0 + 1)
  199. assert Lambda(x, x + _0).as_dummy() == Lambda(_1, _0 + _1)
  200. eq = (1 + Sum(x, (x, 1, x)))
  201. ans = 1 + Sum(_0, (_0, 1, x))
  202. once = eq.as_dummy()
  203. assert once == ans
  204. twice = once.as_dummy()
  205. assert twice == ans
  206. assert Integral(x + _0, (x, x + 1), (_0, 1, 2)
  207. ).as_dummy() == Integral(_0 + _1, (_0, x + 1), (_1, 1, 2))
  208. for T in (Symbol, Dummy):
  209. d = T('x', real=True)
  210. D = d.as_dummy()
  211. assert D != d and D.func == Dummy and D.is_real is None
  212. assert Dummy().as_dummy().is_commutative
  213. assert Dummy(commutative=False).as_dummy().is_commutative is False
  214. def test_canonical_variables():
  215. x, i0, i1 = symbols('x _:2')
  216. assert Integral(x, (x, x + 1)).canonical_variables == {x: i0}
  217. assert Integral(x, (x, x + 1), (i0, 1, 2)).canonical_variables == {
  218. x: i0, i0: i1}
  219. assert Integral(x, (x, x + i0)).canonical_variables == {x: i1}
  220. def test_replace_exceptions():
  221. from sympy.core.symbol import Wild
  222. x, y = symbols('x y')
  223. e = (x**2 + x*y)
  224. raises(TypeError, lambda: e.replace(sin, 2))
  225. b = Wild('b')
  226. c = Wild('c')
  227. raises(TypeError, lambda: e.replace(b*c, c.is_real))
  228. raises(TypeError, lambda: e.replace(b.is_real, 1))
  229. raises(TypeError, lambda: e.replace(lambda d: d.is_Number, 1))
  230. def test_ManagedProperties():
  231. # ManagedProperties is now deprecated. Here we do our best to check that if
  232. # someone is using it then it does work in the way that it previously did
  233. # but gives a deprecation warning.
  234. from sympy.core.assumptions import ManagedProperties
  235. myclasses = []
  236. class MyMeta(ManagedProperties):
  237. def __init__(cls, *args, **kwargs):
  238. myclasses.append('executed')
  239. super().__init__(*args, **kwargs)
  240. code = """
  241. class MySubclass(Basic, metaclass=MyMeta):
  242. pass
  243. """
  244. with warns_deprecated_sympy():
  245. exec(code)
  246. assert myclasses == ['executed']