Coverage for /usr/lib/python3/dist-packages/sympy/core/basic.py: 54%

750 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1"""Base class for all the objects in SymPy""" 

2from __future__ import annotations 

3 

4from collections import defaultdict 

5from collections.abc import Mapping 

6from itertools import chain, zip_longest 

7 

8from .assumptions import _prepare_class_assumptions 

9from .cache import cacheit 

10from .core import ordering_of_classes 

11from .sympify import _sympify, sympify, SympifyError, _external_converter 

12from .sorting import ordered 

13from .kind import Kind, UndefinedKind 

14from ._print_helpers import Printable 

15 

16from sympy.utilities.decorator import deprecated 

17from sympy.utilities.exceptions import sympy_deprecation_warning 

18from sympy.utilities.iterables import iterable, numbered_symbols 

19from sympy.utilities.misc import filldedent, func_name 

20 

21from inspect import getmro 

22 

23 

24def as_Basic(expr): 

25 """Return expr as a Basic instance using strict sympify 

26 or raise a TypeError; this is just a wrapper to _sympify, 

27 raising a TypeError instead of a SympifyError.""" 

28 try: 

29 return _sympify(expr) 

30 except SympifyError: 

31 raise TypeError( 

32 'Argument must be a Basic object, not `%s`' % func_name( 

33 expr)) 

34 

35 

36def _old_compare(x: type, y: type) -> int: 

37 # If the other object is not a Basic subclass, then we are not equal to it. 

38 if not issubclass(y, Basic): 

39 return -1 

40 

41 n1 = x.__name__ 

42 n2 = y.__name__ 

43 if n1 == n2: 

44 return 0 

45 

46 UNKNOWN = len(ordering_of_classes) + 1 

47 try: 

48 i1 = ordering_of_classes.index(n1) 

49 except ValueError: 

50 i1 = UNKNOWN 

51 try: 

52 i2 = ordering_of_classes.index(n2) 

53 except ValueError: 

54 i2 = UNKNOWN 

55 if i1 == UNKNOWN and i2 == UNKNOWN: 

56 return (n1 > n2) - (n1 < n2) 

57 return (i1 > i2) - (i1 < i2) 

58 

59 

60class Basic(Printable): 

61 """ 

62 Base class for all SymPy objects. 

63 

64 Notes and conventions 

65 ===================== 

66 

67 1) Always use ``.args``, when accessing parameters of some instance: 

68 

69 >>> from sympy import cot 

70 >>> from sympy.abc import x, y 

71 

72 >>> cot(x).args 

73 (x,) 

74 

75 >>> cot(x).args[0] 

76 x 

77 

78 >>> (x*y).args 

79 (x, y) 

80 

81 >>> (x*y).args[1] 

82 y 

83 

84 

85 2) Never use internal methods or variables (the ones prefixed with ``_``): 

86 

87 >>> cot(x)._args # do not use this, use cot(x).args instead 

88 (x,) 

89 

90 

91 3) By "SymPy object" we mean something that can be returned by 

92 ``sympify``. But not all objects one encounters using SymPy are 

93 subclasses of Basic. For example, mutable objects are not: 

94 

95 >>> from sympy import Basic, Matrix, sympify 

96 >>> A = Matrix([[1, 2], [3, 4]]).as_mutable() 

97 >>> isinstance(A, Basic) 

98 False 

99 

100 >>> B = sympify(A) 

101 >>> isinstance(B, Basic) 

102 True 

103 """ 

104 __slots__ = ('_mhash', # hash value 

105 '_args', # arguments 

106 '_assumptions' 

107 ) 

108 

109 _args: tuple[Basic, ...] 

110 _mhash: int | None 

111 

112 @property 

113 def __sympy__(self): 

114 return True 

115 

116 def __init_subclass__(cls): 

117 # Initialize the default_assumptions FactKB and also any assumptions 

118 # property methods. This method will only be called for subclasses of 

119 # Basic but not for Basic itself so we call 

120 # _prepare_class_assumptions(Basic) below the class definition. 

121 _prepare_class_assumptions(cls) 

122 

123 # To be overridden with True in the appropriate subclasses 

124 is_number = False 

125 is_Atom = False 

126 is_Symbol = False 

127 is_symbol = False 

128 is_Indexed = False 

129 is_Dummy = False 

130 is_Wild = False 

131 is_Function = False 

132 is_Add = False 

133 is_Mul = False 

134 is_Pow = False 

135 is_Number = False 

136 is_Float = False 

137 is_Rational = False 

138 is_Integer = False 

139 is_NumberSymbol = False 

140 is_Order = False 

141 is_Derivative = False 

142 is_Piecewise = False 

143 is_Poly = False 

144 is_AlgebraicNumber = False 

145 is_Relational = False 

146 is_Equality = False 

147 is_Boolean = False 

148 is_Not = False 

149 is_Matrix = False 

150 is_Vector = False 

151 is_Point = False 

152 is_MatAdd = False 

153 is_MatMul = False 

154 is_real: bool | None 

155 is_extended_real: bool | None 

156 is_zero: bool | None 

157 is_negative: bool | None 

158 is_commutative: bool | None 

159 

160 kind: Kind = UndefinedKind 

161 

162 def __new__(cls, *args): 

163 obj = object.__new__(cls) 

164 obj._assumptions = cls.default_assumptions 

165 obj._mhash = None # will be set by __hash__ method. 

166 

167 obj._args = args # all items in args must be Basic objects 

168 return obj 

169 

170 def copy(self): 

171 return self.func(*self.args) 

172 

173 def __getnewargs__(self): 

174 return self.args 

175 

176 def __getstate__(self): 

177 return None 

178 

179 def __setstate__(self, state): 

180 for name, value in state.items(): 

181 setattr(self, name, value) 

182 

183 def __reduce_ex__(self, protocol): 

184 if protocol < 2: 

185 msg = "Only pickle protocol 2 or higher is supported by SymPy" 

186 raise NotImplementedError(msg) 

187 return super().__reduce_ex__(protocol) 

188 

189 def __hash__(self) -> int: 

190 # hash cannot be cached using cache_it because infinite recurrence 

191 # occurs as hash is needed for setting cache dictionary keys 

192 h = self._mhash 

193 if h is None: 

194 h = hash((type(self).__name__,) + self._hashable_content()) 

195 self._mhash = h 

196 return h 

197 

198 def _hashable_content(self): 

199 """Return a tuple of information about self that can be used to 

200 compute the hash. If a class defines additional attributes, 

201 like ``name`` in Symbol, then this method should be updated 

202 accordingly to return such relevant attributes. 

203 

204 Defining more than _hashable_content is necessary if __eq__ has 

205 been defined by a class. See note about this in Basic.__eq__.""" 

206 return self._args 

207 

208 @property 

209 def assumptions0(self): 

210 """ 

211 Return object `type` assumptions. 

212 

213 For example: 

214 

215 Symbol('x', real=True) 

216 Symbol('x', integer=True) 

217 

218 are different objects. In other words, besides Python type (Symbol in 

219 this case), the initial assumptions are also forming their typeinfo. 

220 

221 Examples 

222 ======== 

223 

224 >>> from sympy import Symbol 

225 >>> from sympy.abc import x 

226 >>> x.assumptions0 

227 {'commutative': True} 

228 >>> x = Symbol("x", positive=True) 

229 >>> x.assumptions0 

230 {'commutative': True, 'complex': True, 'extended_negative': False, 

231 'extended_nonnegative': True, 'extended_nonpositive': False, 

232 'extended_nonzero': True, 'extended_positive': True, 'extended_real': 

233 True, 'finite': True, 'hermitian': True, 'imaginary': False, 

234 'infinite': False, 'negative': False, 'nonnegative': True, 

235 'nonpositive': False, 'nonzero': True, 'positive': True, 'real': 

236 True, 'zero': False} 

237 """ 

238 return {} 

239 

240 def compare(self, other): 

241 """ 

242 Return -1, 0, 1 if the object is smaller, equal, or greater than other. 

243 

244 Not in the mathematical sense. If the object is of a different type 

245 from the "other" then their classes are ordered according to 

246 the sorted_classes list. 

247 

248 Examples 

249 ======== 

250 

251 >>> from sympy.abc import x, y 

252 >>> x.compare(y) 

253 -1 

254 >>> x.compare(x) 

255 0 

256 >>> y.compare(x) 

257 1 

258 

259 """ 

260 # all redefinitions of __cmp__ method should start with the 

261 # following lines: 

262 if self is other: 

263 return 0 

264 n1 = self.__class__ 

265 n2 = other.__class__ 

266 c = _old_compare(n1, n2) 

267 if c: 

268 return c 

269 # 

270 st = self._hashable_content() 

271 ot = other._hashable_content() 

272 c = (len(st) > len(ot)) - (len(st) < len(ot)) 

273 if c: 

274 return c 

275 for l, r in zip(st, ot): 

276 l = Basic(*l) if isinstance(l, frozenset) else l 

277 r = Basic(*r) if isinstance(r, frozenset) else r 

278 if isinstance(l, Basic): 

279 c = l.compare(r) 

280 else: 

281 c = (l > r) - (l < r) 

282 if c: 

283 return c 

284 return 0 

285 

286 @staticmethod 

287 def _compare_pretty(a, b): 

288 from sympy.series.order import Order 

289 if isinstance(a, Order) and not isinstance(b, Order): 

290 return 1 

291 if not isinstance(a, Order) and isinstance(b, Order): 

292 return -1 

293 

294 if a.is_Rational and b.is_Rational: 

295 l = a.p * b.q 

296 r = b.p * a.q 

297 return (l > r) - (l < r) 

298 else: 

299 from .symbol import Wild 

300 p1, p2, p3 = Wild("p1"), Wild("p2"), Wild("p3") 

301 r_a = a.match(p1 * p2**p3) 

302 if r_a and p3 in r_a: 

303 a3 = r_a[p3] 

304 r_b = b.match(p1 * p2**p3) 

305 if r_b and p3 in r_b: 

306 b3 = r_b[p3] 

307 c = Basic.compare(a3, b3) 

308 if c != 0: 

309 return c 

310 

311 return Basic.compare(a, b) 

312 

313 @classmethod 

314 def fromiter(cls, args, **assumptions): 

315 """ 

316 Create a new object from an iterable. 

317 

318 This is a convenience function that allows one to create objects from 

319 any iterable, without having to convert to a list or tuple first. 

320 

321 Examples 

322 ======== 

323 

324 >>> from sympy import Tuple 

325 >>> Tuple.fromiter(i for i in range(5)) 

326 (0, 1, 2, 3, 4) 

327 

328 """ 

329 return cls(*tuple(args), **assumptions) 

330 

331 @classmethod 

332 def class_key(cls): 

333 """Nice order of classes.""" 

334 return 5, 0, cls.__name__ 

335 

336 @cacheit 

337 def sort_key(self, order=None): 

338 """ 

339 Return a sort key. 

340 

341 Examples 

342 ======== 

343 

344 >>> from sympy import S, I 

345 

346 >>> sorted([S(1)/2, I, -I], key=lambda x: x.sort_key()) 

347 [1/2, -I, I] 

348 

349 >>> S("[x, 1/x, 1/x**2, x**2, x**(1/2), x**(1/4), x**(3/2)]") 

350 [x, 1/x, x**(-2), x**2, sqrt(x), x**(1/4), x**(3/2)] 

351 >>> sorted(_, key=lambda x: x.sort_key()) 

352 [x**(-2), 1/x, x**(1/4), sqrt(x), x, x**(3/2), x**2] 

353 

354 """ 

355 

356 # XXX: remove this when issue 5169 is fixed 

357 def inner_key(arg): 

358 if isinstance(arg, Basic): 

359 return arg.sort_key(order) 

360 else: 

361 return arg 

362 

363 args = self._sorted_args 

364 args = len(args), tuple([inner_key(arg) for arg in args]) 

365 return self.class_key(), args, S.One.sort_key(), S.One 

366 

367 def _do_eq_sympify(self, other): 

368 """Returns a boolean indicating whether a == b when either a 

369 or b is not a Basic. This is only done for types that were either 

370 added to `converter` by a 3rd party or when the object has `_sympy_` 

371 defined. This essentially reuses the code in `_sympify` that is 

372 specific for this use case. Non-user defined types that are meant 

373 to work with SymPy should be handled directly in the __eq__ methods 

374 of the `Basic` classes it could equate to and not be converted. Note 

375 that after conversion, `==` is used again since it is not 

376 necessarily clear whether `self` or `other`'s __eq__ method needs 

377 to be used.""" 

378 for superclass in type(other).__mro__: 

379 conv = _external_converter.get(superclass) 

380 if conv is not None: 

381 return self == conv(other) 

382 if hasattr(other, '_sympy_'): 

383 return self == other._sympy_() 

384 return NotImplemented 

385 

386 def __eq__(self, other): 

387 """Return a boolean indicating whether a == b on the basis of 

388 their symbolic trees. 

389 

390 This is the same as a.compare(b) == 0 but faster. 

391 

392 Notes 

393 ===== 

394 

395 If a class that overrides __eq__() needs to retain the 

396 implementation of __hash__() from a parent class, the 

397 interpreter must be told this explicitly by setting 

398 __hash__ : Callable[[object], int] = <ParentClass>.__hash__. 

399 Otherwise the inheritance of __hash__() will be blocked, 

400 just as if __hash__ had been explicitly set to None. 

401 

402 References 

403 ========== 

404 

405 from https://docs.python.org/dev/reference/datamodel.html#object.__hash__ 

406 """ 

407 if self is other: 

408 return True 

409 

410 if not isinstance(other, Basic): 

411 return self._do_eq_sympify(other) 

412 

413 # check for pure number expr 

414 if not (self.is_Number and other.is_Number) and ( 

415 type(self) != type(other)): 

416 return False 

417 a, b = self._hashable_content(), other._hashable_content() 

418 if a != b: 

419 return False 

420 # check number *in* an expression 

421 for a, b in zip(a, b): 

422 if not isinstance(a, Basic): 

423 continue 

424 if a.is_Number and type(a) != type(b): 

425 return False 

426 return True 

427 

428 def __ne__(self, other): 

429 """``a != b`` -> Compare two symbolic trees and see whether they are different 

430 

431 this is the same as: 

432 

433 ``a.compare(b) != 0`` 

434 

435 but faster 

436 """ 

437 return not self == other 

438 

439 def dummy_eq(self, other, symbol=None): 

440 """ 

441 Compare two expressions and handle dummy symbols. 

442 

443 Examples 

444 ======== 

445 

446 >>> from sympy import Dummy 

447 >>> from sympy.abc import x, y 

448 

449 >>> u = Dummy('u') 

450 

451 >>> (u**2 + 1).dummy_eq(x**2 + 1) 

452 True 

453 >>> (u**2 + 1) == (x**2 + 1) 

454 False 

455 

456 >>> (u**2 + y).dummy_eq(x**2 + y, x) 

457 True 

458 >>> (u**2 + y).dummy_eq(x**2 + y, y) 

459 False 

460 

461 """ 

462 s = self.as_dummy() 

463 o = _sympify(other) 

464 o = o.as_dummy() 

465 

466 dummy_symbols = [i for i in s.free_symbols if i.is_Dummy] 

467 

468 if len(dummy_symbols) == 1: 

469 dummy = dummy_symbols.pop() 

470 else: 

471 return s == o 

472 

473 if symbol is None: 

474 symbols = o.free_symbols 

475 

476 if len(symbols) == 1: 

477 symbol = symbols.pop() 

478 else: 

479 return s == o 

480 

481 tmp = dummy.__class__() 

482 

483 return s.xreplace({dummy: tmp}) == o.xreplace({symbol: tmp}) 

484 

485 def atoms(self, *types): 

486 """Returns the atoms that form the current object. 

487 

488 By default, only objects that are truly atomic and cannot 

489 be divided into smaller pieces are returned: symbols, numbers, 

490 and number symbols like I and pi. It is possible to request 

491 atoms of any type, however, as demonstrated below. 

492 

493 Examples 

494 ======== 

495 

496 >>> from sympy import I, pi, sin 

497 >>> from sympy.abc import x, y 

498 >>> (1 + x + 2*sin(y + I*pi)).atoms() 

499 {1, 2, I, pi, x, y} 

500 

501 If one or more types are given, the results will contain only 

502 those types of atoms. 

503 

504 >>> from sympy import Number, NumberSymbol, Symbol 

505 >>> (1 + x + 2*sin(y + I*pi)).atoms(Symbol) 

506 {x, y} 

507 

508 >>> (1 + x + 2*sin(y + I*pi)).atoms(Number) 

509 {1, 2} 

510 

511 >>> (1 + x + 2*sin(y + I*pi)).atoms(Number, NumberSymbol) 

512 {1, 2, pi} 

513 

514 >>> (1 + x + 2*sin(y + I*pi)).atoms(Number, NumberSymbol, I) 

515 {1, 2, I, pi} 

516 

517 Note that I (imaginary unit) and zoo (complex infinity) are special 

518 types of number symbols and are not part of the NumberSymbol class. 

519 

520 The type can be given implicitly, too: 

521 

522 >>> (1 + x + 2*sin(y + I*pi)).atoms(x) # x is a Symbol 

523 {x, y} 

524 

525 Be careful to check your assumptions when using the implicit option 

526 since ``S(1).is_Integer = True`` but ``type(S(1))`` is ``One``, a special type 

527 of SymPy atom, while ``type(S(2))`` is type ``Integer`` and will find all 

528 integers in an expression: 

529 

530 >>> from sympy import S 

531 >>> (1 + x + 2*sin(y + I*pi)).atoms(S(1)) 

532 {1} 

533 

534 >>> (1 + x + 2*sin(y + I*pi)).atoms(S(2)) 

535 {1, 2} 

536 

537 Finally, arguments to atoms() can select more than atomic atoms: any 

538 SymPy type (loaded in core/__init__.py) can be listed as an argument 

539 and those types of "atoms" as found in scanning the arguments of the 

540 expression recursively: 

541 

542 >>> from sympy import Function, Mul 

543 >>> from sympy.core.function import AppliedUndef 

544 >>> f = Function('f') 

545 >>> (1 + f(x) + 2*sin(y + I*pi)).atoms(Function) 

546 {f(x), sin(y + I*pi)} 

547 >>> (1 + f(x) + 2*sin(y + I*pi)).atoms(AppliedUndef) 

548 {f(x)} 

549 

550 >>> (1 + x + 2*sin(y + I*pi)).atoms(Mul) 

551 {I*pi, 2*sin(y + I*pi)} 

552 

553 """ 

554 if types: 

555 types = tuple( 

556 [t if isinstance(t, type) else type(t) for t in types]) 

557 nodes = _preorder_traversal(self) 

558 if types: 

559 result = {node for node in nodes if isinstance(node, types)} 

560 else: 

561 result = {node for node in nodes if not node.args} 

562 return result 

563 

564 @property 

565 def free_symbols(self) -> set[Basic]: 

566 """Return from the atoms of self those which are free symbols. 

567 

568 Not all free symbols are ``Symbol``. Eg: IndexedBase('I')[0].free_symbols 

569 

570 For most expressions, all symbols are free symbols. For some classes 

571 this is not true. e.g. Integrals use Symbols for the dummy variables 

572 which are bound variables, so Integral has a method to return all 

573 symbols except those. Derivative keeps track of symbols with respect 

574 to which it will perform a derivative; those are 

575 bound variables, too, so it has its own free_symbols method. 

576 

577 Any other method that uses bound variables should implement a 

578 free_symbols method.""" 

579 empty: set[Basic] = set() 

580 return empty.union(*(a.free_symbols for a in self.args)) 

581 

582 @property 

583 def expr_free_symbols(self): 

584 sympy_deprecation_warning(""" 

585 The expr_free_symbols property is deprecated. Use free_symbols to get 

586 the free symbols of an expression. 

587 """, 

588 deprecated_since_version="1.9", 

589 active_deprecations_target="deprecated-expr-free-symbols") 

590 return set() 

591 

592 def as_dummy(self): 

593 """Return the expression with any objects having structurally 

594 bound symbols replaced with unique, canonical symbols within 

595 the object in which they appear and having only the default 

596 assumption for commutativity being True. When applied to a 

597 symbol a new symbol having only the same commutativity will be 

598 returned. 

599 

600 Examples 

601 ======== 

602 

603 >>> from sympy import Integral, Symbol 

604 >>> from sympy.abc import x 

605 >>> r = Symbol('r', real=True) 

606 >>> Integral(r, (r, x)).as_dummy() 

607 Integral(_0, (_0, x)) 

608 >>> _.variables[0].is_real is None 

609 True 

610 >>> r.as_dummy() 

611 _r 

612 

613 Notes 

614 ===== 

615 

616 Any object that has structurally bound variables should have 

617 a property, `bound_symbols` that returns those symbols 

618 appearing in the object. 

619 """ 

620 from .symbol import Dummy, Symbol 

621 def can(x): 

622 # mask free that shadow bound 

623 free = x.free_symbols 

624 bound = set(x.bound_symbols) 

625 d = {i: Dummy() for i in bound & free} 

626 x = x.subs(d) 

627 # replace bound with canonical names 

628 x = x.xreplace(x.canonical_variables) 

629 # return after undoing masking 

630 return x.xreplace({v: k for k, v in d.items()}) 

631 if not self.has(Symbol): 

632 return self 

633 return self.replace( 

634 lambda x: hasattr(x, 'bound_symbols'), 

635 can, 

636 simultaneous=False) 

637 

638 @property 

639 def canonical_variables(self): 

640 """Return a dictionary mapping any variable defined in 

641 ``self.bound_symbols`` to Symbols that do not clash 

642 with any free symbols in the expression. 

643 

644 Examples 

645 ======== 

646 

647 >>> from sympy import Lambda 

648 >>> from sympy.abc import x 

649 >>> Lambda(x, 2*x).canonical_variables 

650 {x: _0} 

651 """ 

652 if not hasattr(self, 'bound_symbols'): 

653 return {} 

654 dums = numbered_symbols('_') 

655 reps = {} 

656 # watch out for free symbol that are not in bound symbols; 

657 # those that are in bound symbols are about to get changed 

658 bound = self.bound_symbols 

659 names = {i.name for i in self.free_symbols - set(bound)} 

660 for b in bound: 

661 d = next(dums) 

662 if b.is_Symbol: 

663 while d.name in names: 

664 d = next(dums) 

665 reps[b] = d 

666 return reps 

667 

668 def rcall(self, *args): 

669 """Apply on the argument recursively through the expression tree. 

670 

671 This method is used to simulate a common abuse of notation for 

672 operators. For instance, in SymPy the following will not work: 

673 

674 ``(x+Lambda(y, 2*y))(z) == x+2*z``, 

675 

676 however, you can use: 

677 

678 >>> from sympy import Lambda 

679 >>> from sympy.abc import x, y, z 

680 >>> (x + Lambda(y, 2*y)).rcall(z) 

681 x + 2*z 

682 """ 

683 return Basic._recursive_call(self, args) 

684 

685 @staticmethod 

686 def _recursive_call(expr_to_call, on_args): 

687 """Helper for rcall method.""" 

688 from .symbol import Symbol 

689 def the_call_method_is_overridden(expr): 

690 for cls in getmro(type(expr)): 

691 if '__call__' in cls.__dict__: 

692 return cls != Basic 

693 

694 if callable(expr_to_call) and the_call_method_is_overridden(expr_to_call): 

695 if isinstance(expr_to_call, Symbol): # XXX When you call a Symbol it is 

696 return expr_to_call # transformed into an UndefFunction 

697 else: 

698 return expr_to_call(*on_args) 

699 elif expr_to_call.args: 

700 args = [Basic._recursive_call( 

701 sub, on_args) for sub in expr_to_call.args] 

702 return type(expr_to_call)(*args) 

703 else: 

704 return expr_to_call 

705 

706 def is_hypergeometric(self, k): 

707 from sympy.simplify.simplify import hypersimp 

708 from sympy.functions.elementary.piecewise import Piecewise 

709 if self.has(Piecewise): 

710 return None 

711 return hypersimp(self, k) is not None 

712 

713 @property 

714 def is_comparable(self): 

715 """Return True if self can be computed to a real number 

716 (or already is a real number) with precision, else False. 

717 

718 Examples 

719 ======== 

720 

721 >>> from sympy import exp_polar, pi, I 

722 >>> (I*exp_polar(I*pi/2)).is_comparable 

723 True 

724 >>> (I*exp_polar(I*pi*2)).is_comparable 

725 False 

726 

727 A False result does not mean that `self` cannot be rewritten 

728 into a form that would be comparable. For example, the 

729 difference computed below is zero but without simplification 

730 it does not evaluate to a zero with precision: 

731 

732 >>> e = 2**pi*(1 + 2**pi) 

733 >>> dif = e - e.expand() 

734 >>> dif.is_comparable 

735 False 

736 >>> dif.n(2)._prec 

737 1 

738 

739 """ 

740 is_extended_real = self.is_extended_real 

741 if is_extended_real is False: 

742 return False 

743 if not self.is_number: 

744 return False 

745 # don't re-eval numbers that are already evaluated since 

746 # this will create spurious precision 

747 n, i = [p.evalf(2) if not p.is_Number else p 

748 for p in self.as_real_imag()] 

749 if not (i.is_Number and n.is_Number): 

750 return False 

751 if i: 

752 # if _prec = 1 we can't decide and if not, 

753 # the answer is False because numbers with 

754 # imaginary parts can't be compared 

755 # so return False 

756 return False 

757 else: 

758 return n._prec != 1 

759 

760 @property 

761 def func(self): 

762 """ 

763 The top-level function in an expression. 

764 

765 The following should hold for all objects:: 

766 

767 >> x == x.func(*x.args) 

768 

769 Examples 

770 ======== 

771 

772 >>> from sympy.abc import x 

773 >>> a = 2*x 

774 >>> a.func 

775 <class 'sympy.core.mul.Mul'> 

776 >>> a.args 

777 (2, x) 

778 >>> a.func(*a.args) 

779 2*x 

780 >>> a == a.func(*a.args) 

781 True 

782 

783 """ 

784 return self.__class__ 

785 

786 @property 

787 def args(self) -> tuple[Basic, ...]: 

788 """Returns a tuple of arguments of 'self'. 

789 

790 Examples 

791 ======== 

792 

793 >>> from sympy import cot 

794 >>> from sympy.abc import x, y 

795 

796 >>> cot(x).args 

797 (x,) 

798 

799 >>> cot(x).args[0] 

800 x 

801 

802 >>> (x*y).args 

803 (x, y) 

804 

805 >>> (x*y).args[1] 

806 y 

807 

808 Notes 

809 ===== 

810 

811 Never use self._args, always use self.args. 

812 Only use _args in __new__ when creating a new function. 

813 Do not override .args() from Basic (so that it is easy to 

814 change the interface in the future if needed). 

815 """ 

816 return self._args 

817 

818 @property 

819 def _sorted_args(self): 

820 """ 

821 The same as ``args``. Derived classes which do not fix an 

822 order on their arguments should override this method to 

823 produce the sorted representation. 

824 """ 

825 return self.args 

826 

827 def as_content_primitive(self, radical=False, clear=True): 

828 """A stub to allow Basic args (like Tuple) to be skipped when computing 

829 the content and primitive components of an expression. 

830 

831 See Also 

832 ======== 

833 

834 sympy.core.expr.Expr.as_content_primitive 

835 """ 

836 return S.One, self 

837 

838 def subs(self, *args, **kwargs): 

839 """ 

840 Substitutes old for new in an expression after sympifying args. 

841 

842 `args` is either: 

843 - two arguments, e.g. foo.subs(old, new) 

844 - one iterable argument, e.g. foo.subs(iterable). The iterable may be 

845 o an iterable container with (old, new) pairs. In this case the 

846 replacements are processed in the order given with successive 

847 patterns possibly affecting replacements already made. 

848 o a dict or set whose key/value items correspond to old/new pairs. 

849 In this case the old/new pairs will be sorted by op count and in 

850 case of a tie, by number of args and the default_sort_key. The 

851 resulting sorted list is then processed as an iterable container 

852 (see previous). 

853 

854 If the keyword ``simultaneous`` is True, the subexpressions will not be 

855 evaluated until all the substitutions have been made. 

856 

857 Examples 

858 ======== 

859 

860 >>> from sympy import pi, exp, limit, oo 

861 >>> from sympy.abc import x, y 

862 >>> (1 + x*y).subs(x, pi) 

863 pi*y + 1 

864 >>> (1 + x*y).subs({x:pi, y:2}) 

865 1 + 2*pi 

866 >>> (1 + x*y).subs([(x, pi), (y, 2)]) 

867 1 + 2*pi 

868 >>> reps = [(y, x**2), (x, 2)] 

869 >>> (x + y).subs(reps) 

870 6 

871 >>> (x + y).subs(reversed(reps)) 

872 x**2 + 2 

873 

874 >>> (x**2 + x**4).subs(x**2, y) 

875 y**2 + y 

876 

877 To replace only the x**2 but not the x**4, use xreplace: 

878 

879 >>> (x**2 + x**4).xreplace({x**2: y}) 

880 x**4 + y 

881 

882 To delay evaluation until all substitutions have been made, 

883 set the keyword ``simultaneous`` to True: 

884 

885 >>> (x/y).subs([(x, 0), (y, 0)]) 

886 0 

887 >>> (x/y).subs([(x, 0), (y, 0)], simultaneous=True) 

888 nan 

889 

890 This has the added feature of not allowing subsequent substitutions 

891 to affect those already made: 

892 

893 >>> ((x + y)/y).subs({x + y: y, y: x + y}) 

894 1 

895 >>> ((x + y)/y).subs({x + y: y, y: x + y}, simultaneous=True) 

896 y/(x + y) 

897 

898 In order to obtain a canonical result, unordered iterables are 

899 sorted by count_op length, number of arguments and by the 

900 default_sort_key to break any ties. All other iterables are left 

901 unsorted. 

902 

903 >>> from sympy import sqrt, sin, cos 

904 >>> from sympy.abc import a, b, c, d, e 

905 

906 >>> A = (sqrt(sin(2*x)), a) 

907 >>> B = (sin(2*x), b) 

908 >>> C = (cos(2*x), c) 

909 >>> D = (x, d) 

910 >>> E = (exp(x), e) 

911 

912 >>> expr = sqrt(sin(2*x))*sin(exp(x)*x)*cos(2*x) + sin(2*x) 

913 

914 >>> expr.subs(dict([A, B, C, D, E])) 

915 a*c*sin(d*e) + b 

916 

917 The resulting expression represents a literal replacement of the 

918 old arguments with the new arguments. This may not reflect the 

919 limiting behavior of the expression: 

920 

921 >>> (x**3 - 3*x).subs({x: oo}) 

922 nan 

923 

924 >>> limit(x**3 - 3*x, x, oo) 

925 oo 

926 

927 If the substitution will be followed by numerical 

928 evaluation, it is better to pass the substitution to 

929 evalf as 

930 

931 >>> (1/x).evalf(subs={x: 3.0}, n=21) 

932 0.333333333333333333333 

933 

934 rather than 

935 

936 >>> (1/x).subs({x: 3.0}).evalf(21) 

937 0.333333333333333314830 

938 

939 as the former will ensure that the desired level of precision is 

940 obtained. 

941 

942 See Also 

943 ======== 

944 replace: replacement capable of doing wildcard-like matching, 

945 parsing of match, and conditional replacements 

946 xreplace: exact node replacement in expr tree; also capable of 

947 using matching rules 

948 sympy.core.evalf.EvalfMixin.evalf: calculates the given formula to a desired level of precision 

949 

950 """ 

951 from .containers import Dict 

952 from .symbol import Dummy, Symbol 

953 from .numbers import _illegal 

954 

955 unordered = False 

956 if len(args) == 1: 

957 

958 sequence = args[0] 

959 if isinstance(sequence, set): 

960 unordered = True 

961 elif isinstance(sequence, (Dict, Mapping)): 

962 unordered = True 

963 sequence = sequence.items() 

964 elif not iterable(sequence): 

965 raise ValueError(filldedent(""" 

966 When a single argument is passed to subs 

967 it should be a dictionary of old: new pairs or an iterable 

968 of (old, new) tuples.""")) 

969 elif len(args) == 2: 

970 sequence = [args] 

971 else: 

972 raise ValueError("subs accepts either 1 or 2 arguments") 

973 

974 def sympify_old(old): 

975 if isinstance(old, str): 

976 # Use Symbol rather than parse_expr for old 

977 return Symbol(old) 

978 elif isinstance(old, type): 

979 # Allow a type e.g. Function('f') or sin 

980 return sympify(old, strict=False) 

981 else: 

982 return sympify(old, strict=True) 

983 

984 def sympify_new(new): 

985 if isinstance(new, (str, type)): 

986 # Allow a type or parse a string input 

987 return sympify(new, strict=False) 

988 else: 

989 return sympify(new, strict=True) 

990 

991 sequence = [(sympify_old(s1), sympify_new(s2)) for s1, s2 in sequence] 

992 

993 # skip if there is no change 

994 sequence = [(s1, s2) for s1, s2 in sequence if not _aresame(s1, s2)] 

995 

996 simultaneous = kwargs.pop('simultaneous', False) 

997 

998 if unordered: 

999 from .sorting import _nodes, default_sort_key 

1000 sequence = dict(sequence) 

1001 # order so more complex items are first and items 

1002 # of identical complexity are ordered so 

1003 # f(x) < f(y) < x < y 

1004 # \___ 2 __/ \_1_/ <- number of nodes 

1005 # 

1006 # For more complex ordering use an unordered sequence. 

1007 k = list(ordered(sequence, default=False, keys=( 

1008 lambda x: -_nodes(x), 

1009 default_sort_key, 

1010 ))) 

1011 sequence = [(k, sequence[k]) for k in k] 

1012 # do infinities first 

1013 if not simultaneous: 

1014 redo = [i for i, seq in enumerate(sequence) if seq[1] in _illegal] 

1015 for i in reversed(redo): 

1016 sequence.insert(0, sequence.pop(i)) 

1017 

1018 if simultaneous: # XXX should this be the default for dict subs? 

1019 reps = {} 

1020 rv = self 

1021 kwargs['hack2'] = True 

1022 m = Dummy('subs_m') 

1023 for old, new in sequence: 

1024 com = new.is_commutative 

1025 if com is None: 

1026 com = True 

1027 d = Dummy('subs_d', commutative=com) 

1028 # using d*m so Subs will be used on dummy variables 

1029 # in things like Derivative(f(x, y), x) in which x 

1030 # is both free and bound 

1031 rv = rv._subs(old, d*m, **kwargs) 

1032 if not isinstance(rv, Basic): 

1033 break 

1034 reps[d] = new 

1035 reps[m] = S.One # get rid of m 

1036 return rv.xreplace(reps) 

1037 else: 

1038 rv = self 

1039 for old, new in sequence: 

1040 rv = rv._subs(old, new, **kwargs) 

1041 if not isinstance(rv, Basic): 

1042 break 

1043 return rv 

1044 

1045 @cacheit 

1046 def _subs(self, old, new, **hints): 

1047 """Substitutes an expression old -> new. 

1048 

1049 If self is not equal to old then _eval_subs is called. 

1050 If _eval_subs does not want to make any special replacement 

1051 then a None is received which indicates that the fallback 

1052 should be applied wherein a search for replacements is made 

1053 amongst the arguments of self. 

1054 

1055 >>> from sympy import Add 

1056 >>> from sympy.abc import x, y, z 

1057 

1058 Examples 

1059 ======== 

1060 

1061 Add's _eval_subs knows how to target x + y in the following 

1062 so it makes the change: 

1063 

1064 >>> (x + y + z).subs(x + y, 1) 

1065 z + 1 

1066 

1067 Add's _eval_subs does not need to know how to find x + y in 

1068 the following: 

1069 

1070 >>> Add._eval_subs(z*(x + y) + 3, x + y, 1) is None 

1071 True 

1072 

1073 The returned None will cause the fallback routine to traverse the args and 

1074 pass the z*(x + y) arg to Mul where the change will take place and the 

1075 substitution will succeed: 

1076 

1077 >>> (z*(x + y) + 3).subs(x + y, 1) 

1078 z + 3 

1079 

1080 ** Developers Notes ** 

1081 

1082 An _eval_subs routine for a class should be written if: 

1083 

1084 1) any arguments are not instances of Basic (e.g. bool, tuple); 

1085 

1086 2) some arguments should not be targeted (as in integration 

1087 variables); 

1088 

1089 3) if there is something other than a literal replacement 

1090 that should be attempted (as in Piecewise where the condition 

1091 may be updated without doing a replacement). 

1092 

1093 If it is overridden, here are some special cases that might arise: 

1094 

1095 1) If it turns out that no special change was made and all 

1096 the original sub-arguments should be checked for 

1097 replacements then None should be returned. 

1098 

1099 2) If it is necessary to do substitutions on a portion of 

1100 the expression then _subs should be called. _subs will 

1101 handle the case of any sub-expression being equal to old 

1102 (which usually would not be the case) while its fallback 

1103 will handle the recursion into the sub-arguments. For 

1104 example, after Add's _eval_subs removes some matching terms 

1105 it must process the remaining terms so it calls _subs 

1106 on each of the un-matched terms and then adds them 

1107 onto the terms previously obtained. 

1108 

1109 3) If the initial expression should remain unchanged then 

1110 the original expression should be returned. (Whenever an 

1111 expression is returned, modified or not, no further 

1112 substitution of old -> new is attempted.) Sum's _eval_subs 

1113 routine uses this strategy when a substitution is attempted 

1114 on any of its summation variables. 

1115 """ 

1116 

1117 def fallback(self, old, new): 

1118 """ 

1119 Try to replace old with new in any of self's arguments. 

1120 """ 

1121 hit = False 

1122 args = list(self.args) 

1123 for i, arg in enumerate(args): 

1124 if not hasattr(arg, '_eval_subs'): 

1125 continue 

1126 arg = arg._subs(old, new, **hints) 

1127 if not _aresame(arg, args[i]): 

1128 hit = True 

1129 args[i] = arg 

1130 if hit: 

1131 rv = self.func(*args) 

1132 hack2 = hints.get('hack2', False) 

1133 if hack2 and self.is_Mul and not rv.is_Mul: # 2-arg hack 

1134 coeff = S.One 

1135 nonnumber = [] 

1136 for i in args: 

1137 if i.is_Number: 

1138 coeff *= i 

1139 else: 

1140 nonnumber.append(i) 

1141 nonnumber = self.func(*nonnumber) 

1142 if coeff is S.One: 

1143 return nonnumber 

1144 else: 

1145 return self.func(coeff, nonnumber, evaluate=False) 

1146 return rv 

1147 return self 

1148 

1149 if _aresame(self, old): 

1150 return new 

1151 

1152 rv = self._eval_subs(old, new) 

1153 if rv is None: 

1154 rv = fallback(self, old, new) 

1155 return rv 

1156 

1157 def _eval_subs(self, old, new): 

1158 """Override this stub if you want to do anything more than 

1159 attempt a replacement of old with new in the arguments of self. 

1160 

1161 See also 

1162 ======== 

1163 

1164 _subs 

1165 """ 

1166 return None 

1167 

1168 def xreplace(self, rule): 

1169 """ 

1170 Replace occurrences of objects within the expression. 

1171 

1172 Parameters 

1173 ========== 

1174 

1175 rule : dict-like 

1176 Expresses a replacement rule 

1177 

1178 Returns 

1179 ======= 

1180 

1181 xreplace : the result of the replacement 

1182 

1183 Examples 

1184 ======== 

1185 

1186 >>> from sympy import symbols, pi, exp 

1187 >>> x, y, z = symbols('x y z') 

1188 >>> (1 + x*y).xreplace({x: pi}) 

1189 pi*y + 1 

1190 >>> (1 + x*y).xreplace({x: pi, y: 2}) 

1191 1 + 2*pi 

1192 

1193 Replacements occur only if an entire node in the expression tree is 

1194 matched: 

1195 

1196 >>> (x*y + z).xreplace({x*y: pi}) 

1197 z + pi 

1198 >>> (x*y*z).xreplace({x*y: pi}) 

1199 x*y*z 

1200 >>> (2*x).xreplace({2*x: y, x: z}) 

1201 y 

1202 >>> (2*2*x).xreplace({2*x: y, x: z}) 

1203 4*z 

1204 >>> (x + y + 2).xreplace({x + y: 2}) 

1205 x + y + 2 

1206 >>> (x + 2 + exp(x + 2)).xreplace({x + 2: y}) 

1207 x + exp(y) + 2 

1208 

1209 xreplace does not differentiate between free and bound symbols. In the 

1210 following, subs(x, y) would not change x since it is a bound symbol, 

1211 but xreplace does: 

1212 

1213 >>> from sympy import Integral 

1214 >>> Integral(x, (x, 1, 2*x)).xreplace({x: y}) 

1215 Integral(y, (y, 1, 2*y)) 

1216 

1217 Trying to replace x with an expression raises an error: 

1218 

1219 >>> Integral(x, (x, 1, 2*x)).xreplace({x: 2*y}) # doctest: +SKIP 

1220 ValueError: Invalid limits given: ((2*y, 1, 4*y),) 

1221 

1222 See Also 

1223 ======== 

1224 replace: replacement capable of doing wildcard-like matching, 

1225 parsing of match, and conditional replacements 

1226 subs: substitution of subexpressions as defined by the objects 

1227 themselves. 

1228 

1229 """ 

1230 value, _ = self._xreplace(rule) 

1231 return value 

1232 

1233 def _xreplace(self, rule): 

1234 """ 

1235 Helper for xreplace. Tracks whether a replacement actually occurred. 

1236 """ 

1237 if self in rule: 

1238 return rule[self], True 

1239 elif rule: 

1240 args = [] 

1241 changed = False 

1242 for a in self.args: 

1243 _xreplace = getattr(a, '_xreplace', None) 

1244 if _xreplace is not None: 

1245 a_xr = _xreplace(rule) 

1246 args.append(a_xr[0]) 

1247 changed |= a_xr[1] 

1248 else: 

1249 args.append(a) 

1250 args = tuple(args) 

1251 if changed: 

1252 return self.func(*args), True 

1253 return self, False 

1254 

1255 @cacheit 

1256 def has(self, *patterns): 

1257 """ 

1258 Test whether any subexpression matches any of the patterns. 

1259 

1260 Examples 

1261 ======== 

1262 

1263 >>> from sympy import sin 

1264 >>> from sympy.abc import x, y, z 

1265 >>> (x**2 + sin(x*y)).has(z) 

1266 False 

1267 >>> (x**2 + sin(x*y)).has(x, y, z) 

1268 True 

1269 >>> x.has(x) 

1270 True 

1271 

1272 Note ``has`` is a structural algorithm with no knowledge of 

1273 mathematics. Consider the following half-open interval: 

1274 

1275 >>> from sympy import Interval 

1276 >>> i = Interval.Lopen(0, 5); i 

1277 Interval.Lopen(0, 5) 

1278 >>> i.args 

1279 (0, 5, True, False) 

1280 >>> i.has(4) # there is no "4" in the arguments 

1281 False 

1282 >>> i.has(0) # there *is* a "0" in the arguments 

1283 True 

1284 

1285 Instead, use ``contains`` to determine whether a number is in the 

1286 interval or not: 

1287 

1288 >>> i.contains(4) 

1289 True 

1290 >>> i.contains(0) 

1291 False 

1292 

1293 

1294 Note that ``expr.has(*patterns)`` is exactly equivalent to 

1295 ``any(expr.has(p) for p in patterns)``. In particular, ``False`` is 

1296 returned when the list of patterns is empty. 

1297 

1298 >>> x.has() 

1299 False 

1300 

1301 """ 

1302 return self._has(iterargs, *patterns) 

1303 

1304 def has_xfree(self, s: set[Basic]): 

1305 """Return True if self has any of the patterns in s as a 

1306 free argument, else False. This is like `Basic.has_free` 

1307 but this will only report exact argument matches. 

1308 

1309 Examples 

1310 ======== 

1311 

1312 >>> from sympy import Function 

1313 >>> from sympy.abc import x, y 

1314 >>> f = Function('f') 

1315 >>> f(x).has_xfree({f}) 

1316 False 

1317 >>> f(x).has_xfree({f(x)}) 

1318 True 

1319 >>> f(x + 1).has_xfree({x}) 

1320 True 

1321 >>> f(x + 1).has_xfree({x + 1}) 

1322 True 

1323 >>> f(x + y + 1).has_xfree({x + 1}) 

1324 False 

1325 """ 

1326 # protect O(1) containment check by requiring: 

1327 if type(s) is not set: 

1328 raise TypeError('expecting set argument') 

1329 return any(a in s for a in iterfreeargs(self)) 

1330 

1331 @cacheit 

1332 def has_free(self, *patterns): 

1333 """Return True if self has object(s) ``x`` as a free expression 

1334 else False. 

1335 

1336 Examples 

1337 ======== 

1338 

1339 >>> from sympy import Integral, Function 

1340 >>> from sympy.abc import x, y 

1341 >>> f = Function('f') 

1342 >>> g = Function('g') 

1343 >>> expr = Integral(f(x), (f(x), 1, g(y))) 

1344 >>> expr.free_symbols 

1345 {y} 

1346 >>> expr.has_free(g(y)) 

1347 True 

1348 >>> expr.has_free(*(x, f(x))) 

1349 False 

1350 

1351 This works for subexpressions and types, too: 

1352 

1353 >>> expr.has_free(g) 

1354 True 

1355 >>> (x + y + 1).has_free(y + 1) 

1356 True 

1357 """ 

1358 if not patterns: 

1359 return False 

1360 p0 = patterns[0] 

1361 if len(patterns) == 1 and iterable(p0) and not isinstance(p0, Basic): 

1362 # Basic can contain iterables (though not non-Basic, ideally) 

1363 # but don't encourage mixed passing patterns 

1364 raise TypeError(filldedent(''' 

1365 Expecting 1 or more Basic args, not a single 

1366 non-Basic iterable. Don't forget to unpack 

1367 iterables: `eq.has_free(*patterns)`''')) 

1368 # try quick test first 

1369 s = set(patterns) 

1370 rv = self.has_xfree(s) 

1371 if rv: 

1372 return rv 

1373 # now try matching through slower _has 

1374 return self._has(iterfreeargs, *patterns) 

1375 

1376 def _has(self, iterargs, *patterns): 

1377 # separate out types and unhashable objects 

1378 type_set = set() # only types 

1379 p_set = set() # hashable non-types 

1380 for p in patterns: 

1381 if isinstance(p, type) and issubclass(p, Basic): 

1382 type_set.add(p) 

1383 continue 

1384 if not isinstance(p, Basic): 

1385 try: 

1386 p = _sympify(p) 

1387 except SympifyError: 

1388 continue # Basic won't have this in it 

1389 p_set.add(p) # fails if object defines __eq__ but 

1390 # doesn't define __hash__ 

1391 types = tuple(type_set) # 

1392 for i in iterargs(self): # 

1393 if i in p_set: # <--- here, too 

1394 return True 

1395 if isinstance(i, types): 

1396 return True 

1397 

1398 # use matcher if defined, e.g. operations defines 

1399 # matcher that checks for exact subset containment, 

1400 # (x + y + 1).has(x + 1) -> True 

1401 for i in p_set - type_set: # types don't have matchers 

1402 if not hasattr(i, '_has_matcher'): 

1403 continue 

1404 match = i._has_matcher() 

1405 if any(match(arg) for arg in iterargs(self)): 

1406 return True 

1407 

1408 # no success 

1409 return False 

1410 

1411 def replace(self, query, value, map=False, simultaneous=True, exact=None): 

1412 """ 

1413 Replace matching subexpressions of ``self`` with ``value``. 

1414 

1415 If ``map = True`` then also return the mapping {old: new} where ``old`` 

1416 was a sub-expression found with query and ``new`` is the replacement 

1417 value for it. If the expression itself does not match the query, then 

1418 the returned value will be ``self.xreplace(map)`` otherwise it should 

1419 be ``self.subs(ordered(map.items()))``. 

1420 

1421 Traverses an expression tree and performs replacement of matching 

1422 subexpressions from the bottom to the top of the tree. The default 

1423 approach is to do the replacement in a simultaneous fashion so 

1424 changes made are targeted only once. If this is not desired or causes 

1425 problems, ``simultaneous`` can be set to False. 

1426 

1427 In addition, if an expression containing more than one Wild symbol 

1428 is being used to match subexpressions and the ``exact`` flag is None 

1429 it will be set to True so the match will only succeed if all non-zero 

1430 values are received for each Wild that appears in the match pattern. 

1431 Setting this to False accepts a match of 0; while setting it True 

1432 accepts all matches that have a 0 in them. See example below for 

1433 cautions. 

1434 

1435 The list of possible combinations of queries and replacement values 

1436 is listed below: 

1437 

1438 Examples 

1439 ======== 

1440 

1441 Initial setup 

1442 

1443 >>> from sympy import log, sin, cos, tan, Wild, Mul, Add 

1444 >>> from sympy.abc import x, y 

1445 >>> f = log(sin(x)) + tan(sin(x**2)) 

1446 

1447 1.1. type -> type 

1448 obj.replace(type, newtype) 

1449 

1450 When object of type ``type`` is found, replace it with the 

1451 result of passing its argument(s) to ``newtype``. 

1452 

1453 >>> f.replace(sin, cos) 

1454 log(cos(x)) + tan(cos(x**2)) 

1455 >>> sin(x).replace(sin, cos, map=True) 

1456 (cos(x), {sin(x): cos(x)}) 

1457 >>> (x*y).replace(Mul, Add) 

1458 x + y 

1459 

1460 1.2. type -> func 

1461 obj.replace(type, func) 

1462 

1463 When object of type ``type`` is found, apply ``func`` to its 

1464 argument(s). ``func`` must be written to handle the number 

1465 of arguments of ``type``. 

1466 

1467 >>> f.replace(sin, lambda arg: sin(2*arg)) 

1468 log(sin(2*x)) + tan(sin(2*x**2)) 

1469 >>> (x*y).replace(Mul, lambda *args: sin(2*Mul(*args))) 

1470 sin(2*x*y) 

1471 

1472 2.1. pattern -> expr 

1473 obj.replace(pattern(wild), expr(wild)) 

1474 

1475 Replace subexpressions matching ``pattern`` with the expression 

1476 written in terms of the Wild symbols in ``pattern``. 

1477 

1478 >>> a, b = map(Wild, 'ab') 

1479 >>> f.replace(sin(a), tan(a)) 

1480 log(tan(x)) + tan(tan(x**2)) 

1481 >>> f.replace(sin(a), tan(a/2)) 

1482 log(tan(x/2)) + tan(tan(x**2/2)) 

1483 >>> f.replace(sin(a), a) 

1484 log(x) + tan(x**2) 

1485 >>> (x*y).replace(a*x, a) 

1486 y 

1487 

1488 Matching is exact by default when more than one Wild symbol 

1489 is used: matching fails unless the match gives non-zero 

1490 values for all Wild symbols: 

1491 

1492 >>> (2*x + y).replace(a*x + b, b - a) 

1493 y - 2 

1494 >>> (2*x).replace(a*x + b, b - a) 

1495 2*x 

1496 

1497 When set to False, the results may be non-intuitive: 

1498 

1499 >>> (2*x).replace(a*x + b, b - a, exact=False) 

1500 2/x 

1501 

1502 2.2. pattern -> func 

1503 obj.replace(pattern(wild), lambda wild: expr(wild)) 

1504 

1505 All behavior is the same as in 2.1 but now a function in terms of 

1506 pattern variables is used rather than an expression: 

1507 

1508 >>> f.replace(sin(a), lambda a: sin(2*a)) 

1509 log(sin(2*x)) + tan(sin(2*x**2)) 

1510 

1511 3.1. func -> func 

1512 obj.replace(filter, func) 

1513 

1514 Replace subexpression ``e`` with ``func(e)`` if ``filter(e)`` 

1515 is True. 

1516 

1517 >>> g = 2*sin(x**3) 

1518 >>> g.replace(lambda expr: expr.is_Number, lambda expr: expr**2) 

1519 4*sin(x**9) 

1520 

1521 The expression itself is also targeted by the query but is done in 

1522 such a fashion that changes are not made twice. 

1523 

1524 >>> e = x*(x*y + 1) 

1525 >>> e.replace(lambda x: x.is_Mul, lambda x: 2*x) 

1526 2*x*(2*x*y + 1) 

1527 

1528 When matching a single symbol, `exact` will default to True, but 

1529 this may or may not be the behavior that is desired: 

1530 

1531 Here, we want `exact=False`: 

1532 

1533 >>> from sympy import Function 

1534 >>> f = Function('f') 

1535 >>> e = f(1) + f(0) 

1536 >>> q = f(a), lambda a: f(a + 1) 

1537 >>> e.replace(*q, exact=False) 

1538 f(1) + f(2) 

1539 >>> e.replace(*q, exact=True) 

1540 f(0) + f(2) 

1541 

1542 But here, the nature of matching makes selecting 

1543 the right setting tricky: 

1544 

1545 >>> e = x**(1 + y) 

1546 >>> (x**(1 + y)).replace(x**(1 + a), lambda a: x**-a, exact=False) 

1547 x 

1548 >>> (x**(1 + y)).replace(x**(1 + a), lambda a: x**-a, exact=True) 

1549 x**(-x - y + 1) 

1550 >>> (x**y).replace(x**(1 + a), lambda a: x**-a, exact=False) 

1551 x 

1552 >>> (x**y).replace(x**(1 + a), lambda a: x**-a, exact=True) 

1553 x**(1 - y) 

1554 

1555 It is probably better to use a different form of the query 

1556 that describes the target expression more precisely: 

1557 

1558 >>> (1 + x**(1 + y)).replace( 

1559 ... lambda x: x.is_Pow and x.exp.is_Add and x.exp.args[0] == 1, 

1560 ... lambda x: x.base**(1 - (x.exp - 1))) 

1561 ... 

1562 x**(1 - y) + 1 

1563 

1564 See Also 

1565 ======== 

1566 

1567 subs: substitution of subexpressions as defined by the objects 

1568 themselves. 

1569 xreplace: exact node replacement in expr tree; also capable of 

1570 using matching rules 

1571 

1572 """ 

1573 

1574 try: 

1575 query = _sympify(query) 

1576 except SympifyError: 

1577 pass 

1578 try: 

1579 value = _sympify(value) 

1580 except SympifyError: 

1581 pass 

1582 if isinstance(query, type): 

1583 _query = lambda expr: isinstance(expr, query) 

1584 

1585 if isinstance(value, type): 

1586 _value = lambda expr, result: value(*expr.args) 

1587 elif callable(value): 

1588 _value = lambda expr, result: value(*expr.args) 

1589 else: 

1590 raise TypeError( 

1591 "given a type, replace() expects another " 

1592 "type or a callable") 

1593 elif isinstance(query, Basic): 

1594 _query = lambda expr: expr.match(query) 

1595 if exact is None: 

1596 from .symbol import Wild 

1597 exact = (len(query.atoms(Wild)) > 1) 

1598 

1599 if isinstance(value, Basic): 

1600 if exact: 

1601 _value = lambda expr, result: (value.subs(result) 

1602 if all(result.values()) else expr) 

1603 else: 

1604 _value = lambda expr, result: value.subs(result) 

1605 elif callable(value): 

1606 # match dictionary keys get the trailing underscore stripped 

1607 # from them and are then passed as keywords to the callable; 

1608 # if ``exact`` is True, only accept match if there are no null 

1609 # values amongst those matched. 

1610 if exact: 

1611 _value = lambda expr, result: (value(** 

1612 {str(k)[:-1]: v for k, v in result.items()}) 

1613 if all(val for val in result.values()) else expr) 

1614 else: 

1615 _value = lambda expr, result: value(** 

1616 {str(k)[:-1]: v for k, v in result.items()}) 

1617 else: 

1618 raise TypeError( 

1619 "given an expression, replace() expects " 

1620 "another expression or a callable") 

1621 elif callable(query): 

1622 _query = query 

1623 

1624 if callable(value): 

1625 _value = lambda expr, result: value(expr) 

1626 else: 

1627 raise TypeError( 

1628 "given a callable, replace() expects " 

1629 "another callable") 

1630 else: 

1631 raise TypeError( 

1632 "first argument to replace() must be a " 

1633 "type, an expression or a callable") 

1634 

1635 def walk(rv, F): 

1636 """Apply ``F`` to args and then to result. 

1637 """ 

1638 args = getattr(rv, 'args', None) 

1639 if args is not None: 

1640 if args: 

1641 newargs = tuple([walk(a, F) for a in args]) 

1642 if args != newargs: 

1643 rv = rv.func(*newargs) 

1644 if simultaneous: 

1645 # if rv is something that was already 

1646 # matched (that was changed) then skip 

1647 # applying F again 

1648 for i, e in enumerate(args): 

1649 if rv == e and e != newargs[i]: 

1650 return rv 

1651 rv = F(rv) 

1652 return rv 

1653 

1654 mapping = {} # changes that took place 

1655 

1656 def rec_replace(expr): 

1657 result = _query(expr) 

1658 if result or result == {}: 

1659 v = _value(expr, result) 

1660 if v is not None and v != expr: 

1661 if map: 

1662 mapping[expr] = v 

1663 expr = v 

1664 return expr 

1665 

1666 rv = walk(self, rec_replace) 

1667 return (rv, mapping) if map else rv 

1668 

1669 def find(self, query, group=False): 

1670 """Find all subexpressions matching a query.""" 

1671 query = _make_find_query(query) 

1672 results = list(filter(query, _preorder_traversal(self))) 

1673 

1674 if not group: 

1675 return set(results) 

1676 else: 

1677 groups = {} 

1678 

1679 for result in results: 

1680 if result in groups: 

1681 groups[result] += 1 

1682 else: 

1683 groups[result] = 1 

1684 

1685 return groups 

1686 

1687 def count(self, query): 

1688 """Count the number of matching subexpressions.""" 

1689 query = _make_find_query(query) 

1690 return sum(bool(query(sub)) for sub in _preorder_traversal(self)) 

1691 

1692 def matches(self, expr, repl_dict=None, old=False): 

1693 """ 

1694 Helper method for match() that looks for a match between Wild symbols 

1695 in self and expressions in expr. 

1696 

1697 Examples 

1698 ======== 

1699 

1700 >>> from sympy import symbols, Wild, Basic 

1701 >>> a, b, c = symbols('a b c') 

1702 >>> x = Wild('x') 

1703 >>> Basic(a + x, x).matches(Basic(a + b, c)) is None 

1704 True 

1705 >>> Basic(a + x, x).matches(Basic(a + b + c, b + c)) 

1706 {x_: b + c} 

1707 """ 

1708 expr = sympify(expr) 

1709 if not isinstance(expr, self.__class__): 

1710 return None 

1711 

1712 if repl_dict is None: 

1713 repl_dict = {} 

1714 else: 

1715 repl_dict = repl_dict.copy() 

1716 

1717 if self == expr: 

1718 return repl_dict 

1719 

1720 if len(self.args) != len(expr.args): 

1721 return None 

1722 

1723 d = repl_dict # already a copy 

1724 for arg, other_arg in zip(self.args, expr.args): 

1725 if arg == other_arg: 

1726 continue 

1727 if arg.is_Relational: 

1728 try: 

1729 d = arg.xreplace(d).matches(other_arg, d, old=old) 

1730 except TypeError: # Should be InvalidComparisonError when introduced 

1731 d = None 

1732 else: 

1733 d = arg.xreplace(d).matches(other_arg, d, old=old) 

1734 if d is None: 

1735 return None 

1736 return d 

1737 

1738 def match(self, pattern, old=False): 

1739 """ 

1740 Pattern matching. 

1741 

1742 Wild symbols match all. 

1743 

1744 Return ``None`` when expression (self) does not match 

1745 with pattern. Otherwise return a dictionary such that:: 

1746 

1747 pattern.xreplace(self.match(pattern)) == self 

1748 

1749 Examples 

1750 ======== 

1751 

1752 >>> from sympy import Wild, Sum 

1753 >>> from sympy.abc import x, y 

1754 >>> p = Wild("p") 

1755 >>> q = Wild("q") 

1756 >>> r = Wild("r") 

1757 >>> e = (x+y)**(x+y) 

1758 >>> e.match(p**p) 

1759 {p_: x + y} 

1760 >>> e.match(p**q) 

1761 {p_: x + y, q_: x + y} 

1762 >>> e = (2*x)**2 

1763 >>> e.match(p*q**r) 

1764 {p_: 4, q_: x, r_: 2} 

1765 >>> (p*q**r).xreplace(e.match(p*q**r)) 

1766 4*x**2 

1767 

1768 Structurally bound symbols are ignored during matching: 

1769 

1770 >>> Sum(x, (x, 1, 2)).match(Sum(y, (y, 1, p))) 

1771 {p_: 2} 

1772 

1773 But they can be identified if desired: 

1774 

1775 >>> Sum(x, (x, 1, 2)).match(Sum(q, (q, 1, p))) 

1776 {p_: 2, q_: x} 

1777 

1778 The ``old`` flag will give the old-style pattern matching where 

1779 expressions and patterns are essentially solved to give the 

1780 match. Both of the following give None unless ``old=True``: 

1781 

1782 >>> (x - 2).match(p - x, old=True) 

1783 {p_: 2*x - 2} 

1784 >>> (2/x).match(p*x, old=True) 

1785 {p_: 2/x**2} 

1786 

1787 """ 

1788 pattern = sympify(pattern) 

1789 # match non-bound symbols 

1790 canonical = lambda x: x if x.is_Symbol else x.as_dummy() 

1791 m = canonical(pattern).matches(canonical(self), old=old) 

1792 if m is None: 

1793 return m 

1794 from .symbol import Wild 

1795 from .function import WildFunction 

1796 from ..tensor.tensor import WildTensor, WildTensorIndex, WildTensorHead 

1797 wild = pattern.atoms(Wild, WildFunction, WildTensor, WildTensorIndex, WildTensorHead) 

1798 # sanity check 

1799 if set(m) - wild: 

1800 raise ValueError(filldedent(''' 

1801 Some `matches` routine did not use a copy of repl_dict 

1802 and injected unexpected symbols. Report this as an 

1803 error at https://github.com/sympy/sympy/issues''')) 

1804 # now see if bound symbols were requested 

1805 bwild = wild - set(m) 

1806 if not bwild: 

1807 return m 

1808 # replace free-Wild symbols in pattern with match result 

1809 # so they will match but not be in the next match 

1810 wpat = pattern.xreplace(m) 

1811 # identify remaining bound wild 

1812 w = wpat.matches(self, old=old) 

1813 # add them to m 

1814 if w: 

1815 m.update(w) 

1816 # done 

1817 return m 

1818 

1819 def count_ops(self, visual=None): 

1820 """Wrapper for count_ops that returns the operation count.""" 

1821 from .function import count_ops 

1822 return count_ops(self, visual) 

1823 

1824 def doit(self, **hints): 

1825 """Evaluate objects that are not evaluated by default like limits, 

1826 integrals, sums and products. All objects of this kind will be 

1827 evaluated recursively, unless some species were excluded via 'hints' 

1828 or unless the 'deep' hint was set to 'False'. 

1829 

1830 >>> from sympy import Integral 

1831 >>> from sympy.abc import x 

1832 

1833 >>> 2*Integral(x, x) 

1834 2*Integral(x, x) 

1835 

1836 >>> (2*Integral(x, x)).doit() 

1837 x**2 

1838 

1839 >>> (2*Integral(x, x)).doit(deep=False) 

1840 2*Integral(x, x) 

1841 

1842 """ 

1843 if hints.get('deep', True): 

1844 terms = [term.doit(**hints) if isinstance(term, Basic) else term 

1845 for term in self.args] 

1846 return self.func(*terms) 

1847 else: 

1848 return self 

1849 

1850 def simplify(self, **kwargs): 

1851 """See the simplify function in sympy.simplify""" 

1852 from sympy.simplify.simplify import simplify 

1853 return simplify(self, **kwargs) 

1854 

1855 def refine(self, assumption=True): 

1856 """See the refine function in sympy.assumptions""" 

1857 from sympy.assumptions.refine import refine 

1858 return refine(self, assumption) 

1859 

1860 def _eval_derivative_n_times(self, s, n): 

1861 # This is the default evaluator for derivatives (as called by `diff` 

1862 # and `Derivative`), it will attempt a loop to derive the expression 

1863 # `n` times by calling the corresponding `_eval_derivative` method, 

1864 # while leaving the derivative unevaluated if `n` is symbolic. This 

1865 # method should be overridden if the object has a closed form for its 

1866 # symbolic n-th derivative. 

1867 from .numbers import Integer 

1868 if isinstance(n, (int, Integer)): 

1869 obj = self 

1870 for i in range(n): 

1871 obj2 = obj._eval_derivative(s) 

1872 if obj == obj2 or obj2 is None: 

1873 break 

1874 obj = obj2 

1875 return obj2 

1876 else: 

1877 return None 

1878 

1879 def rewrite(self, *args, deep=True, **hints): 

1880 """ 

1881 Rewrite *self* using a defined rule. 

1882 

1883 Rewriting transforms an expression to another, which is mathematically 

1884 equivalent but structurally different. For example you can rewrite 

1885 trigonometric functions as complex exponentials or combinatorial 

1886 functions as gamma function. 

1887 

1888 This method takes a *pattern* and a *rule* as positional arguments. 

1889 *pattern* is optional parameter which defines the types of expressions 

1890 that will be transformed. If it is not passed, all possible expressions 

1891 will be rewritten. *rule* defines how the expression will be rewritten. 

1892 

1893 Parameters 

1894 ========== 

1895 

1896 args : Expr 

1897 A *rule*, or *pattern* and *rule*. 

1898 - *pattern* is a type or an iterable of types. 

1899 - *rule* can be any object. 

1900 

1901 deep : bool, optional 

1902 If ``True``, subexpressions are recursively transformed. Default is 

1903 ``True``. 

1904 

1905 Examples 

1906 ======== 

1907 

1908 If *pattern* is unspecified, all possible expressions are transformed. 

1909 

1910 >>> from sympy import cos, sin, exp, I 

1911 >>> from sympy.abc import x 

1912 >>> expr = cos(x) + I*sin(x) 

1913 >>> expr.rewrite(exp) 

1914 exp(I*x) 

1915 

1916 Pattern can be a type or an iterable of types. 

1917 

1918 >>> expr.rewrite(sin, exp) 

1919 exp(I*x)/2 + cos(x) - exp(-I*x)/2 

1920 >>> expr.rewrite([cos,], exp) 

1921 exp(I*x)/2 + I*sin(x) + exp(-I*x)/2 

1922 >>> expr.rewrite([cos, sin], exp) 

1923 exp(I*x) 

1924 

1925 Rewriting behavior can be implemented by defining ``_eval_rewrite()`` 

1926 method. 

1927 

1928 >>> from sympy import Expr, sqrt, pi 

1929 >>> class MySin(Expr): 

1930 ... def _eval_rewrite(self, rule, args, **hints): 

1931 ... x, = args 

1932 ... if rule == cos: 

1933 ... return cos(pi/2 - x, evaluate=False) 

1934 ... if rule == sqrt: 

1935 ... return sqrt(1 - cos(x)**2) 

1936 >>> MySin(MySin(x)).rewrite(cos) 

1937 cos(-cos(-x + pi/2) + pi/2) 

1938 >>> MySin(x).rewrite(sqrt) 

1939 sqrt(1 - cos(x)**2) 

1940 

1941 Defining ``_eval_rewrite_as_[...]()`` method is supported for backwards 

1942 compatibility reason. This may be removed in the future and using it is 

1943 discouraged. 

1944 

1945 >>> class MySin(Expr): 

1946 ... def _eval_rewrite_as_cos(self, *args, **hints): 

1947 ... x, = args 

1948 ... return cos(pi/2 - x, evaluate=False) 

1949 >>> MySin(x).rewrite(cos) 

1950 cos(-x + pi/2) 

1951 

1952 """ 

1953 if not args: 

1954 return self 

1955 

1956 hints.update(deep=deep) 

1957 

1958 pattern = args[:-1] 

1959 rule = args[-1] 

1960 

1961 # support old design by _eval_rewrite_as_[...] method 

1962 if isinstance(rule, str): 

1963 method = "_eval_rewrite_as_%s" % rule 

1964 elif hasattr(rule, "__name__"): 

1965 # rule is class or function 

1966 clsname = rule.__name__ 

1967 method = "_eval_rewrite_as_%s" % clsname 

1968 else: 

1969 # rule is instance 

1970 clsname = rule.__class__.__name__ 

1971 method = "_eval_rewrite_as_%s" % clsname 

1972 

1973 if pattern: 

1974 if iterable(pattern[0]): 

1975 pattern = pattern[0] 

1976 pattern = tuple(p for p in pattern if self.has(p)) 

1977 if not pattern: 

1978 return self 

1979 # hereafter, empty pattern is interpreted as all pattern. 

1980 

1981 return self._rewrite(pattern, rule, method, **hints) 

1982 

1983 def _rewrite(self, pattern, rule, method, **hints): 

1984 deep = hints.pop('deep', True) 

1985 if deep: 

1986 args = [a._rewrite(pattern, rule, method, **hints) 

1987 for a in self.args] 

1988 else: 

1989 args = self.args 

1990 if not pattern or any(isinstance(self, p) for p in pattern): 

1991 meth = getattr(self, method, None) 

1992 if meth is not None: 

1993 rewritten = meth(*args, **hints) 

1994 else: 

1995 rewritten = self._eval_rewrite(rule, args, **hints) 

1996 if rewritten is not None: 

1997 return rewritten 

1998 if not args: 

1999 return self 

2000 return self.func(*args) 

2001 

2002 def _eval_rewrite(self, rule, args, **hints): 

2003 return None 

2004 

2005 _constructor_postprocessor_mapping = {} # type: ignore 

2006 

2007 @classmethod 

2008 def _exec_constructor_postprocessors(cls, obj): 

2009 # WARNING: This API is experimental. 

2010 

2011 # This is an experimental API that introduces constructor 

2012 # postprosessors for SymPy Core elements. If an argument of a SymPy 

2013 # expression has a `_constructor_postprocessor_mapping` attribute, it will 

2014 # be interpreted as a dictionary containing lists of postprocessing 

2015 # functions for matching expression node names. 

2016 

2017 clsname = obj.__class__.__name__ 

2018 postprocessors = defaultdict(list) 

2019 for i in obj.args: 

2020 try: 

2021 postprocessor_mappings = ( 

2022 Basic._constructor_postprocessor_mapping[cls].items() 

2023 for cls in type(i).mro() 

2024 if cls in Basic._constructor_postprocessor_mapping 

2025 ) 

2026 for k, v in chain.from_iterable(postprocessor_mappings): 

2027 postprocessors[k].extend([j for j in v if j not in postprocessors[k]]) 

2028 except TypeError: 

2029 pass 

2030 

2031 for f in postprocessors.get(clsname, []): 

2032 obj = f(obj) 

2033 

2034 return obj 

2035 

2036 def _sage_(self): 

2037 """ 

2038 Convert *self* to a symbolic expression of SageMath. 

2039 

2040 This version of the method is merely a placeholder. 

2041 """ 

2042 old_method = self._sage_ 

2043 from sage.interfaces.sympy import sympy_init 

2044 sympy_init() # may monkey-patch _sage_ method into self's class or superclasses 

2045 if old_method == self._sage_: 

2046 raise NotImplementedError('conversion to SageMath is not implemented') 

2047 else: 

2048 # call the freshly monkey-patched method 

2049 return self._sage_() 

2050 

2051 def could_extract_minus_sign(self): 

2052 return False # see Expr.could_extract_minus_sign 

2053 

2054 

2055# For all Basic subclasses _prepare_class_assumptions is called by 

2056# Basic.__init_subclass__ but that method is not called for Basic itself so we 

2057# call the function here instead. 

2058_prepare_class_assumptions(Basic) 

2059 

2060 

2061class Atom(Basic): 

2062 """ 

2063 A parent class for atomic things. An atom is an expression with no subexpressions. 

2064 

2065 Examples 

2066 ======== 

2067 

2068 Symbol, Number, Rational, Integer, ... 

2069 But not: Add, Mul, Pow, ... 

2070 """ 

2071 

2072 is_Atom = True 

2073 

2074 __slots__ = () 

2075 

2076 def matches(self, expr, repl_dict=None, old=False): 

2077 if self == expr: 

2078 if repl_dict is None: 

2079 return {} 

2080 return repl_dict.copy() 

2081 

2082 def xreplace(self, rule, hack2=False): 

2083 return rule.get(self, self) 

2084 

2085 def doit(self, **hints): 

2086 return self 

2087 

2088 @classmethod 

2089 def class_key(cls): 

2090 return 2, 0, cls.__name__ 

2091 

2092 @cacheit 

2093 def sort_key(self, order=None): 

2094 return self.class_key(), (1, (str(self),)), S.One.sort_key(), S.One 

2095 

2096 def _eval_simplify(self, **kwargs): 

2097 return self 

2098 

2099 @property 

2100 def _sorted_args(self): 

2101 # this is here as a safeguard against accidentally using _sorted_args 

2102 # on Atoms -- they cannot be rebuilt as atom.func(*atom._sorted_args) 

2103 # since there are no args. So the calling routine should be checking 

2104 # to see that this property is not called for Atoms. 

2105 raise AttributeError('Atoms have no args. It might be necessary' 

2106 ' to make a check for Atoms in the calling code.') 

2107 

2108 

2109def _aresame(a, b): 

2110 """Return True if a and b are structurally the same, else False. 

2111 

2112 Examples 

2113 ======== 

2114 

2115 In SymPy (as in Python) two numbers compare the same if they 

2116 have the same underlying base-2 representation even though 

2117 they may not be the same type: 

2118 

2119 >>> from sympy import S 

2120 >>> 2.0 == S(2) 

2121 True 

2122 >>> 0.5 == S.Half 

2123 True 

2124 

2125 This routine was written to provide a query for such cases that 

2126 would give false when the types do not match: 

2127 

2128 >>> from sympy.core.basic import _aresame 

2129 >>> _aresame(S(2.0), S(2)) 

2130 False 

2131 

2132 """ 

2133 from .numbers import Number 

2134 from .function import AppliedUndef, UndefinedFunction as UndefFunc 

2135 if isinstance(a, Number) and isinstance(b, Number): 

2136 return a == b and a.__class__ == b.__class__ 

2137 for i, j in zip_longest(_preorder_traversal(a), _preorder_traversal(b)): 

2138 if i != j or type(i) != type(j): 

2139 if ((isinstance(i, UndefFunc) and isinstance(j, UndefFunc)) or 

2140 (isinstance(i, AppliedUndef) and isinstance(j, AppliedUndef))): 

2141 if i.class_key() != j.class_key(): 

2142 return False 

2143 else: 

2144 return False 

2145 return True 

2146 

2147 

2148def _ne(a, b): 

2149 # use this as a second test after `a != b` if you want to make 

2150 # sure that things are truly equal, e.g. 

2151 # a, b = 0.5, S.Half 

2152 # a !=b or _ne(a, b) -> True 

2153 from .numbers import Number 

2154 # 0.5 == S.Half 

2155 if isinstance(a, Number) and isinstance(b, Number): 

2156 return a.__class__ != b.__class__ 

2157 

2158 

2159def _atomic(e, recursive=False): 

2160 """Return atom-like quantities as far as substitution is 

2161 concerned: Derivatives, Functions and Symbols. Do not 

2162 return any 'atoms' that are inside such quantities unless 

2163 they also appear outside, too, unless `recursive` is True. 

2164 

2165 Examples 

2166 ======== 

2167 

2168 >>> from sympy import Derivative, Function, cos 

2169 >>> from sympy.abc import x, y 

2170 >>> from sympy.core.basic import _atomic 

2171 >>> f = Function('f') 

2172 >>> _atomic(x + y) 

2173 {x, y} 

2174 >>> _atomic(x + f(y)) 

2175 {x, f(y)} 

2176 >>> _atomic(Derivative(f(x), x) + cos(x) + y) 

2177 {y, cos(x), Derivative(f(x), x)} 

2178 

2179 """ 

2180 pot = _preorder_traversal(e) 

2181 seen = set() 

2182 if isinstance(e, Basic): 

2183 free = getattr(e, "free_symbols", None) 

2184 if free is None: 

2185 return {e} 

2186 else: 

2187 return set() 

2188 from .symbol import Symbol 

2189 from .function import Derivative, Function 

2190 atoms = set() 

2191 for p in pot: 

2192 if p in seen: 

2193 pot.skip() 

2194 continue 

2195 seen.add(p) 

2196 if isinstance(p, Symbol) and p in free: 

2197 atoms.add(p) 

2198 elif isinstance(p, (Derivative, Function)): 

2199 if not recursive: 

2200 pot.skip() 

2201 atoms.add(p) 

2202 return atoms 

2203 

2204 

2205def _make_find_query(query): 

2206 """Convert the argument of Basic.find() into a callable""" 

2207 try: 

2208 query = _sympify(query) 

2209 except SympifyError: 

2210 pass 

2211 if isinstance(query, type): 

2212 return lambda expr: isinstance(expr, query) 

2213 elif isinstance(query, Basic): 

2214 return lambda expr: expr.match(query) is not None 

2215 return query 

2216 

2217# Delayed to avoid cyclic import 

2218from .singleton import S 

2219from .traversal import (preorder_traversal as _preorder_traversal, 

2220 iterargs, iterfreeargs) 

2221 

2222preorder_traversal = deprecated( 

2223 """ 

2224 Using preorder_traversal from the sympy.core.basic submodule is 

2225 deprecated. 

2226 

2227 Instead, use preorder_traversal from the top-level sympy namespace, like 

2228 

2229 sympy.preorder_traversal 

2230 """, 

2231 deprecated_since_version="1.10", 

2232 active_deprecations_target="deprecated-traversal-functions-moved", 

2233)(_preorder_traversal)