Coverage for /usr/lib/python3/dist-packages/sympy/core/relational.py: 35%

550 statements  

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

1from __future__ import annotations 

2 

3from .basic import Atom, Basic 

4from .sorting import ordered 

5from .evalf import EvalfMixin 

6from .function import AppliedUndef 

7from .singleton import S 

8from .sympify import _sympify, SympifyError 

9from .parameters import global_parameters 

10from .logic import fuzzy_bool, fuzzy_xor, fuzzy_and, fuzzy_not 

11from sympy.logic.boolalg import Boolean, BooleanAtom 

12from sympy.utilities.iterables import sift 

13from sympy.utilities.misc import filldedent 

14 

15__all__ = ( 

16 'Rel', 'Eq', 'Ne', 'Lt', 'Le', 'Gt', 'Ge', 

17 'Relational', 'Equality', 'Unequality', 'StrictLessThan', 'LessThan', 

18 'StrictGreaterThan', 'GreaterThan', 

19) 

20 

21from .expr import Expr 

22from sympy.multipledispatch import dispatch 

23from .containers import Tuple 

24from .symbol import Symbol 

25 

26 

27def _nontrivBool(side): 

28 return isinstance(side, Boolean) and \ 

29 not isinstance(side, Atom) 

30 

31 

32# Note, see issue 4986. Ideally, we wouldn't want to subclass both Boolean 

33# and Expr. 

34# from .. import Expr 

35 

36 

37def _canonical(cond): 

38 # return a condition in which all relationals are canonical 

39 reps = {r: r.canonical for r in cond.atoms(Relational)} 

40 return cond.xreplace(reps) 

41 # XXX: AttributeError was being caught here but it wasn't triggered by any of 

42 # the tests so I've removed it... 

43 

44 

45def _canonical_coeff(rel): 

46 # return -2*x + 1 < 0 as x > 1/2 

47 # XXX make this part of Relational.canonical? 

48 rel = rel.canonical 

49 if not rel.is_Relational or rel.rhs.is_Boolean: 

50 return rel # Eq(x, True) 

51 b, l = rel.lhs.as_coeff_Add(rational=True) 

52 m, lhs = l.as_coeff_Mul(rational=True) 

53 rhs = (rel.rhs - b)/m 

54 if m < 0: 

55 return rel.reversed.func(lhs, rhs) 

56 return rel.func(lhs, rhs) 

57 

58 

59class Relational(Boolean, EvalfMixin): 

60 """Base class for all relation types. 

61 

62 Explanation 

63 =========== 

64 

65 Subclasses of Relational should generally be instantiated directly, but 

66 Relational can be instantiated with a valid ``rop`` value to dispatch to 

67 the appropriate subclass. 

68 

69 Parameters 

70 ========== 

71 

72 rop : str or None 

73 Indicates what subclass to instantiate. Valid values can be found 

74 in the keys of Relational.ValidRelationOperator. 

75 

76 Examples 

77 ======== 

78 

79 >>> from sympy import Rel 

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

81 >>> Rel(y, x + x**2, '==') 

82 Eq(y, x**2 + x) 

83 

84 A relation's type can be defined upon creation using ``rop``. 

85 The relation type of an existing expression can be obtained 

86 using its ``rel_op`` property. 

87 Here is a table of all the relation types, along with their 

88 ``rop`` and ``rel_op`` values: 

89 

90 +---------------------+----------------------------+------------+ 

91 |Relation |``rop`` |``rel_op`` | 

92 +=====================+============================+============+ 

93 |``Equality`` |``==`` or ``eq`` or ``None``|``==`` | 

94 +---------------------+----------------------------+------------+ 

95 |``Unequality`` |``!=`` or ``ne`` |``!=`` | 

96 +---------------------+----------------------------+------------+ 

97 |``GreaterThan`` |``>=`` or ``ge`` |``>=`` | 

98 +---------------------+----------------------------+------------+ 

99 |``LessThan`` |``<=`` or ``le`` |``<=`` | 

100 +---------------------+----------------------------+------------+ 

101 |``StrictGreaterThan``|``>`` or ``gt`` |``>`` | 

102 +---------------------+----------------------------+------------+ 

103 |``StrictLessThan`` |``<`` or ``lt`` |``<`` | 

104 +---------------------+----------------------------+------------+ 

105 

106 For example, setting ``rop`` to ``==`` produces an 

107 ``Equality`` relation, ``Eq()``. 

108 So does setting ``rop`` to ``eq``, or leaving ``rop`` unspecified. 

109 That is, the first three ``Rel()`` below all produce the same result. 

110 Using a ``rop`` from a different row in the table produces a 

111 different relation type. 

112 For example, the fourth ``Rel()`` below using ``lt`` for ``rop`` 

113 produces a ``StrictLessThan`` inequality: 

114 

115 >>> from sympy import Rel 

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

117 >>> Rel(y, x + x**2, '==') 

118 Eq(y, x**2 + x) 

119 >>> Rel(y, x + x**2, 'eq') 

120 Eq(y, x**2 + x) 

121 >>> Rel(y, x + x**2) 

122 Eq(y, x**2 + x) 

123 >>> Rel(y, x + x**2, 'lt') 

124 y < x**2 + x 

125 

126 To obtain the relation type of an existing expression, 

127 get its ``rel_op`` property. 

128 For example, ``rel_op`` is ``==`` for the ``Equality`` relation above, 

129 and ``<`` for the strict less than inequality above: 

130 

131 >>> from sympy import Rel 

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

133 >>> my_equality = Rel(y, x + x**2, '==') 

134 >>> my_equality.rel_op 

135 '==' 

136 >>> my_inequality = Rel(y, x + x**2, 'lt') 

137 >>> my_inequality.rel_op 

138 '<' 

139 

140 """ 

141 __slots__ = () 

142 

143 ValidRelationOperator: dict[str | None, type[Relational]] = {} 

144 

145 is_Relational = True 

146 

147 # ValidRelationOperator - Defined below, because the necessary classes 

148 # have not yet been defined 

149 

150 def __new__(cls, lhs, rhs, rop=None, **assumptions): 

151 # If called by a subclass, do nothing special and pass on to Basic. 

152 if cls is not Relational: 

153 return Basic.__new__(cls, lhs, rhs, **assumptions) 

154 

155 # XXX: Why do this? There should be a separate function to make a 

156 # particular subclass of Relational from a string. 

157 # 

158 # If called directly with an operator, look up the subclass 

159 # corresponding to that operator and delegate to it 

160 cls = cls.ValidRelationOperator.get(rop, None) 

161 if cls is None: 

162 raise ValueError("Invalid relational operator symbol: %r" % rop) 

163 

164 if not issubclass(cls, (Eq, Ne)): 

165 # validate that Booleans are not being used in a relational 

166 # other than Eq/Ne; 

167 # Note: Symbol is a subclass of Boolean but is considered 

168 # acceptable here. 

169 if any(map(_nontrivBool, (lhs, rhs))): 

170 raise TypeError(filldedent(''' 

171 A Boolean argument can only be used in 

172 Eq and Ne; all other relationals expect 

173 real expressions. 

174 ''')) 

175 

176 return cls(lhs, rhs, **assumptions) 

177 

178 @property 

179 def lhs(self): 

180 """The left-hand side of the relation.""" 

181 return self._args[0] 

182 

183 @property 

184 def rhs(self): 

185 """The right-hand side of the relation.""" 

186 return self._args[1] 

187 

188 @property 

189 def reversed(self): 

190 """Return the relationship with sides reversed. 

191 

192 Examples 

193 ======== 

194 

195 >>> from sympy import Eq 

196 >>> from sympy.abc import x 

197 >>> Eq(x, 1) 

198 Eq(x, 1) 

199 >>> _.reversed 

200 Eq(1, x) 

201 >>> x < 1 

202 x < 1 

203 >>> _.reversed 

204 1 > x 

205 """ 

206 ops = {Eq: Eq, Gt: Lt, Ge: Le, Lt: Gt, Le: Ge, Ne: Ne} 

207 a, b = self.args 

208 return Relational.__new__(ops.get(self.func, self.func), b, a) 

209 

210 @property 

211 def reversedsign(self): 

212 """Return the relationship with signs reversed. 

213 

214 Examples 

215 ======== 

216 

217 >>> from sympy import Eq 

218 >>> from sympy.abc import x 

219 >>> Eq(x, 1) 

220 Eq(x, 1) 

221 >>> _.reversedsign 

222 Eq(-x, -1) 

223 >>> x < 1 

224 x < 1 

225 >>> _.reversedsign 

226 -x > -1 

227 """ 

228 a, b = self.args 

229 if not (isinstance(a, BooleanAtom) or isinstance(b, BooleanAtom)): 

230 ops = {Eq: Eq, Gt: Lt, Ge: Le, Lt: Gt, Le: Ge, Ne: Ne} 

231 return Relational.__new__(ops.get(self.func, self.func), -a, -b) 

232 else: 

233 return self 

234 

235 @property 

236 def negated(self): 

237 """Return the negated relationship. 

238 

239 Examples 

240 ======== 

241 

242 >>> from sympy import Eq 

243 >>> from sympy.abc import x 

244 >>> Eq(x, 1) 

245 Eq(x, 1) 

246 >>> _.negated 

247 Ne(x, 1) 

248 >>> x < 1 

249 x < 1 

250 >>> _.negated 

251 x >= 1 

252 

253 Notes 

254 ===== 

255 

256 This works more or less identical to ``~``/``Not``. The difference is 

257 that ``negated`` returns the relationship even if ``evaluate=False``. 

258 Hence, this is useful in code when checking for e.g. negated relations 

259 to existing ones as it will not be affected by the `evaluate` flag. 

260 

261 """ 

262 ops = {Eq: Ne, Ge: Lt, Gt: Le, Le: Gt, Lt: Ge, Ne: Eq} 

263 # If there ever will be new Relational subclasses, the following line 

264 # will work until it is properly sorted out 

265 # return ops.get(self.func, lambda a, b, evaluate=False: ~(self.func(a, 

266 # b, evaluate=evaluate)))(*self.args, evaluate=False) 

267 return Relational.__new__(ops.get(self.func), *self.args) 

268 

269 @property 

270 def weak(self): 

271 """return the non-strict version of the inequality or self 

272 

273 EXAMPLES 

274 ======== 

275 

276 >>> from sympy.abc import x 

277 >>> (x < 1).weak 

278 x <= 1 

279 >>> _.weak 

280 x <= 1 

281 """ 

282 return self 

283 

284 @property 

285 def strict(self): 

286 """return the strict version of the inequality or self 

287 

288 EXAMPLES 

289 ======== 

290 

291 >>> from sympy.abc import x 

292 >>> (x <= 1).strict 

293 x < 1 

294 >>> _.strict 

295 x < 1 

296 """ 

297 return self 

298 

299 def _eval_evalf(self, prec): 

300 return self.func(*[s._evalf(prec) for s in self.args]) 

301 

302 @property 

303 def canonical(self): 

304 """Return a canonical form of the relational by putting a 

305 number on the rhs, canonically removing a sign or else 

306 ordering the args canonically. No other simplification is 

307 attempted. 

308 

309 Examples 

310 ======== 

311 

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

313 >>> x < 2 

314 x < 2 

315 >>> _.reversed.canonical 

316 x < 2 

317 >>> (-y < x).canonical 

318 x > -y 

319 >>> (-y > x).canonical 

320 x < -y 

321 >>> (-y < -x).canonical 

322 x < y 

323 

324 The canonicalization is recursively applied: 

325 

326 >>> from sympy import Eq 

327 >>> Eq(x < y, y > x).canonical 

328 True 

329 """ 

330 args = tuple([i.canonical if isinstance(i, Relational) else i for i in self.args]) 

331 if args != self.args: 

332 r = self.func(*args) 

333 if not isinstance(r, Relational): 

334 return r 

335 else: 

336 r = self 

337 if r.rhs.is_number: 

338 if r.rhs.is_Number and r.lhs.is_Number and r.lhs > r.rhs: 

339 r = r.reversed 

340 elif r.lhs.is_number: 

341 r = r.reversed 

342 elif tuple(ordered(args)) != args: 

343 r = r.reversed 

344 

345 LHS_CEMS = getattr(r.lhs, 'could_extract_minus_sign', None) 

346 RHS_CEMS = getattr(r.rhs, 'could_extract_minus_sign', None) 

347 

348 if isinstance(r.lhs, BooleanAtom) or isinstance(r.rhs, BooleanAtom): 

349 return r 

350 

351 # Check if first value has negative sign 

352 if LHS_CEMS and LHS_CEMS(): 

353 return r.reversedsign 

354 elif not r.rhs.is_number and RHS_CEMS and RHS_CEMS(): 

355 # Right hand side has a minus, but not lhs. 

356 # How does the expression with reversed signs behave? 

357 # This is so that expressions of the type 

358 # Eq(x, -y) and Eq(-x, y) 

359 # have the same canonical representation 

360 expr1, _ = ordered([r.lhs, -r.rhs]) 

361 if expr1 != r.lhs: 

362 return r.reversed.reversedsign 

363 

364 return r 

365 

366 def equals(self, other, failing_expression=False): 

367 """Return True if the sides of the relationship are mathematically 

368 identical and the type of relationship is the same. 

369 If failing_expression is True, return the expression whose truth value 

370 was unknown.""" 

371 if isinstance(other, Relational): 

372 if other in (self, self.reversed): 

373 return True 

374 a, b = self, other 

375 if a.func in (Eq, Ne) or b.func in (Eq, Ne): 

376 if a.func != b.func: 

377 return False 

378 left, right = [i.equals(j, 

379 failing_expression=failing_expression) 

380 for i, j in zip(a.args, b.args)] 

381 if left is True: 

382 return right 

383 if right is True: 

384 return left 

385 lr, rl = [i.equals(j, failing_expression=failing_expression) 

386 for i, j in zip(a.args, b.reversed.args)] 

387 if lr is True: 

388 return rl 

389 if rl is True: 

390 return lr 

391 e = (left, right, lr, rl) 

392 if all(i is False for i in e): 

393 return False 

394 for i in e: 

395 if i not in (True, False): 

396 return i 

397 else: 

398 if b.func != a.func: 

399 b = b.reversed 

400 if a.func != b.func: 

401 return False 

402 left = a.lhs.equals(b.lhs, 

403 failing_expression=failing_expression) 

404 if left is False: 

405 return False 

406 right = a.rhs.equals(b.rhs, 

407 failing_expression=failing_expression) 

408 if right is False: 

409 return False 

410 if left is True: 

411 return right 

412 return left 

413 

414 def _eval_simplify(self, **kwargs): 

415 from .add import Add 

416 from .expr import Expr 

417 r = self 

418 r = r.func(*[i.simplify(**kwargs) for i in r.args]) 

419 if r.is_Relational: 

420 if not isinstance(r.lhs, Expr) or not isinstance(r.rhs, Expr): 

421 return r 

422 dif = r.lhs - r.rhs 

423 # replace dif with a valid Number that will 

424 # allow a definitive comparison with 0 

425 v = None 

426 if dif.is_comparable: 

427 v = dif.n(2) 

428 elif dif.equals(0): # XXX this is expensive 

429 v = S.Zero 

430 if v is not None: 

431 r = r.func._eval_relation(v, S.Zero) 

432 r = r.canonical 

433 # If there is only one symbol in the expression, 

434 # try to write it on a simplified form 

435 free = list(filter(lambda x: x.is_real is not False, r.free_symbols)) 

436 if len(free) == 1: 

437 try: 

438 from sympy.solvers.solveset import linear_coeffs 

439 x = free.pop() 

440 dif = r.lhs - r.rhs 

441 m, b = linear_coeffs(dif, x) 

442 if m.is_zero is False: 

443 if m.is_negative: 

444 # Dividing with a negative number, so change order of arguments 

445 # canonical will put the symbol back on the lhs later 

446 r = r.func(-b / m, x) 

447 else: 

448 r = r.func(x, -b / m) 

449 else: 

450 r = r.func(b, S.Zero) 

451 except ValueError: 

452 # maybe not a linear function, try polynomial 

453 from sympy.polys.polyerrors import PolynomialError 

454 from sympy.polys.polytools import gcd, Poly, poly 

455 try: 

456 p = poly(dif, x) 

457 c = p.all_coeffs() 

458 constant = c[-1] 

459 c[-1] = 0 

460 scale = gcd(c) 

461 c = [ctmp / scale for ctmp in c] 

462 r = r.func(Poly.from_list(c, x).as_expr(), -constant / scale) 

463 except PolynomialError: 

464 pass 

465 elif len(free) >= 2: 

466 try: 

467 from sympy.solvers.solveset import linear_coeffs 

468 from sympy.polys.polytools import gcd 

469 free = list(ordered(free)) 

470 dif = r.lhs - r.rhs 

471 m = linear_coeffs(dif, *free) 

472 constant = m[-1] 

473 del m[-1] 

474 scale = gcd(m) 

475 m = [mtmp / scale for mtmp in m] 

476 nzm = list(filter(lambda f: f[0] != 0, list(zip(m, free)))) 

477 if scale.is_zero is False: 

478 if constant != 0: 

479 # lhs: expression, rhs: constant 

480 newexpr = Add(*[i * j for i, j in nzm]) 

481 r = r.func(newexpr, -constant / scale) 

482 else: 

483 # keep first term on lhs 

484 lhsterm = nzm[0][0] * nzm[0][1] 

485 del nzm[0] 

486 newexpr = Add(*[i * j for i, j in nzm]) 

487 r = r.func(lhsterm, -newexpr) 

488 

489 else: 

490 r = r.func(constant, S.Zero) 

491 except ValueError: 

492 pass 

493 # Did we get a simplified result? 

494 r = r.canonical 

495 measure = kwargs['measure'] 

496 if measure(r) < kwargs['ratio'] * measure(self): 

497 return r 

498 else: 

499 return self 

500 

501 def _eval_trigsimp(self, **opts): 

502 from sympy.simplify.trigsimp import trigsimp 

503 return self.func(trigsimp(self.lhs, **opts), trigsimp(self.rhs, **opts)) 

504 

505 def expand(self, **kwargs): 

506 args = (arg.expand(**kwargs) for arg in self.args) 

507 return self.func(*args) 

508 

509 def __bool__(self): 

510 raise TypeError("cannot determine truth value of Relational") 

511 

512 def _eval_as_set(self): 

513 # self is univariate and periodicity(self, x) in (0, None) 

514 from sympy.solvers.inequalities import solve_univariate_inequality 

515 from sympy.sets.conditionset import ConditionSet 

516 syms = self.free_symbols 

517 assert len(syms) == 1 

518 x = syms.pop() 

519 try: 

520 xset = solve_univariate_inequality(self, x, relational=False) 

521 except NotImplementedError: 

522 # solve_univariate_inequality raises NotImplementedError for 

523 # unsolvable equations/inequalities. 

524 xset = ConditionSet(x, self, S.Reals) 

525 return xset 

526 

527 @property 

528 def binary_symbols(self): 

529 # override where necessary 

530 return set() 

531 

532 

533Rel = Relational 

534 

535 

536class Equality(Relational): 

537 """ 

538 An equal relation between two objects. 

539 

540 Explanation 

541 =========== 

542 

543 Represents that two objects are equal. If they can be easily shown 

544 to be definitively equal (or unequal), this will reduce to True (or 

545 False). Otherwise, the relation is maintained as an unevaluated 

546 Equality object. Use the ``simplify`` function on this object for 

547 more nontrivial evaluation of the equality relation. 

548 

549 As usual, the keyword argument ``evaluate=False`` can be used to 

550 prevent any evaluation. 

551 

552 Examples 

553 ======== 

554 

555 >>> from sympy import Eq, simplify, exp, cos 

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

557 >>> Eq(y, x + x**2) 

558 Eq(y, x**2 + x) 

559 >>> Eq(2, 5) 

560 False 

561 >>> Eq(2, 5, evaluate=False) 

562 Eq(2, 5) 

563 >>> _.doit() 

564 False 

565 >>> Eq(exp(x), exp(x).rewrite(cos)) 

566 Eq(exp(x), sinh(x) + cosh(x)) 

567 >>> simplify(_) 

568 True 

569 

570 See Also 

571 ======== 

572 

573 sympy.logic.boolalg.Equivalent : for representing equality between two 

574 boolean expressions 

575 

576 Notes 

577 ===== 

578 

579 Python treats 1 and True (and 0 and False) as being equal; SymPy 

580 does not. And integer will always compare as unequal to a Boolean: 

581 

582 >>> Eq(True, 1), True == 1 

583 (False, True) 

584 

585 This class is not the same as the == operator. The == operator tests 

586 for exact structural equality between two expressions; this class 

587 compares expressions mathematically. 

588 

589 If either object defines an ``_eval_Eq`` method, it can be used in place of 

590 the default algorithm. If ``lhs._eval_Eq(rhs)`` or ``rhs._eval_Eq(lhs)`` 

591 returns anything other than None, that return value will be substituted for 

592 the Equality. If None is returned by ``_eval_Eq``, an Equality object will 

593 be created as usual. 

594 

595 Since this object is already an expression, it does not respond to 

596 the method ``as_expr`` if one tries to create `x - y` from ``Eq(x, y)``. 

597 This can be done with the ``rewrite(Add)`` method. 

598 

599 .. deprecated:: 1.5 

600 

601 ``Eq(expr)`` with a single argument is a shorthand for ``Eq(expr, 0)``, 

602 but this behavior is deprecated and will be removed in a future version 

603 of SymPy. 

604 

605 """ 

606 rel_op = '==' 

607 

608 __slots__ = () 

609 

610 is_Equality = True 

611 

612 def __new__(cls, lhs, rhs, **options): 

613 evaluate = options.pop('evaluate', global_parameters.evaluate) 

614 lhs = _sympify(lhs) 

615 rhs = _sympify(rhs) 

616 if evaluate: 

617 val = is_eq(lhs, rhs) 

618 if val is None: 

619 return cls(lhs, rhs, evaluate=False) 

620 else: 

621 return _sympify(val) 

622 

623 return Relational.__new__(cls, lhs, rhs) 

624 

625 @classmethod 

626 def _eval_relation(cls, lhs, rhs): 

627 return _sympify(lhs == rhs) 

628 

629 def _eval_rewrite_as_Add(self, *args, **kwargs): 

630 """ 

631 return Eq(L, R) as L - R. To control the evaluation of 

632 the result set pass `evaluate=True` to give L - R; 

633 if `evaluate=None` then terms in L and R will not cancel 

634 but they will be listed in canonical order; otherwise 

635 non-canonical args will be returned. If one side is 0, the 

636 non-zero side will be returned. 

637 

638 Examples 

639 ======== 

640 

641 >>> from sympy import Eq, Add 

642 >>> from sympy.abc import b, x 

643 >>> eq = Eq(x + b, x - b) 

644 >>> eq.rewrite(Add) 

645 2*b 

646 >>> eq.rewrite(Add, evaluate=None).args 

647 (b, b, x, -x) 

648 >>> eq.rewrite(Add, evaluate=False).args 

649 (b, x, b, -x) 

650 """ 

651 from .add import _unevaluated_Add, Add 

652 L, R = args 

653 if L == 0: 

654 return R 

655 if R == 0: 

656 return L 

657 evaluate = kwargs.get('evaluate', True) 

658 if evaluate: 

659 # allow cancellation of args 

660 return L - R 

661 args = Add.make_args(L) + Add.make_args(-R) 

662 if evaluate is None: 

663 # no cancellation, but canonical 

664 return _unevaluated_Add(*args) 

665 # no cancellation, not canonical 

666 return Add._from_args(args) 

667 

668 @property 

669 def binary_symbols(self): 

670 if S.true in self.args or S.false in self.args: 

671 if self.lhs.is_Symbol: 

672 return {self.lhs} 

673 elif self.rhs.is_Symbol: 

674 return {self.rhs} 

675 return set() 

676 

677 def _eval_simplify(self, **kwargs): 

678 # standard simplify 

679 e = super()._eval_simplify(**kwargs) 

680 if not isinstance(e, Equality): 

681 return e 

682 from .expr import Expr 

683 if not isinstance(e.lhs, Expr) or not isinstance(e.rhs, Expr): 

684 return e 

685 free = self.free_symbols 

686 if len(free) == 1: 

687 try: 

688 from .add import Add 

689 from sympy.solvers.solveset import linear_coeffs 

690 x = free.pop() 

691 m, b = linear_coeffs( 

692 e.rewrite(Add, evaluate=False), x) 

693 if m.is_zero is False: 

694 enew = e.func(x, -b / m) 

695 else: 

696 enew = e.func(m * x, -b) 

697 measure = kwargs['measure'] 

698 if measure(enew) <= kwargs['ratio'] * measure(e): 

699 e = enew 

700 except ValueError: 

701 pass 

702 return e.canonical 

703 

704 def integrate(self, *args, **kwargs): 

705 """See the integrate function in sympy.integrals""" 

706 from sympy.integrals.integrals import integrate 

707 return integrate(self, *args, **kwargs) 

708 

709 def as_poly(self, *gens, **kwargs): 

710 '''Returns lhs-rhs as a Poly 

711 

712 Examples 

713 ======== 

714 

715 >>> from sympy import Eq 

716 >>> from sympy.abc import x 

717 >>> Eq(x**2, 1).as_poly(x) 

718 Poly(x**2 - 1, x, domain='ZZ') 

719 ''' 

720 return (self.lhs - self.rhs).as_poly(*gens, **kwargs) 

721 

722 

723Eq = Equality 

724 

725 

726class Unequality(Relational): 

727 """An unequal relation between two objects. 

728 

729 Explanation 

730 =========== 

731 

732 Represents that two objects are not equal. If they can be shown to be 

733 definitively equal, this will reduce to False; if definitively unequal, 

734 this will reduce to True. Otherwise, the relation is maintained as an 

735 Unequality object. 

736 

737 Examples 

738 ======== 

739 

740 >>> from sympy import Ne 

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

742 >>> Ne(y, x+x**2) 

743 Ne(y, x**2 + x) 

744 

745 See Also 

746 ======== 

747 Equality 

748 

749 Notes 

750 ===== 

751 This class is not the same as the != operator. The != operator tests 

752 for exact structural equality between two expressions; this class 

753 compares expressions mathematically. 

754 

755 This class is effectively the inverse of Equality. As such, it uses the 

756 same algorithms, including any available `_eval_Eq` methods. 

757 

758 """ 

759 rel_op = '!=' 

760 

761 __slots__ = () 

762 

763 def __new__(cls, lhs, rhs, **options): 

764 lhs = _sympify(lhs) 

765 rhs = _sympify(rhs) 

766 evaluate = options.pop('evaluate', global_parameters.evaluate) 

767 if evaluate: 

768 val = is_neq(lhs, rhs) 

769 if val is None: 

770 return cls(lhs, rhs, evaluate=False) 

771 else: 

772 return _sympify(val) 

773 

774 return Relational.__new__(cls, lhs, rhs, **options) 

775 

776 @classmethod 

777 def _eval_relation(cls, lhs, rhs): 

778 return _sympify(lhs != rhs) 

779 

780 @property 

781 def binary_symbols(self): 

782 if S.true in self.args or S.false in self.args: 

783 if self.lhs.is_Symbol: 

784 return {self.lhs} 

785 elif self.rhs.is_Symbol: 

786 return {self.rhs} 

787 return set() 

788 

789 def _eval_simplify(self, **kwargs): 

790 # simplify as an equality 

791 eq = Equality(*self.args)._eval_simplify(**kwargs) 

792 if isinstance(eq, Equality): 

793 # send back Ne with the new args 

794 return self.func(*eq.args) 

795 return eq.negated # result of Ne is the negated Eq 

796 

797 

798Ne = Unequality 

799 

800 

801class _Inequality(Relational): 

802 """Internal base class for all *Than types. 

803 

804 Each subclass must implement _eval_relation to provide the method for 

805 comparing two real numbers. 

806 

807 """ 

808 __slots__ = () 

809 

810 def __new__(cls, lhs, rhs, **options): 

811 

812 try: 

813 lhs = _sympify(lhs) 

814 rhs = _sympify(rhs) 

815 except SympifyError: 

816 return NotImplemented 

817 

818 evaluate = options.pop('evaluate', global_parameters.evaluate) 

819 if evaluate: 

820 for me in (lhs, rhs): 

821 if me.is_extended_real is False: 

822 raise TypeError("Invalid comparison of non-real %s" % me) 

823 if me is S.NaN: 

824 raise TypeError("Invalid NaN comparison") 

825 # First we invoke the appropriate inequality method of `lhs` 

826 # (e.g., `lhs.__lt__`). That method will try to reduce to 

827 # boolean or raise an exception. It may keep calling 

828 # superclasses until it reaches `Expr` (e.g., `Expr.__lt__`). 

829 # In some cases, `Expr` will just invoke us again (if neither it 

830 # nor a subclass was able to reduce to boolean or raise an 

831 # exception). In that case, it must call us with 

832 # `evaluate=False` to prevent infinite recursion. 

833 return cls._eval_relation(lhs, rhs, **options) 

834 

835 # make a "non-evaluated" Expr for the inequality 

836 return Relational.__new__(cls, lhs, rhs, **options) 

837 

838 @classmethod 

839 def _eval_relation(cls, lhs, rhs, **options): 

840 val = cls._eval_fuzzy_relation(lhs, rhs) 

841 if val is None: 

842 return cls(lhs, rhs, evaluate=False) 

843 else: 

844 return _sympify(val) 

845 

846 

847class _Greater(_Inequality): 

848 """Not intended for general use 

849 

850 _Greater is only used so that GreaterThan and StrictGreaterThan may 

851 subclass it for the .gts and .lts properties. 

852 

853 """ 

854 __slots__ = () 

855 

856 @property 

857 def gts(self): 

858 return self._args[0] 

859 

860 @property 

861 def lts(self): 

862 return self._args[1] 

863 

864 

865class _Less(_Inequality): 

866 """Not intended for general use. 

867 

868 _Less is only used so that LessThan and StrictLessThan may subclass it for 

869 the .gts and .lts properties. 

870 

871 """ 

872 __slots__ = () 

873 

874 @property 

875 def gts(self): 

876 return self._args[1] 

877 

878 @property 

879 def lts(self): 

880 return self._args[0] 

881 

882 

883class GreaterThan(_Greater): 

884 r"""Class representations of inequalities. 

885 

886 Explanation 

887 =========== 

888 

889 The ``*Than`` classes represent inequal relationships, where the left-hand 

890 side is generally bigger or smaller than the right-hand side. For example, 

891 the GreaterThan class represents an inequal relationship where the 

892 left-hand side is at least as big as the right side, if not bigger. In 

893 mathematical notation: 

894 

895 lhs $\ge$ rhs 

896 

897 In total, there are four ``*Than`` classes, to represent the four 

898 inequalities: 

899 

900 +-----------------+--------+ 

901 |Class Name | Symbol | 

902 +=================+========+ 

903 |GreaterThan | ``>=`` | 

904 +-----------------+--------+ 

905 |LessThan | ``<=`` | 

906 +-----------------+--------+ 

907 |StrictGreaterThan| ``>`` | 

908 +-----------------+--------+ 

909 |StrictLessThan | ``<`` | 

910 +-----------------+--------+ 

911 

912 All classes take two arguments, lhs and rhs. 

913 

914 +----------------------------+-----------------+ 

915 |Signature Example | Math Equivalent | 

916 +============================+=================+ 

917 |GreaterThan(lhs, rhs) | lhs $\ge$ rhs | 

918 +----------------------------+-----------------+ 

919 |LessThan(lhs, rhs) | lhs $\le$ rhs | 

920 +----------------------------+-----------------+ 

921 |StrictGreaterThan(lhs, rhs) | lhs $>$ rhs | 

922 +----------------------------+-----------------+ 

923 |StrictLessThan(lhs, rhs) | lhs $<$ rhs | 

924 +----------------------------+-----------------+ 

925 

926 In addition to the normal .lhs and .rhs of Relations, ``*Than`` inequality 

927 objects also have the .lts and .gts properties, which represent the "less 

928 than side" and "greater than side" of the operator. Use of .lts and .gts 

929 in an algorithm rather than .lhs and .rhs as an assumption of inequality 

930 direction will make more explicit the intent of a certain section of code, 

931 and will make it similarly more robust to client code changes: 

932 

933 >>> from sympy import GreaterThan, StrictGreaterThan 

934 >>> from sympy import LessThan, StrictLessThan 

935 >>> from sympy import And, Ge, Gt, Le, Lt, Rel, S 

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

937 >>> from sympy.core.relational import Relational 

938 

939 >>> e = GreaterThan(x, 1) 

940 >>> e 

941 x >= 1 

942 >>> '%s >= %s is the same as %s <= %s' % (e.gts, e.lts, e.lts, e.gts) 

943 'x >= 1 is the same as 1 <= x' 

944 

945 Examples 

946 ======== 

947 

948 One generally does not instantiate these classes directly, but uses various 

949 convenience methods: 

950 

951 >>> for f in [Ge, Gt, Le, Lt]: # convenience wrappers 

952 ... print(f(x, 2)) 

953 x >= 2 

954 x > 2 

955 x <= 2 

956 x < 2 

957 

958 Another option is to use the Python inequality operators (``>=``, ``>``, 

959 ``<=``, ``<``) directly. Their main advantage over the ``Ge``, ``Gt``, 

960 ``Le``, and ``Lt`` counterparts, is that one can write a more 

961 "mathematical looking" statement rather than littering the math with 

962 oddball function calls. However there are certain (minor) caveats of 

963 which to be aware (search for 'gotcha', below). 

964 

965 >>> x >= 2 

966 x >= 2 

967 >>> _ == Ge(x, 2) 

968 True 

969 

970 However, it is also perfectly valid to instantiate a ``*Than`` class less 

971 succinctly and less conveniently: 

972 

973 >>> Rel(x, 1, ">") 

974 x > 1 

975 >>> Relational(x, 1, ">") 

976 x > 1 

977 

978 >>> StrictGreaterThan(x, 1) 

979 x > 1 

980 >>> GreaterThan(x, 1) 

981 x >= 1 

982 >>> LessThan(x, 1) 

983 x <= 1 

984 >>> StrictLessThan(x, 1) 

985 x < 1 

986 

987 Notes 

988 ===== 

989 

990 There are a couple of "gotchas" to be aware of when using Python's 

991 operators. 

992 

993 The first is that what your write is not always what you get: 

994 

995 >>> 1 < x 

996 x > 1 

997 

998 Due to the order that Python parses a statement, it may 

999 not immediately find two objects comparable. When ``1 < x`` 

1000 is evaluated, Python recognizes that the number 1 is a native 

1001 number and that x is *not*. Because a native Python number does 

1002 not know how to compare itself with a SymPy object 

1003 Python will try the reflective operation, ``x > 1`` and that is the 

1004 form that gets evaluated, hence returned. 

1005 

1006 If the order of the statement is important (for visual output to 

1007 the console, perhaps), one can work around this annoyance in a 

1008 couple ways: 

1009 

1010 (1) "sympify" the literal before comparison 

1011 

1012 >>> S(1) < x 

1013 1 < x 

1014 

1015 (2) use one of the wrappers or less succinct methods described 

1016 above 

1017 

1018 >>> Lt(1, x) 

1019 1 < x 

1020 >>> Relational(1, x, "<") 

1021 1 < x 

1022 

1023 The second gotcha involves writing equality tests between relationals 

1024 when one or both sides of the test involve a literal relational: 

1025 

1026 >>> e = x < 1; e 

1027 x < 1 

1028 >>> e == e # neither side is a literal 

1029 True 

1030 >>> e == x < 1 # expecting True, too 

1031 False 

1032 >>> e != x < 1 # expecting False 

1033 x < 1 

1034 >>> x < 1 != x < 1 # expecting False or the same thing as before 

1035 Traceback (most recent call last): 

1036 ... 

1037 TypeError: cannot determine truth value of Relational 

1038 

1039 The solution for this case is to wrap literal relationals in 

1040 parentheses: 

1041 

1042 >>> e == (x < 1) 

1043 True 

1044 >>> e != (x < 1) 

1045 False 

1046 >>> (x < 1) != (x < 1) 

1047 False 

1048 

1049 The third gotcha involves chained inequalities not involving 

1050 ``==`` or ``!=``. Occasionally, one may be tempted to write: 

1051 

1052 >>> e = x < y < z 

1053 Traceback (most recent call last): 

1054 ... 

1055 TypeError: symbolic boolean expression has no truth value. 

1056 

1057 Due to an implementation detail or decision of Python [1]_, 

1058 there is no way for SymPy to create a chained inequality with 

1059 that syntax so one must use And: 

1060 

1061 >>> e = And(x < y, y < z) 

1062 >>> type( e ) 

1063 And 

1064 >>> e 

1065 (x < y) & (y < z) 

1066 

1067 Although this can also be done with the '&' operator, it cannot 

1068 be done with the 'and' operarator: 

1069 

1070 >>> (x < y) & (y < z) 

1071 (x < y) & (y < z) 

1072 >>> (x < y) and (y < z) 

1073 Traceback (most recent call last): 

1074 ... 

1075 TypeError: cannot determine truth value of Relational 

1076 

1077 .. [1] This implementation detail is that Python provides no reliable 

1078 method to determine that a chained inequality is being built. 

1079 Chained comparison operators are evaluated pairwise, using "and" 

1080 logic (see 

1081 https://docs.python.org/3/reference/expressions.html#not-in). This 

1082 is done in an efficient way, so that each object being compared 

1083 is only evaluated once and the comparison can short-circuit. For 

1084 example, ``1 > 2 > 3`` is evaluated by Python as ``(1 > 2) and (2 

1085 > 3)``. The ``and`` operator coerces each side into a bool, 

1086 returning the object itself when it short-circuits. The bool of 

1087 the --Than operators will raise TypeError on purpose, because 

1088 SymPy cannot determine the mathematical ordering of symbolic 

1089 expressions. Thus, if we were to compute ``x > y > z``, with 

1090 ``x``, ``y``, and ``z`` being Symbols, Python converts the 

1091 statement (roughly) into these steps: 

1092 

1093 (1) x > y > z 

1094 (2) (x > y) and (y > z) 

1095 (3) (GreaterThanObject) and (y > z) 

1096 (4) (GreaterThanObject.__bool__()) and (y > z) 

1097 (5) TypeError 

1098 

1099 Because of the ``and`` added at step 2, the statement gets turned into a 

1100 weak ternary statement, and the first object's ``__bool__`` method will 

1101 raise TypeError. Thus, creating a chained inequality is not possible. 

1102 

1103 In Python, there is no way to override the ``and`` operator, or to 

1104 control how it short circuits, so it is impossible to make something 

1105 like ``x > y > z`` work. There was a PEP to change this, 

1106 :pep:`335`, but it was officially closed in March, 2012. 

1107 

1108 """ 

1109 __slots__ = () 

1110 

1111 rel_op = '>=' 

1112 

1113 @classmethod 

1114 def _eval_fuzzy_relation(cls, lhs, rhs): 

1115 return is_ge(lhs, rhs) 

1116 

1117 @property 

1118 def strict(self): 

1119 return Gt(*self.args) 

1120 

1121Ge = GreaterThan 

1122 

1123 

1124class LessThan(_Less): 

1125 __doc__ = GreaterThan.__doc__ 

1126 __slots__ = () 

1127 

1128 rel_op = '<=' 

1129 

1130 @classmethod 

1131 def _eval_fuzzy_relation(cls, lhs, rhs): 

1132 return is_le(lhs, rhs) 

1133 

1134 @property 

1135 def strict(self): 

1136 return Lt(*self.args) 

1137 

1138Le = LessThan 

1139 

1140 

1141class StrictGreaterThan(_Greater): 

1142 __doc__ = GreaterThan.__doc__ 

1143 __slots__ = () 

1144 

1145 rel_op = '>' 

1146 

1147 @classmethod 

1148 def _eval_fuzzy_relation(cls, lhs, rhs): 

1149 return is_gt(lhs, rhs) 

1150 

1151 @property 

1152 def weak(self): 

1153 return Ge(*self.args) 

1154 

1155 

1156Gt = StrictGreaterThan 

1157 

1158 

1159class StrictLessThan(_Less): 

1160 __doc__ = GreaterThan.__doc__ 

1161 __slots__ = () 

1162 

1163 rel_op = '<' 

1164 

1165 @classmethod 

1166 def _eval_fuzzy_relation(cls, lhs, rhs): 

1167 return is_lt(lhs, rhs) 

1168 

1169 @property 

1170 def weak(self): 

1171 return Le(*self.args) 

1172 

1173Lt = StrictLessThan 

1174 

1175# A class-specific (not object-specific) data item used for a minor speedup. 

1176# It is defined here, rather than directly in the class, because the classes 

1177# that it references have not been defined until now (e.g. StrictLessThan). 

1178Relational.ValidRelationOperator = { 

1179 None: Equality, 

1180 '==': Equality, 

1181 'eq': Equality, 

1182 '!=': Unequality, 

1183 '<>': Unequality, 

1184 'ne': Unequality, 

1185 '>=': GreaterThan, 

1186 'ge': GreaterThan, 

1187 '<=': LessThan, 

1188 'le': LessThan, 

1189 '>': StrictGreaterThan, 

1190 'gt': StrictGreaterThan, 

1191 '<': StrictLessThan, 

1192 'lt': StrictLessThan, 

1193} 

1194 

1195 

1196def _n2(a, b): 

1197 """Return (a - b).evalf(2) if a and b are comparable, else None. 

1198 This should only be used when a and b are already sympified. 

1199 """ 

1200 # /!\ it is very important (see issue 8245) not to 

1201 # use a re-evaluated number in the calculation of dif 

1202 if a.is_comparable and b.is_comparable: 

1203 dif = (a - b).evalf(2) 

1204 if dif.is_comparable: 

1205 return dif 

1206 

1207 

1208@dispatch(Expr, Expr) 

1209def _eval_is_ge(lhs, rhs): 

1210 return None 

1211 

1212 

1213@dispatch(Basic, Basic) 

1214def _eval_is_eq(lhs, rhs): 

1215 return None 

1216 

1217 

1218@dispatch(Tuple, Expr) # type: ignore 

1219def _eval_is_eq(lhs, rhs): # noqa:F811 

1220 return False 

1221 

1222 

1223@dispatch(Tuple, AppliedUndef) # type: ignore 

1224def _eval_is_eq(lhs, rhs): # noqa:F811 

1225 return None 

1226 

1227 

1228@dispatch(Tuple, Symbol) # type: ignore 

1229def _eval_is_eq(lhs, rhs): # noqa:F811 

1230 return None 

1231 

1232 

1233@dispatch(Tuple, Tuple) # type: ignore 

1234def _eval_is_eq(lhs, rhs): # noqa:F811 

1235 if len(lhs) != len(rhs): 

1236 return False 

1237 

1238 return fuzzy_and(fuzzy_bool(is_eq(s, o)) for s, o in zip(lhs, rhs)) 

1239 

1240 

1241def is_lt(lhs, rhs, assumptions=None): 

1242 """Fuzzy bool for lhs is strictly less than rhs. 

1243 

1244 See the docstring for :func:`~.is_ge` for more. 

1245 """ 

1246 return fuzzy_not(is_ge(lhs, rhs, assumptions)) 

1247 

1248 

1249def is_gt(lhs, rhs, assumptions=None): 

1250 """Fuzzy bool for lhs is strictly greater than rhs. 

1251 

1252 See the docstring for :func:`~.is_ge` for more. 

1253 """ 

1254 return fuzzy_not(is_le(lhs, rhs, assumptions)) 

1255 

1256 

1257def is_le(lhs, rhs, assumptions=None): 

1258 """Fuzzy bool for lhs is less than or equal to rhs. 

1259 

1260 See the docstring for :func:`~.is_ge` for more. 

1261 """ 

1262 return is_ge(rhs, lhs, assumptions) 

1263 

1264 

1265def is_ge(lhs, rhs, assumptions=None): 

1266 """ 

1267 Fuzzy bool for *lhs* is greater than or equal to *rhs*. 

1268 

1269 Parameters 

1270 ========== 

1271 

1272 lhs : Expr 

1273 The left-hand side of the expression, must be sympified, 

1274 and an instance of expression. Throws an exception if 

1275 lhs is not an instance of expression. 

1276 

1277 rhs : Expr 

1278 The right-hand side of the expression, must be sympified 

1279 and an instance of expression. Throws an exception if 

1280 lhs is not an instance of expression. 

1281 

1282 assumptions: Boolean, optional 

1283 Assumptions taken to evaluate the inequality. 

1284 

1285 Returns 

1286 ======= 

1287 

1288 ``True`` if *lhs* is greater than or equal to *rhs*, ``False`` if *lhs* 

1289 is less than *rhs*, and ``None`` if the comparison between *lhs* and 

1290 *rhs* is indeterminate. 

1291 

1292 Explanation 

1293 =========== 

1294 

1295 This function is intended to give a relatively fast determination and 

1296 deliberately does not attempt slow calculations that might help in 

1297 obtaining a determination of True or False in more difficult cases. 

1298 

1299 The four comparison functions ``is_le``, ``is_lt``, ``is_ge``, and ``is_gt`` are 

1300 each implemented in terms of ``is_ge`` in the following way: 

1301 

1302 is_ge(x, y) := is_ge(x, y) 

1303 is_le(x, y) := is_ge(y, x) 

1304 is_lt(x, y) := fuzzy_not(is_ge(x, y)) 

1305 is_gt(x, y) := fuzzy_not(is_ge(y, x)) 

1306 

1307 Therefore, supporting new type with this function will ensure behavior for 

1308 other three functions as well. 

1309 

1310 To maintain these equivalences in fuzzy logic it is important that in cases where 

1311 either x or y is non-real all comparisons will give None. 

1312 

1313 Examples 

1314 ======== 

1315 

1316 >>> from sympy import S, Q 

1317 >>> from sympy.core.relational import is_ge, is_le, is_gt, is_lt 

1318 >>> from sympy.abc import x 

1319 >>> is_ge(S(2), S(0)) 

1320 True 

1321 >>> is_ge(S(0), S(2)) 

1322 False 

1323 >>> is_le(S(0), S(2)) 

1324 True 

1325 >>> is_gt(S(0), S(2)) 

1326 False 

1327 >>> is_lt(S(2), S(0)) 

1328 False 

1329 

1330 Assumptions can be passed to evaluate the quality which is otherwise 

1331 indeterminate. 

1332 

1333 >>> print(is_ge(x, S(0))) 

1334 None 

1335 >>> is_ge(x, S(0), assumptions=Q.positive(x)) 

1336 True 

1337 

1338 New types can be supported by dispatching to ``_eval_is_ge``. 

1339 

1340 >>> from sympy import Expr, sympify 

1341 >>> from sympy.multipledispatch import dispatch 

1342 >>> class MyExpr(Expr): 

1343 ... def __new__(cls, arg): 

1344 ... return super().__new__(cls, sympify(arg)) 

1345 ... @property 

1346 ... def value(self): 

1347 ... return self.args[0] 

1348 >>> @dispatch(MyExpr, MyExpr) 

1349 ... def _eval_is_ge(a, b): 

1350 ... return is_ge(a.value, b.value) 

1351 >>> a = MyExpr(1) 

1352 >>> b = MyExpr(2) 

1353 >>> is_ge(b, a) 

1354 True 

1355 >>> is_le(a, b) 

1356 True 

1357 """ 

1358 from sympy.assumptions.wrapper import AssumptionsWrapper, is_extended_nonnegative 

1359 

1360 if not (isinstance(lhs, Expr) and isinstance(rhs, Expr)): 

1361 raise TypeError("Can only compare inequalities with Expr") 

1362 

1363 retval = _eval_is_ge(lhs, rhs) 

1364 

1365 if retval is not None: 

1366 return retval 

1367 else: 

1368 n2 = _n2(lhs, rhs) 

1369 if n2 is not None: 

1370 # use float comparison for infinity. 

1371 # otherwise get stuck in infinite recursion 

1372 if n2 in (S.Infinity, S.NegativeInfinity): 

1373 n2 = float(n2) 

1374 return n2 >= 0 

1375 

1376 _lhs = AssumptionsWrapper(lhs, assumptions) 

1377 _rhs = AssumptionsWrapper(rhs, assumptions) 

1378 if _lhs.is_extended_real and _rhs.is_extended_real: 

1379 if (_lhs.is_infinite and _lhs.is_extended_positive) or (_rhs.is_infinite and _rhs.is_extended_negative): 

1380 return True 

1381 diff = lhs - rhs 

1382 if diff is not S.NaN: 

1383 rv = is_extended_nonnegative(diff, assumptions) 

1384 if rv is not None: 

1385 return rv 

1386 

1387 

1388def is_neq(lhs, rhs, assumptions=None): 

1389 """Fuzzy bool for lhs does not equal rhs. 

1390 

1391 See the docstring for :func:`~.is_eq` for more. 

1392 """ 

1393 return fuzzy_not(is_eq(lhs, rhs, assumptions)) 

1394 

1395 

1396def is_eq(lhs, rhs, assumptions=None): 

1397 """ 

1398 Fuzzy bool representing mathematical equality between *lhs* and *rhs*. 

1399 

1400 Parameters 

1401 ========== 

1402 

1403 lhs : Expr 

1404 The left-hand side of the expression, must be sympified. 

1405 

1406 rhs : Expr 

1407 The right-hand side of the expression, must be sympified. 

1408 

1409 assumptions: Boolean, optional 

1410 Assumptions taken to evaluate the equality. 

1411 

1412 Returns 

1413 ======= 

1414 

1415 ``True`` if *lhs* is equal to *rhs*, ``False`` is *lhs* is not equal to *rhs*, 

1416 and ``None`` if the comparison between *lhs* and *rhs* is indeterminate. 

1417 

1418 Explanation 

1419 =========== 

1420 

1421 This function is intended to give a relatively fast determination and 

1422 deliberately does not attempt slow calculations that might help in 

1423 obtaining a determination of True or False in more difficult cases. 

1424 

1425 :func:`~.is_neq` calls this function to return its value, so supporting 

1426 new type with this function will ensure correct behavior for ``is_neq`` 

1427 as well. 

1428 

1429 Examples 

1430 ======== 

1431 

1432 >>> from sympy import Q, S 

1433 >>> from sympy.core.relational import is_eq, is_neq 

1434 >>> from sympy.abc import x 

1435 >>> is_eq(S(0), S(0)) 

1436 True 

1437 >>> is_neq(S(0), S(0)) 

1438 False 

1439 >>> is_eq(S(0), S(2)) 

1440 False 

1441 >>> is_neq(S(0), S(2)) 

1442 True 

1443 

1444 Assumptions can be passed to evaluate the equality which is otherwise 

1445 indeterminate. 

1446 

1447 >>> print(is_eq(x, S(0))) 

1448 None 

1449 >>> is_eq(x, S(0), assumptions=Q.zero(x)) 

1450 True 

1451 

1452 New types can be supported by dispatching to ``_eval_is_eq``. 

1453 

1454 >>> from sympy import Basic, sympify 

1455 >>> from sympy.multipledispatch import dispatch 

1456 >>> class MyBasic(Basic): 

1457 ... def __new__(cls, arg): 

1458 ... return Basic.__new__(cls, sympify(arg)) 

1459 ... @property 

1460 ... def value(self): 

1461 ... return self.args[0] 

1462 ... 

1463 >>> @dispatch(MyBasic, MyBasic) 

1464 ... def _eval_is_eq(a, b): 

1465 ... return is_eq(a.value, b.value) 

1466 ... 

1467 >>> a = MyBasic(1) 

1468 >>> b = MyBasic(1) 

1469 >>> is_eq(a, b) 

1470 True 

1471 >>> is_neq(a, b) 

1472 False 

1473 

1474 """ 

1475 # here, _eval_Eq is only called for backwards compatibility 

1476 # new code should use is_eq with multiple dispatch as 

1477 # outlined in the docstring 

1478 for side1, side2 in (lhs, rhs), (rhs, lhs): 

1479 eval_func = getattr(side1, '_eval_Eq', None) 

1480 if eval_func is not None: 

1481 retval = eval_func(side2) 

1482 if retval is not None: 

1483 return retval 

1484 

1485 retval = _eval_is_eq(lhs, rhs) 

1486 if retval is not None: 

1487 return retval 

1488 

1489 if dispatch(type(lhs), type(rhs)) != dispatch(type(rhs), type(lhs)): 

1490 retval = _eval_is_eq(rhs, lhs) 

1491 if retval is not None: 

1492 return retval 

1493 

1494 # retval is still None, so go through the equality logic 

1495 # If expressions have the same structure, they must be equal. 

1496 if lhs == rhs: 

1497 return True # e.g. True == True 

1498 elif all(isinstance(i, BooleanAtom) for i in (rhs, lhs)): 

1499 return False # True != False 

1500 elif not (lhs.is_Symbol or rhs.is_Symbol) and ( 

1501 isinstance(lhs, Boolean) != 

1502 isinstance(rhs, Boolean)): 

1503 return False # only Booleans can equal Booleans 

1504 

1505 from sympy.assumptions.wrapper import (AssumptionsWrapper, 

1506 is_infinite, is_extended_real) 

1507 from .add import Add 

1508 

1509 _lhs = AssumptionsWrapper(lhs, assumptions) 

1510 _rhs = AssumptionsWrapper(rhs, assumptions) 

1511 

1512 if _lhs.is_infinite or _rhs.is_infinite: 

1513 if fuzzy_xor([_lhs.is_infinite, _rhs.is_infinite]): 

1514 return False 

1515 if fuzzy_xor([_lhs.is_extended_real, _rhs.is_extended_real]): 

1516 return False 

1517 if fuzzy_and([_lhs.is_extended_real, _rhs.is_extended_real]): 

1518 return fuzzy_xor([_lhs.is_extended_positive, fuzzy_not(_rhs.is_extended_positive)]) 

1519 

1520 # Try to split real/imaginary parts and equate them 

1521 I = S.ImaginaryUnit 

1522 

1523 def split_real_imag(expr): 

1524 real_imag = lambda t: ( 

1525 'real' if is_extended_real(t, assumptions) else 

1526 'imag' if is_extended_real(I*t, assumptions) else None) 

1527 return sift(Add.make_args(expr), real_imag) 

1528 

1529 lhs_ri = split_real_imag(lhs) 

1530 if not lhs_ri[None]: 

1531 rhs_ri = split_real_imag(rhs) 

1532 if not rhs_ri[None]: 

1533 eq_real = is_eq(Add(*lhs_ri['real']), Add(*rhs_ri['real']), assumptions) 

1534 eq_imag = is_eq(I * Add(*lhs_ri['imag']), I * Add(*rhs_ri['imag']), assumptions) 

1535 return fuzzy_and(map(fuzzy_bool, [eq_real, eq_imag])) 

1536 

1537 from sympy.functions.elementary.complexes import arg 

1538 # Compare e.g. zoo with 1+I*oo by comparing args 

1539 arglhs = arg(lhs) 

1540 argrhs = arg(rhs) 

1541 # Guard against Eq(nan, nan) -> False 

1542 if not (arglhs == S.NaN and argrhs == S.NaN): 

1543 return fuzzy_bool(is_eq(arglhs, argrhs, assumptions)) 

1544 

1545 if all(isinstance(i, Expr) for i in (lhs, rhs)): 

1546 # see if the difference evaluates 

1547 dif = lhs - rhs 

1548 _dif = AssumptionsWrapper(dif, assumptions) 

1549 z = _dif.is_zero 

1550 if z is not None: 

1551 if z is False and _dif.is_commutative: # issue 10728 

1552 return False 

1553 if z: 

1554 return True 

1555 

1556 n2 = _n2(lhs, rhs) 

1557 if n2 is not None: 

1558 return _sympify(n2 == 0) 

1559 

1560 # see if the ratio evaluates 

1561 n, d = dif.as_numer_denom() 

1562 rv = None 

1563 _n = AssumptionsWrapper(n, assumptions) 

1564 _d = AssumptionsWrapper(d, assumptions) 

1565 if _n.is_zero: 

1566 rv = _d.is_nonzero 

1567 elif _n.is_finite: 

1568 if _d.is_infinite: 

1569 rv = True 

1570 elif _n.is_zero is False: 

1571 rv = _d.is_infinite 

1572 if rv is None: 

1573 # if the condition that makes the denominator 

1574 # infinite does not make the original expression 

1575 # True then False can be returned 

1576 from sympy.simplify.simplify import clear_coefficients 

1577 l, r = clear_coefficients(d, S.Infinity) 

1578 args = [_.subs(l, r) for _ in (lhs, rhs)] 

1579 if args != [lhs, rhs]: 

1580 rv = fuzzy_bool(is_eq(*args, assumptions)) 

1581 if rv is True: 

1582 rv = None 

1583 elif any(is_infinite(a, assumptions) for a in Add.make_args(n)): 

1584 # (inf or nan)/x != 0 

1585 rv = False 

1586 if rv is not None: 

1587 return rv