Path: blob/main/python/py-sympy/src/test_basic.py
1396 views
"""This tests sympy/core/basic.py with (ideally) no reference to subclasses1of Basic or Atom."""23import collections45from sympy.assumptions.ask import Q6from sympy.core.basic import (Basic, Atom, as_Basic,7_atomic, _aresame)8from sympy.core.containers import Tuple9from sympy.core.function import Function, Lambda10from sympy.core.numbers import I, pi11from sympy.core.singleton import S12from sympy.core.symbol import symbols, Symbol, Dummy13from sympy.concrete.summations import Sum14from sympy.functions.elementary.trigonometric import (cos, sin)15from sympy.functions.special.gamma_functions import gamma16from sympy.integrals.integrals import Integral17from sympy.functions.elementary.exponential import exp18from sympy.testing.pytest import raises1920b1 = Basic()21b2 = Basic(b1)22b3 = Basic(b2)23b21 = Basic(b2, b1)242526def test__aresame():27assert not _aresame(Basic(Tuple()), Basic())28assert not _aresame(Basic(S(2)), Basic(S(2.)))293031def test_structure():32assert b21.args == (b2, b1)33assert b21.func(*b21.args) == b2134assert bool(b1)353637def test_immutable():38assert not hasattr(b1, '__dict__')39with raises(AttributeError):40b1.x = 1414243def test_equality():44instances = [b1, b2, b3, b21, Basic(b1, b1, b1), Basic]45for i, b_i in enumerate(instances):46for j, b_j in enumerate(instances):47assert (b_i == b_j) == (i == j)48assert (b_i != b_j) == (i != j)4950assert Basic() != []51assert not(Basic() == [])52assert Basic() != 053assert not(Basic() == 0)5455class Foo:56"""57Class that is unaware of Basic, and relies on both classes returning58the NotImplemented singleton for equivalence to evaluate to False.5960"""6162b = Basic()63foo = Foo()6465assert b != foo66assert foo != b67assert not b == foo68assert not foo == b6970class Bar:71"""72Class that considers itself equal to any instance of Basic, and relies73on Basic returning the NotImplemented singleton in order to achieve74a symmetric equivalence relation.7576"""77def __eq__(self, other):78if isinstance(other, Basic):79return True80return NotImplemented8182def __ne__(self, other):83return not self == other8485bar = Bar()8687assert b == bar88assert bar == b89assert not b != bar90assert not bar != b919293def test_matches_basic():94instances = [Basic(b1, b1, b2), Basic(b1, b2, b1), Basic(b2, b1, b1),95Basic(b1, b2), Basic(b2, b1), b2, b1]96for i, b_i in enumerate(instances):97for j, b_j in enumerate(instances):98if i == j:99assert b_i.matches(b_j) == {}100else:101assert b_i.matches(b_j) is None102assert b1.match(b1) == {}103104105def test_has():106assert b21.has(b1)107assert b21.has(b3, b1)108assert b21.has(Basic)109assert not b1.has(b21, b3)110assert not b21.has()111assert not b21.has(str)112assert not Symbol("x").has("x")113114115def test_subs():116assert b21.subs(b2, b1) == Basic(b1, b1)117assert b21.subs(b2, b21) == Basic(b21, b1)118assert b3.subs(b2, b1) == b2119120assert b21.subs([(b2, b1), (b1, b2)]) == Basic(b2, b2)121122assert b21.subs({b1: b2, b2: b1}) == Basic(b2, b2)123assert b21.subs(collections.ChainMap({b1: b2}, {b2: b1})) == Basic(b2, b2)124assert b21.subs(collections.OrderedDict([(b2, b1), (b1, b2)])) == Basic(b2, b2)125126raises(ValueError, lambda: b21.subs('bad arg'))127raises(ValueError, lambda: b21.subs(b1, b2, b3))128# dict(b1=foo) creates a string 'b1' but leaves foo unchanged; subs129# will convert the first to a symbol but will raise an error if foo130# cannot be sympified; sympification is strict if foo is not string131raises(ValueError, lambda: b21.subs(b1='bad arg'))132133assert Symbol("text").subs({"text": b1}) == b1134assert Symbol("s").subs({"s": 1}) == 1135136137def test_subs_with_unicode_symbols():138expr = Symbol('var1')139replaced = expr.subs('var1', 'x')140assert replaced.name == 'x'141142replaced = expr.subs('var1', 'x')143assert replaced.name == 'x'144145146def test_atoms():147assert b21.atoms() == {Basic()}148149150def test_free_symbols_empty():151assert b21.free_symbols == set()152153154def test_doit():155assert b21.doit() == b21156assert b21.doit(deep=False) == b21157158159def test_S():160assert repr(S) == 'S'161162163def test_xreplace():164assert b21.xreplace({b2: b1}) == Basic(b1, b1)165assert b21.xreplace({b2: b21}) == Basic(b21, b1)166assert b3.xreplace({b2: b1}) == b2167assert Basic(b1, b2).xreplace({b1: b2, b2: b1}) == Basic(b2, b1)168assert Atom(b1).xreplace({b1: b2}) == Atom(b1)169assert Atom(b1).xreplace({Atom(b1): b2}) == b2170raises(TypeError, lambda: b1.xreplace())171raises(TypeError, lambda: b1.xreplace([b1, b2]))172for f in (exp, Function('f')):173assert f.xreplace({}) == f174assert f.xreplace({}, hack2=True) == f175assert f.xreplace({f: b1}) == b1176assert f.xreplace({f: b1}, hack2=True) == b1177178179def test_sorted_args():180x = symbols('x')181assert b21._sorted_args == b21.args182raises(AttributeError, lambda: x._sorted_args)183184def test_call():185x, y = symbols('x y')186# See the long history of this in issues 5026 and 5105.187188raises(TypeError, lambda: sin(x)({ x : 1, sin(x) : 2}))189raises(TypeError, lambda: sin(x)(1))190191# No effect as there are no callables192assert sin(x).rcall(1) == sin(x)193assert (1 + sin(x)).rcall(1) == 1 + sin(x)194195# Effect in the pressence of callables196l = Lambda(x, 2*x)197assert (l + x).rcall(y) == 2*y + x198assert (x**l).rcall(2) == x**4199# TODO UndefinedFunction does not subclass Expr200#f = Function('f')201#assert (2*f)(x) == 2*f(x)202203assert (Q.real & Q.positive).rcall(x) == Q.real(x) & Q.positive(x)204205206def test_rewrite():207x, y, z = symbols('x y z')208a, b = symbols('a b')209f1 = sin(x) + cos(x)210assert f1.rewrite(cos,exp) == exp(I*x)/2 + sin(x) + exp(-I*x)/2211assert f1.rewrite([cos],sin) == sin(x) + sin(x + pi/2, evaluate=False)212f2 = sin(x) + cos(y)/gamma(z)213assert f2.rewrite(sin,exp) == -I*(exp(I*x) - exp(-I*x))/2 + cos(y)/gamma(z)214215assert f1.rewrite() == f1216217def test_literal_evalf_is_number_is_zero_is_comparable():218x = symbols('x')219f = Function('f')220221# issue 5033222assert f.is_number is False223# issue 6646224assert f(1).is_number is False225i = Integral(0, (x, x, x))226# expressions that are symbolically 0 can be difficult to prove227# so in case there is some easy way to know if something is 0228# it should appear in the is_zero property for that object;229# if is_zero is true evalf should always be able to compute that230# zero231assert i.n() == 0232assert i.is_zero233assert i.is_number is False234assert i.evalf(2, strict=False) == 0235236# issue 10268237n = sin(1)**2 + cos(1)**2 - 1238assert n.is_comparable is False239assert n.n(2).is_comparable is False240assert n.n(2).n(2).is_comparable241242243def test_as_Basic():244assert as_Basic(1) is S.One245assert as_Basic(()) == Tuple()246raises(TypeError, lambda: as_Basic([]))247248249def test_atomic():250g, h = map(Function, 'gh')251x = symbols('x')252assert _atomic(g(x + h(x))) == {g(x + h(x))}253assert _atomic(g(x + h(x)), recursive=True) == {h(x), x, g(x + h(x))}254assert _atomic(1) == set()255assert _atomic(Basic(S(1), S(2))) == set()256257258def test_as_dummy():259u, v, x, y, z, _0, _1 = symbols('u v x y z _0 _1')260assert Lambda(x, x + 1).as_dummy() == Lambda(_0, _0 + 1)261assert Lambda(x, x + _0).as_dummy() == Lambda(_1, _0 + _1)262eq = (1 + Sum(x, (x, 1, x)))263ans = 1 + Sum(_0, (_0, 1, x))264once = eq.as_dummy()265assert once == ans266twice = once.as_dummy()267assert twice == ans268assert Integral(x + _0, (x, x + 1), (_0, 1, 2)269).as_dummy() == Integral(_0 + _1, (_0, x + 1), (_1, 1, 2))270for T in (Symbol, Dummy):271d = T('x', real=True)272D = d.as_dummy()273assert D != d and D.func == Dummy and D.is_real is None274assert Dummy().as_dummy().is_commutative275assert Dummy(commutative=False).as_dummy().is_commutative is False276277278def test_canonical_variables():279x, i0, i1 = symbols('x _:2')280assert Integral(x, (x, x + 1)).canonical_variables == {x: i0}281assert Integral(x, (x, x + 1), (i0, 1, 2)).canonical_variables == {282x: i0, i0: i1}283assert Integral(x, (x, x + i0)).canonical_variables == {x: i1}284285286def test_replace_exceptions():287from sympy.core.symbol import Wild288x, y = symbols('x y')289e = (x**2 + x*y)290raises(TypeError, lambda: e.replace(sin, 2))291b = Wild('b')292c = Wild('c')293raises(TypeError, lambda: e.replace(b*c, c.is_real))294raises(TypeError, lambda: e.replace(b.is_real, 1))295raises(TypeError, lambda: e.replace(lambda d: d.is_Number, 1))296297if __name__ == "__main__":298tests = [f for f in globals().keys() if f.startswith('test_')]299for f in tests:300globals()[f]()301302