Coverage for /usr/lib/python3/dist-packages/sympy/sets/sets.py: 32%

1154 statements  

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

1from typing import Any, Callable 

2from functools import reduce 

3from collections import defaultdict 

4import inspect 

5 

6from sympy.core.kind import Kind, UndefinedKind, NumberKind 

7from sympy.core.basic import Basic 

8from sympy.core.containers import Tuple, TupleKind 

9from sympy.core.decorators import sympify_method_args, sympify_return 

10from sympy.core.evalf import EvalfMixin 

11from sympy.core.expr import Expr 

12from sympy.core.function import Lambda 

13from sympy.core.logic import (FuzzyBool, fuzzy_bool, fuzzy_or, fuzzy_and, 

14 fuzzy_not) 

15from sympy.core.numbers import Float, Integer 

16from sympy.core.operations import LatticeOp 

17from sympy.core.parameters import global_parameters 

18from sympy.core.relational import Eq, Ne, is_lt 

19from sympy.core.singleton import Singleton, S 

20from sympy.core.sorting import ordered 

21from sympy.core.symbol import symbols, Symbol, Dummy, uniquely_named_symbol 

22from sympy.core.sympify import _sympify, sympify, _sympy_converter 

23from sympy.functions.elementary.exponential import exp, log 

24from sympy.functions.elementary.miscellaneous import Max, Min 

25from sympy.logic.boolalg import And, Or, Not, Xor, true, false 

26from sympy.utilities.decorator import deprecated 

27from sympy.utilities.exceptions import sympy_deprecation_warning 

28from sympy.utilities.iterables import (iproduct, sift, roundrobin, iterable, 

29 subsets) 

30from sympy.utilities.misc import func_name, filldedent 

31 

32from mpmath import mpi, mpf 

33 

34from mpmath.libmp.libmpf import prec_to_dps 

35 

36 

37tfn = defaultdict(lambda: None, { 

38 True: S.true, 

39 S.true: S.true, 

40 False: S.false, 

41 S.false: S.false}) 

42 

43 

44@sympify_method_args 

45class Set(Basic, EvalfMixin): 

46 """ 

47 The base class for any kind of set. 

48 

49 Explanation 

50 =========== 

51 

52 This is not meant to be used directly as a container of items. It does not 

53 behave like the builtin ``set``; see :class:`FiniteSet` for that. 

54 

55 Real intervals are represented by the :class:`Interval` class and unions of 

56 sets by the :class:`Union` class. The empty set is represented by the 

57 :class:`EmptySet` class and available as a singleton as ``S.EmptySet``. 

58 """ 

59 

60 __slots__ = () 

61 

62 is_number = False 

63 is_iterable = False 

64 is_interval = False 

65 

66 is_FiniteSet = False 

67 is_Interval = False 

68 is_ProductSet = False 

69 is_Union = False 

70 is_Intersection: FuzzyBool = None 

71 is_UniversalSet: FuzzyBool = None 

72 is_Complement: FuzzyBool = None 

73 is_ComplexRegion = False 

74 

75 is_empty: FuzzyBool = None 

76 is_finite_set: FuzzyBool = None 

77 

78 @property # type: ignore 

79 @deprecated( 

80 """ 

81 The is_EmptySet attribute of Set objects is deprecated. 

82 Use 's is S.EmptySet" or 's.is_empty' instead. 

83 """, 

84 deprecated_since_version="1.5", 

85 active_deprecations_target="deprecated-is-emptyset", 

86 ) 

87 def is_EmptySet(self): 

88 return None 

89 

90 @staticmethod 

91 def _infimum_key(expr): 

92 """ 

93 Return infimum (if possible) else S.Infinity. 

94 """ 

95 try: 

96 infimum = expr.inf 

97 assert infimum.is_comparable 

98 infimum = infimum.evalf() # issue #18505 

99 except (NotImplementedError, 

100 AttributeError, AssertionError, ValueError): 

101 infimum = S.Infinity 

102 return infimum 

103 

104 def union(self, other): 

105 """ 

106 Returns the union of ``self`` and ``other``. 

107 

108 Examples 

109 ======== 

110 

111 As a shortcut it is possible to use the ``+`` operator: 

112 

113 >>> from sympy import Interval, FiniteSet 

114 >>> Interval(0, 1).union(Interval(2, 3)) 

115 Union(Interval(0, 1), Interval(2, 3)) 

116 >>> Interval(0, 1) + Interval(2, 3) 

117 Union(Interval(0, 1), Interval(2, 3)) 

118 >>> Interval(1, 2, True, True) + FiniteSet(2, 3) 

119 Union({3}, Interval.Lopen(1, 2)) 

120 

121 Similarly it is possible to use the ``-`` operator for set differences: 

122 

123 >>> Interval(0, 2) - Interval(0, 1) 

124 Interval.Lopen(1, 2) 

125 >>> Interval(1, 3) - FiniteSet(2) 

126 Union(Interval.Ropen(1, 2), Interval.Lopen(2, 3)) 

127 

128 """ 

129 return Union(self, other) 

130 

131 def intersect(self, other): 

132 """ 

133 Returns the intersection of 'self' and 'other'. 

134 

135 Examples 

136 ======== 

137 

138 >>> from sympy import Interval 

139 

140 >>> Interval(1, 3).intersect(Interval(1, 2)) 

141 Interval(1, 2) 

142 

143 >>> from sympy import imageset, Lambda, symbols, S 

144 >>> n, m = symbols('n m') 

145 >>> a = imageset(Lambda(n, 2*n), S.Integers) 

146 >>> a.intersect(imageset(Lambda(m, 2*m + 1), S.Integers)) 

147 EmptySet 

148 

149 """ 

150 return Intersection(self, other) 

151 

152 def intersection(self, other): 

153 """ 

154 Alias for :meth:`intersect()` 

155 """ 

156 return self.intersect(other) 

157 

158 def is_disjoint(self, other): 

159 """ 

160 Returns True if ``self`` and ``other`` are disjoint. 

161 

162 Examples 

163 ======== 

164 

165 >>> from sympy import Interval 

166 >>> Interval(0, 2).is_disjoint(Interval(1, 2)) 

167 False 

168 >>> Interval(0, 2).is_disjoint(Interval(3, 4)) 

169 True 

170 

171 References 

172 ========== 

173 

174 .. [1] https://en.wikipedia.org/wiki/Disjoint_sets 

175 """ 

176 return self.intersect(other) == S.EmptySet 

177 

178 def isdisjoint(self, other): 

179 """ 

180 Alias for :meth:`is_disjoint()` 

181 """ 

182 return self.is_disjoint(other) 

183 

184 def complement(self, universe): 

185 r""" 

186 The complement of 'self' w.r.t the given universe. 

187 

188 Examples 

189 ======== 

190 

191 >>> from sympy import Interval, S 

192 >>> Interval(0, 1).complement(S.Reals) 

193 Union(Interval.open(-oo, 0), Interval.open(1, oo)) 

194 

195 >>> Interval(0, 1).complement(S.UniversalSet) 

196 Complement(UniversalSet, Interval(0, 1)) 

197 

198 """ 

199 return Complement(universe, self) 

200 

201 def _complement(self, other): 

202 # this behaves as other - self 

203 if isinstance(self, ProductSet) and isinstance(other, ProductSet): 

204 # If self and other are disjoint then other - self == self 

205 if len(self.sets) != len(other.sets): 

206 return other 

207 

208 # There can be other ways to represent this but this gives: 

209 # (A x B) - (C x D) = ((A - C) x B) U (A x (B - D)) 

210 overlaps = [] 

211 pairs = list(zip(self.sets, other.sets)) 

212 for n in range(len(pairs)): 

213 sets = (o if i != n else o-s for i, (s, o) in enumerate(pairs)) 

214 overlaps.append(ProductSet(*sets)) 

215 return Union(*overlaps) 

216 

217 elif isinstance(other, Interval): 

218 if isinstance(self, (Interval, FiniteSet)): 

219 return Intersection(other, self.complement(S.Reals)) 

220 

221 elif isinstance(other, Union): 

222 return Union(*(o - self for o in other.args)) 

223 

224 elif isinstance(other, Complement): 

225 return Complement(other.args[0], Union(other.args[1], self), evaluate=False) 

226 

227 elif other is S.EmptySet: 

228 return S.EmptySet 

229 

230 elif isinstance(other, FiniteSet): 

231 sifted = sift(other, lambda x: fuzzy_bool(self.contains(x))) 

232 # ignore those that are contained in self 

233 return Union(FiniteSet(*(sifted[False])), 

234 Complement(FiniteSet(*(sifted[None])), self, evaluate=False) 

235 if sifted[None] else S.EmptySet) 

236 

237 def symmetric_difference(self, other): 

238 """ 

239 Returns symmetric difference of ``self`` and ``other``. 

240 

241 Examples 

242 ======== 

243 

244 >>> from sympy import Interval, S 

245 >>> Interval(1, 3).symmetric_difference(S.Reals) 

246 Union(Interval.open(-oo, 1), Interval.open(3, oo)) 

247 >>> Interval(1, 10).symmetric_difference(S.Reals) 

248 Union(Interval.open(-oo, 1), Interval.open(10, oo)) 

249 

250 >>> from sympy import S, EmptySet 

251 >>> S.Reals.symmetric_difference(EmptySet) 

252 Reals 

253 

254 References 

255 ========== 

256 .. [1] https://en.wikipedia.org/wiki/Symmetric_difference 

257 

258 """ 

259 return SymmetricDifference(self, other) 

260 

261 def _symmetric_difference(self, other): 

262 return Union(Complement(self, other), Complement(other, self)) 

263 

264 @property 

265 def inf(self): 

266 """ 

267 The infimum of ``self``. 

268 

269 Examples 

270 ======== 

271 

272 >>> from sympy import Interval, Union 

273 >>> Interval(0, 1).inf 

274 0 

275 >>> Union(Interval(0, 1), Interval(2, 3)).inf 

276 0 

277 

278 """ 

279 return self._inf 

280 

281 @property 

282 def _inf(self): 

283 raise NotImplementedError("(%s)._inf" % self) 

284 

285 @property 

286 def sup(self): 

287 """ 

288 The supremum of ``self``. 

289 

290 Examples 

291 ======== 

292 

293 >>> from sympy import Interval, Union 

294 >>> Interval(0, 1).sup 

295 1 

296 >>> Union(Interval(0, 1), Interval(2, 3)).sup 

297 3 

298 

299 """ 

300 return self._sup 

301 

302 @property 

303 def _sup(self): 

304 raise NotImplementedError("(%s)._sup" % self) 

305 

306 def contains(self, other): 

307 """ 

308 Returns a SymPy value indicating whether ``other`` is contained 

309 in ``self``: ``true`` if it is, ``false`` if it is not, else 

310 an unevaluated ``Contains`` expression (or, as in the case of 

311 ConditionSet and a union of FiniteSet/Intervals, an expression 

312 indicating the conditions for containment). 

313 

314 Examples 

315 ======== 

316 

317 >>> from sympy import Interval, S 

318 >>> from sympy.abc import x 

319 

320 >>> Interval(0, 1).contains(0.5) 

321 True 

322 

323 As a shortcut it is possible to use the ``in`` operator, but that 

324 will raise an error unless an affirmative true or false is not 

325 obtained. 

326 

327 >>> Interval(0, 1).contains(x) 

328 (0 <= x) & (x <= 1) 

329 >>> x in Interval(0, 1) 

330 Traceback (most recent call last): 

331 ... 

332 TypeError: did not evaluate to a bool: None 

333 

334 The result of 'in' is a bool, not a SymPy value 

335 

336 >>> 1 in Interval(0, 2) 

337 True 

338 >>> _ is S.true 

339 False 

340 """ 

341 from .contains import Contains 

342 other = sympify(other, strict=True) 

343 

344 c = self._contains(other) 

345 if isinstance(c, Contains): 

346 return c 

347 if c is None: 

348 return Contains(other, self, evaluate=False) 

349 b = tfn[c] 

350 if b is None: 

351 return c 

352 return b 

353 

354 def _contains(self, other): 

355 raise NotImplementedError(filldedent(''' 

356 (%s)._contains(%s) is not defined. This method, when 

357 defined, will receive a sympified object. The method 

358 should return True, False, None or something that 

359 expresses what must be true for the containment of that 

360 object in self to be evaluated. If None is returned 

361 then a generic Contains object will be returned 

362 by the ``contains`` method.''' % (self, other))) 

363 

364 def is_subset(self, other): 

365 """ 

366 Returns True if ``self`` is a subset of ``other``. 

367 

368 Examples 

369 ======== 

370 

371 >>> from sympy import Interval 

372 >>> Interval(0, 0.5).is_subset(Interval(0, 1)) 

373 True 

374 >>> Interval(0, 1).is_subset(Interval(0, 1, left_open=True)) 

375 False 

376 

377 """ 

378 if not isinstance(other, Set): 

379 raise ValueError("Unknown argument '%s'" % other) 

380 

381 # Handle the trivial cases 

382 if self == other: 

383 return True 

384 is_empty = self.is_empty 

385 if is_empty is True: 

386 return True 

387 elif fuzzy_not(is_empty) and other.is_empty: 

388 return False 

389 if self.is_finite_set is False and other.is_finite_set: 

390 return False 

391 

392 # Dispatch on subclass rules 

393 ret = self._eval_is_subset(other) 

394 if ret is not None: 

395 return ret 

396 ret = other._eval_is_superset(self) 

397 if ret is not None: 

398 return ret 

399 

400 # Use pairwise rules from multiple dispatch 

401 from sympy.sets.handlers.issubset import is_subset_sets 

402 ret = is_subset_sets(self, other) 

403 if ret is not None: 

404 return ret 

405 

406 # Fall back on computing the intersection 

407 # XXX: We shouldn't do this. A query like this should be handled 

408 # without evaluating new Set objects. It should be the other way round 

409 # so that the intersect method uses is_subset for evaluation. 

410 if self.intersect(other) == self: 

411 return True 

412 

413 def _eval_is_subset(self, other): 

414 '''Returns a fuzzy bool for whether self is a subset of other.''' 

415 return None 

416 

417 def _eval_is_superset(self, other): 

418 '''Returns a fuzzy bool for whether self is a subset of other.''' 

419 return None 

420 

421 # This should be deprecated: 

422 def issubset(self, other): 

423 """ 

424 Alias for :meth:`is_subset()` 

425 """ 

426 return self.is_subset(other) 

427 

428 def is_proper_subset(self, other): 

429 """ 

430 Returns True if ``self`` is a proper subset of ``other``. 

431 

432 Examples 

433 ======== 

434 

435 >>> from sympy import Interval 

436 >>> Interval(0, 0.5).is_proper_subset(Interval(0, 1)) 

437 True 

438 >>> Interval(0, 1).is_proper_subset(Interval(0, 1)) 

439 False 

440 

441 """ 

442 if isinstance(other, Set): 

443 return self != other and self.is_subset(other) 

444 else: 

445 raise ValueError("Unknown argument '%s'" % other) 

446 

447 def is_superset(self, other): 

448 """ 

449 Returns True if ``self`` is a superset of ``other``. 

450 

451 Examples 

452 ======== 

453 

454 >>> from sympy import Interval 

455 >>> Interval(0, 0.5).is_superset(Interval(0, 1)) 

456 False 

457 >>> Interval(0, 1).is_superset(Interval(0, 1, left_open=True)) 

458 True 

459 

460 """ 

461 if isinstance(other, Set): 

462 return other.is_subset(self) 

463 else: 

464 raise ValueError("Unknown argument '%s'" % other) 

465 

466 # This should be deprecated: 

467 def issuperset(self, other): 

468 """ 

469 Alias for :meth:`is_superset()` 

470 """ 

471 return self.is_superset(other) 

472 

473 def is_proper_superset(self, other): 

474 """ 

475 Returns True if ``self`` is a proper superset of ``other``. 

476 

477 Examples 

478 ======== 

479 

480 >>> from sympy import Interval 

481 >>> Interval(0, 1).is_proper_superset(Interval(0, 0.5)) 

482 True 

483 >>> Interval(0, 1).is_proper_superset(Interval(0, 1)) 

484 False 

485 

486 """ 

487 if isinstance(other, Set): 

488 return self != other and self.is_superset(other) 

489 else: 

490 raise ValueError("Unknown argument '%s'" % other) 

491 

492 def _eval_powerset(self): 

493 from .powerset import PowerSet 

494 return PowerSet(self) 

495 

496 def powerset(self): 

497 """ 

498 Find the Power set of ``self``. 

499 

500 Examples 

501 ======== 

502 

503 >>> from sympy import EmptySet, FiniteSet, Interval 

504 

505 A power set of an empty set: 

506 

507 >>> A = EmptySet 

508 >>> A.powerset() 

509 {EmptySet} 

510 

511 A power set of a finite set: 

512 

513 >>> A = FiniteSet(1, 2) 

514 >>> a, b, c = FiniteSet(1), FiniteSet(2), FiniteSet(1, 2) 

515 >>> A.powerset() == FiniteSet(a, b, c, EmptySet) 

516 True 

517 

518 A power set of an interval: 

519 

520 >>> Interval(1, 2).powerset() 

521 PowerSet(Interval(1, 2)) 

522 

523 References 

524 ========== 

525 

526 .. [1] https://en.wikipedia.org/wiki/Power_set 

527 

528 """ 

529 return self._eval_powerset() 

530 

531 @property 

532 def measure(self): 

533 """ 

534 The (Lebesgue) measure of ``self``. 

535 

536 Examples 

537 ======== 

538 

539 >>> from sympy import Interval, Union 

540 >>> Interval(0, 1).measure 

541 1 

542 >>> Union(Interval(0, 1), Interval(2, 3)).measure 

543 2 

544 

545 """ 

546 return self._measure 

547 

548 @property 

549 def kind(self): 

550 """ 

551 The kind of a Set 

552 

553 Explanation 

554 =========== 

555 

556 Any :class:`Set` will have kind :class:`SetKind` which is 

557 parametrised by the kind of the elements of the set. For example 

558 most sets are sets of numbers and will have kind 

559 ``SetKind(NumberKind)``. If elements of sets are different in kind than 

560 their kind will ``SetKind(UndefinedKind)``. See 

561 :class:`sympy.core.kind.Kind` for an explanation of the kind system. 

562 

563 Examples 

564 ======== 

565 

566 >>> from sympy import Interval, Matrix, FiniteSet, EmptySet, ProductSet, PowerSet 

567 

568 >>> FiniteSet(Matrix([1, 2])).kind 

569 SetKind(MatrixKind(NumberKind)) 

570 

571 >>> Interval(1, 2).kind 

572 SetKind(NumberKind) 

573 

574 >>> EmptySet.kind 

575 SetKind() 

576 

577 A :class:`sympy.sets.powerset.PowerSet` is a set of sets: 

578 

579 >>> PowerSet({1, 2, 3}).kind 

580 SetKind(SetKind(NumberKind)) 

581 

582 A :class:`ProductSet` represents the set of tuples of elements of 

583 other sets. Its kind is :class:`sympy.core.containers.TupleKind` 

584 parametrised by the kinds of the elements of those sets: 

585 

586 >>> p = ProductSet(FiniteSet(1, 2), FiniteSet(3, 4)) 

587 >>> list(p) 

588 [(1, 3), (2, 3), (1, 4), (2, 4)] 

589 >>> p.kind 

590 SetKind(TupleKind(NumberKind, NumberKind)) 

591 

592 When all elements of the set do not have same kind, the kind 

593 will be returned as ``SetKind(UndefinedKind)``: 

594 

595 >>> FiniteSet(0, Matrix([1, 2])).kind 

596 SetKind(UndefinedKind) 

597 

598 The kind of the elements of a set are given by the ``element_kind`` 

599 attribute of ``SetKind``: 

600 

601 >>> Interval(1, 2).kind.element_kind 

602 NumberKind 

603 

604 See Also 

605 ======== 

606 

607 NumberKind 

608 sympy.core.kind.UndefinedKind 

609 sympy.core.containers.TupleKind 

610 MatrixKind 

611 sympy.matrices.expressions.sets.MatrixSet 

612 sympy.sets.conditionset.ConditionSet 

613 Rationals 

614 Naturals 

615 Integers 

616 sympy.sets.fancysets.ImageSet 

617 sympy.sets.fancysets.Range 

618 sympy.sets.fancysets.ComplexRegion 

619 sympy.sets.powerset.PowerSet 

620 sympy.sets.sets.ProductSet 

621 sympy.sets.sets.Interval 

622 sympy.sets.sets.Union 

623 sympy.sets.sets.Intersection 

624 sympy.sets.sets.Complement 

625 sympy.sets.sets.EmptySet 

626 sympy.sets.sets.UniversalSet 

627 sympy.sets.sets.FiniteSet 

628 sympy.sets.sets.SymmetricDifference 

629 sympy.sets.sets.DisjointUnion 

630 """ 

631 return self._kind() 

632 

633 @property 

634 def boundary(self): 

635 """ 

636 The boundary or frontier of a set. 

637 

638 Explanation 

639 =========== 

640 

641 A point x is on the boundary of a set S if 

642 

643 1. x is in the closure of S. 

644 I.e. Every neighborhood of x contains a point in S. 

645 2. x is not in the interior of S. 

646 I.e. There does not exist an open set centered on x contained 

647 entirely within S. 

648 

649 There are the points on the outer rim of S. If S is open then these 

650 points need not actually be contained within S. 

651 

652 For example, the boundary of an interval is its start and end points. 

653 This is true regardless of whether or not the interval is open. 

654 

655 Examples 

656 ======== 

657 

658 >>> from sympy import Interval 

659 >>> Interval(0, 1).boundary 

660 {0, 1} 

661 >>> Interval(0, 1, True, False).boundary 

662 {0, 1} 

663 """ 

664 return self._boundary 

665 

666 @property 

667 def is_open(self): 

668 """ 

669 Property method to check whether a set is open. 

670 

671 Explanation 

672 =========== 

673 

674 A set is open if and only if it has an empty intersection with its 

675 boundary. In particular, a subset A of the reals is open if and only 

676 if each one of its points is contained in an open interval that is a 

677 subset of A. 

678 

679 Examples 

680 ======== 

681 >>> from sympy import S 

682 >>> S.Reals.is_open 

683 True 

684 >>> S.Rationals.is_open 

685 False 

686 """ 

687 return Intersection(self, self.boundary).is_empty 

688 

689 @property 

690 def is_closed(self): 

691 """ 

692 A property method to check whether a set is closed. 

693 

694 Explanation 

695 =========== 

696 

697 A set is closed if its complement is an open set. The closedness of a 

698 subset of the reals is determined with respect to R and its standard 

699 topology. 

700 

701 Examples 

702 ======== 

703 >>> from sympy import Interval 

704 >>> Interval(0, 1).is_closed 

705 True 

706 """ 

707 return self.boundary.is_subset(self) 

708 

709 @property 

710 def closure(self): 

711 """ 

712 Property method which returns the closure of a set. 

713 The closure is defined as the union of the set itself and its 

714 boundary. 

715 

716 Examples 

717 ======== 

718 >>> from sympy import S, Interval 

719 >>> S.Reals.closure 

720 Reals 

721 >>> Interval(0, 1).closure 

722 Interval(0, 1) 

723 """ 

724 return self + self.boundary 

725 

726 @property 

727 def interior(self): 

728 """ 

729 Property method which returns the interior of a set. 

730 The interior of a set S consists all points of S that do not 

731 belong to the boundary of S. 

732 

733 Examples 

734 ======== 

735 >>> from sympy import Interval 

736 >>> Interval(0, 1).interior 

737 Interval.open(0, 1) 

738 >>> Interval(0, 1).boundary.interior 

739 EmptySet 

740 """ 

741 return self - self.boundary 

742 

743 @property 

744 def _boundary(self): 

745 raise NotImplementedError() 

746 

747 @property 

748 def _measure(self): 

749 raise NotImplementedError("(%s)._measure" % self) 

750 

751 def _kind(self): 

752 return SetKind(UndefinedKind) 

753 

754 def _eval_evalf(self, prec): 

755 dps = prec_to_dps(prec) 

756 return self.func(*[arg.evalf(n=dps) for arg in self.args]) 

757 

758 @sympify_return([('other', 'Set')], NotImplemented) 

759 def __add__(self, other): 

760 return self.union(other) 

761 

762 @sympify_return([('other', 'Set')], NotImplemented) 

763 def __or__(self, other): 

764 return self.union(other) 

765 

766 @sympify_return([('other', 'Set')], NotImplemented) 

767 def __and__(self, other): 

768 return self.intersect(other) 

769 

770 @sympify_return([('other', 'Set')], NotImplemented) 

771 def __mul__(self, other): 

772 return ProductSet(self, other) 

773 

774 @sympify_return([('other', 'Set')], NotImplemented) 

775 def __xor__(self, other): 

776 return SymmetricDifference(self, other) 

777 

778 @sympify_return([('exp', Expr)], NotImplemented) 

779 def __pow__(self, exp): 

780 if not (exp.is_Integer and exp >= 0): 

781 raise ValueError("%s: Exponent must be a positive Integer" % exp) 

782 return ProductSet(*[self]*exp) 

783 

784 @sympify_return([('other', 'Set')], NotImplemented) 

785 def __sub__(self, other): 

786 return Complement(self, other) 

787 

788 def __contains__(self, other): 

789 other = _sympify(other) 

790 c = self._contains(other) 

791 b = tfn[c] 

792 if b is None: 

793 # x in y must evaluate to T or F; to entertain a None 

794 # result with Set use y.contains(x) 

795 raise TypeError('did not evaluate to a bool: %r' % c) 

796 return b 

797 

798 

799class ProductSet(Set): 

800 """ 

801 Represents a Cartesian Product of Sets. 

802 

803 Explanation 

804 =========== 

805 

806 Returns a Cartesian product given several sets as either an iterable 

807 or individual arguments. 

808 

809 Can use ``*`` operator on any sets for convenient shorthand. 

810 

811 Examples 

812 ======== 

813 

814 >>> from sympy import Interval, FiniteSet, ProductSet 

815 >>> I = Interval(0, 5); S = FiniteSet(1, 2, 3) 

816 >>> ProductSet(I, S) 

817 ProductSet(Interval(0, 5), {1, 2, 3}) 

818 

819 >>> (2, 2) in ProductSet(I, S) 

820 True 

821 

822 >>> Interval(0, 1) * Interval(0, 1) # The unit square 

823 ProductSet(Interval(0, 1), Interval(0, 1)) 

824 

825 >>> coin = FiniteSet('H', 'T') 

826 >>> set(coin**2) 

827 {(H, H), (H, T), (T, H), (T, T)} 

828 

829 The Cartesian product is not commutative or associative e.g.: 

830 

831 >>> I*S == S*I 

832 False 

833 >>> (I*I)*I == I*(I*I) 

834 False 

835 

836 Notes 

837 ===== 

838 

839 - Passes most operations down to the argument sets 

840 

841 References 

842 ========== 

843 

844 .. [1] https://en.wikipedia.org/wiki/Cartesian_product 

845 """ 

846 is_ProductSet = True 

847 

848 def __new__(cls, *sets, **assumptions): 

849 if len(sets) == 1 and iterable(sets[0]) and not isinstance(sets[0], (Set, set)): 

850 sympy_deprecation_warning( 

851 """ 

852ProductSet(iterable) is deprecated. Use ProductSet(*iterable) instead. 

853 """, 

854 deprecated_since_version="1.5", 

855 active_deprecations_target="deprecated-productset-iterable", 

856 ) 

857 sets = tuple(sets[0]) 

858 

859 sets = [sympify(s) for s in sets] 

860 

861 if not all(isinstance(s, Set) for s in sets): 

862 raise TypeError("Arguments to ProductSet should be of type Set") 

863 

864 # Nullary product of sets is *not* the empty set 

865 if len(sets) == 0: 

866 return FiniteSet(()) 

867 

868 if S.EmptySet in sets: 

869 return S.EmptySet 

870 

871 return Basic.__new__(cls, *sets, **assumptions) 

872 

873 @property 

874 def sets(self): 

875 return self.args 

876 

877 def flatten(self): 

878 def _flatten(sets): 

879 for s in sets: 

880 if s.is_ProductSet: 

881 yield from _flatten(s.sets) 

882 else: 

883 yield s 

884 return ProductSet(*_flatten(self.sets)) 

885 

886 

887 

888 def _contains(self, element): 

889 """ 

890 ``in`` operator for ProductSets. 

891 

892 Examples 

893 ======== 

894 

895 >>> from sympy import Interval 

896 >>> (2, 3) in Interval(0, 5) * Interval(0, 5) 

897 True 

898 

899 >>> (10, 10) in Interval(0, 5) * Interval(0, 5) 

900 False 

901 

902 Passes operation on to constituent sets 

903 """ 

904 if element.is_Symbol: 

905 return None 

906 

907 if not isinstance(element, Tuple) or len(element) != len(self.sets): 

908 return False 

909 

910 return fuzzy_and(s._contains(e) for s, e in zip(self.sets, element)) 

911 

912 def as_relational(self, *symbols): 

913 symbols = [_sympify(s) for s in symbols] 

914 if len(symbols) != len(self.sets) or not all( 

915 i.is_Symbol for i in symbols): 

916 raise ValueError( 

917 'number of symbols must match the number of sets') 

918 return And(*[s.as_relational(i) for s, i in zip(self.sets, symbols)]) 

919 

920 @property 

921 def _boundary(self): 

922 return Union(*(ProductSet(*(b + b.boundary if i != j else b.boundary 

923 for j, b in enumerate(self.sets))) 

924 for i, a in enumerate(self.sets))) 

925 

926 @property 

927 def is_iterable(self): 

928 """ 

929 A property method which tests whether a set is iterable or not. 

930 Returns True if set is iterable, otherwise returns False. 

931 

932 Examples 

933 ======== 

934 

935 >>> from sympy import FiniteSet, Interval 

936 >>> I = Interval(0, 1) 

937 >>> A = FiniteSet(1, 2, 3, 4, 5) 

938 >>> I.is_iterable 

939 False 

940 >>> A.is_iterable 

941 True 

942 

943 """ 

944 return all(set.is_iterable for set in self.sets) 

945 

946 def __iter__(self): 

947 """ 

948 A method which implements is_iterable property method. 

949 If self.is_iterable returns True (both constituent sets are iterable), 

950 then return the Cartesian Product. Otherwise, raise TypeError. 

951 """ 

952 return iproduct(*self.sets) 

953 

954 @property 

955 def is_empty(self): 

956 return fuzzy_or(s.is_empty for s in self.sets) 

957 

958 @property 

959 def is_finite_set(self): 

960 all_finite = fuzzy_and(s.is_finite_set for s in self.sets) 

961 return fuzzy_or([self.is_empty, all_finite]) 

962 

963 @property 

964 def _measure(self): 

965 measure = 1 

966 for s in self.sets: 

967 measure *= s.measure 

968 return measure 

969 

970 def _kind(self): 

971 return SetKind(TupleKind(*(i.kind.element_kind for i in self.args))) 

972 

973 def __len__(self): 

974 return reduce(lambda a, b: a*b, (len(s) for s in self.args)) 

975 

976 def __bool__(self): 

977 return all(self.sets) 

978 

979 

980class Interval(Set): 

981 """ 

982 Represents a real interval as a Set. 

983 

984 Usage: 

985 Returns an interval with end points ``start`` and ``end``. 

986 

987 For ``left_open=True`` (default ``left_open`` is ``False``) the interval 

988 will be open on the left. Similarly, for ``right_open=True`` the interval 

989 will be open on the right. 

990 

991 Examples 

992 ======== 

993 

994 >>> from sympy import Symbol, Interval 

995 >>> Interval(0, 1) 

996 Interval(0, 1) 

997 >>> Interval.Ropen(0, 1) 

998 Interval.Ropen(0, 1) 

999 >>> Interval.Ropen(0, 1) 

1000 Interval.Ropen(0, 1) 

1001 >>> Interval.Lopen(0, 1) 

1002 Interval.Lopen(0, 1) 

1003 >>> Interval.open(0, 1) 

1004 Interval.open(0, 1) 

1005 

1006 >>> a = Symbol('a', real=True) 

1007 >>> Interval(0, a) 

1008 Interval(0, a) 

1009 

1010 Notes 

1011 ===== 

1012 - Only real end points are supported 

1013 - ``Interval(a, b)`` with $a > b$ will return the empty set 

1014 - Use the ``evalf()`` method to turn an Interval into an mpmath 

1015 ``mpi`` interval instance 

1016 

1017 References 

1018 ========== 

1019 

1020 .. [1] https://en.wikipedia.org/wiki/Interval_%28mathematics%29 

1021 """ 

1022 is_Interval = True 

1023 

1024 def __new__(cls, start, end, left_open=False, right_open=False): 

1025 

1026 start = _sympify(start) 

1027 end = _sympify(end) 

1028 left_open = _sympify(left_open) 

1029 right_open = _sympify(right_open) 

1030 

1031 if not all(isinstance(a, (type(true), type(false))) 

1032 for a in [left_open, right_open]): 

1033 raise NotImplementedError( 

1034 "left_open and right_open can have only true/false values, " 

1035 "got %s and %s" % (left_open, right_open)) 

1036 

1037 # Only allow real intervals 

1038 if fuzzy_not(fuzzy_and(i.is_extended_real for i in (start, end, end-start))): 

1039 raise ValueError("Non-real intervals are not supported") 

1040 

1041 # evaluate if possible 

1042 if is_lt(end, start): 

1043 return S.EmptySet 

1044 elif (end - start).is_negative: 

1045 return S.EmptySet 

1046 

1047 if end == start and (left_open or right_open): 

1048 return S.EmptySet 

1049 if end == start and not (left_open or right_open): 

1050 if start is S.Infinity or start is S.NegativeInfinity: 

1051 return S.EmptySet 

1052 return FiniteSet(end) 

1053 

1054 # Make sure infinite interval end points are open. 

1055 if start is S.NegativeInfinity: 

1056 left_open = true 

1057 if end is S.Infinity: 

1058 right_open = true 

1059 if start == S.Infinity or end == S.NegativeInfinity: 

1060 return S.EmptySet 

1061 

1062 return Basic.__new__(cls, start, end, left_open, right_open) 

1063 

1064 @property 

1065 def start(self): 

1066 """ 

1067 The left end point of the interval. 

1068 

1069 This property takes the same value as the ``inf`` property. 

1070 

1071 Examples 

1072 ======== 

1073 

1074 >>> from sympy import Interval 

1075 >>> Interval(0, 1).start 

1076 0 

1077 

1078 """ 

1079 return self._args[0] 

1080 

1081 @property 

1082 def end(self): 

1083 """ 

1084 The right end point of the interval. 

1085 

1086 This property takes the same value as the ``sup`` property. 

1087 

1088 Examples 

1089 ======== 

1090 

1091 >>> from sympy import Interval 

1092 >>> Interval(0, 1).end 

1093 1 

1094 

1095 """ 

1096 return self._args[1] 

1097 

1098 @property 

1099 def left_open(self): 

1100 """ 

1101 True if interval is left-open. 

1102 

1103 Examples 

1104 ======== 

1105 

1106 >>> from sympy import Interval 

1107 >>> Interval(0, 1, left_open=True).left_open 

1108 True 

1109 >>> Interval(0, 1, left_open=False).left_open 

1110 False 

1111 

1112 """ 

1113 return self._args[2] 

1114 

1115 @property 

1116 def right_open(self): 

1117 """ 

1118 True if interval is right-open. 

1119 

1120 Examples 

1121 ======== 

1122 

1123 >>> from sympy import Interval 

1124 >>> Interval(0, 1, right_open=True).right_open 

1125 True 

1126 >>> Interval(0, 1, right_open=False).right_open 

1127 False 

1128 

1129 """ 

1130 return self._args[3] 

1131 

1132 @classmethod 

1133 def open(cls, a, b): 

1134 """Return an interval including neither boundary.""" 

1135 return cls(a, b, True, True) 

1136 

1137 @classmethod 

1138 def Lopen(cls, a, b): 

1139 """Return an interval not including the left boundary.""" 

1140 return cls(a, b, True, False) 

1141 

1142 @classmethod 

1143 def Ropen(cls, a, b): 

1144 """Return an interval not including the right boundary.""" 

1145 return cls(a, b, False, True) 

1146 

1147 @property 

1148 def _inf(self): 

1149 return self.start 

1150 

1151 @property 

1152 def _sup(self): 

1153 return self.end 

1154 

1155 @property 

1156 def left(self): 

1157 return self.start 

1158 

1159 @property 

1160 def right(self): 

1161 return self.end 

1162 

1163 @property 

1164 def is_empty(self): 

1165 if self.left_open or self.right_open: 

1166 cond = self.start >= self.end # One/both bounds open 

1167 else: 

1168 cond = self.start > self.end # Both bounds closed 

1169 return fuzzy_bool(cond) 

1170 

1171 @property 

1172 def is_finite_set(self): 

1173 return self.measure.is_zero 

1174 

1175 def _complement(self, other): 

1176 if other == S.Reals: 

1177 a = Interval(S.NegativeInfinity, self.start, 

1178 True, not self.left_open) 

1179 b = Interval(self.end, S.Infinity, not self.right_open, True) 

1180 return Union(a, b) 

1181 

1182 if isinstance(other, FiniteSet): 

1183 nums = [m for m in other.args if m.is_number] 

1184 if nums == []: 

1185 return None 

1186 

1187 return Set._complement(self, other) 

1188 

1189 @property 

1190 def _boundary(self): 

1191 finite_points = [p for p in (self.start, self.end) 

1192 if abs(p) != S.Infinity] 

1193 return FiniteSet(*finite_points) 

1194 

1195 def _contains(self, other): 

1196 if (not isinstance(other, Expr) or other is S.NaN 

1197 or other.is_real is False or other.has(S.ComplexInfinity)): 

1198 # if an expression has zoo it will be zoo or nan 

1199 # and neither of those is real 

1200 return false 

1201 

1202 if self.start is S.NegativeInfinity and self.end is S.Infinity: 

1203 if other.is_real is not None: 

1204 return other.is_real 

1205 

1206 d = Dummy() 

1207 return self.as_relational(d).subs(d, other) 

1208 

1209 def as_relational(self, x): 

1210 """Rewrite an interval in terms of inequalities and logic operators.""" 

1211 x = sympify(x) 

1212 if self.right_open: 

1213 right = x < self.end 

1214 else: 

1215 right = x <= self.end 

1216 if self.left_open: 

1217 left = self.start < x 

1218 else: 

1219 left = self.start <= x 

1220 return And(left, right) 

1221 

1222 @property 

1223 def _measure(self): 

1224 return self.end - self.start 

1225 

1226 def _kind(self): 

1227 return SetKind(NumberKind) 

1228 

1229 def to_mpi(self, prec=53): 

1230 return mpi(mpf(self.start._eval_evalf(prec)), 

1231 mpf(self.end._eval_evalf(prec))) 

1232 

1233 def _eval_evalf(self, prec): 

1234 return Interval(self.left._evalf(prec), self.right._evalf(prec), 

1235 left_open=self.left_open, right_open=self.right_open) 

1236 

1237 def _is_comparable(self, other): 

1238 is_comparable = self.start.is_comparable 

1239 is_comparable &= self.end.is_comparable 

1240 is_comparable &= other.start.is_comparable 

1241 is_comparable &= other.end.is_comparable 

1242 

1243 return is_comparable 

1244 

1245 @property 

1246 def is_left_unbounded(self): 

1247 """Return ``True`` if the left endpoint is negative infinity. """ 

1248 return self.left is S.NegativeInfinity or self.left == Float("-inf") 

1249 

1250 @property 

1251 def is_right_unbounded(self): 

1252 """Return ``True`` if the right endpoint is positive infinity. """ 

1253 return self.right is S.Infinity or self.right == Float("+inf") 

1254 

1255 def _eval_Eq(self, other): 

1256 if not isinstance(other, Interval): 

1257 if isinstance(other, FiniteSet): 

1258 return false 

1259 elif isinstance(other, Set): 

1260 return None 

1261 return false 

1262 

1263 

1264class Union(Set, LatticeOp): 

1265 """ 

1266 Represents a union of sets as a :class:`Set`. 

1267 

1268 Examples 

1269 ======== 

1270 

1271 >>> from sympy import Union, Interval 

1272 >>> Union(Interval(1, 2), Interval(3, 4)) 

1273 Union(Interval(1, 2), Interval(3, 4)) 

1274 

1275 The Union constructor will always try to merge overlapping intervals, 

1276 if possible. For example: 

1277 

1278 >>> Union(Interval(1, 2), Interval(2, 3)) 

1279 Interval(1, 3) 

1280 

1281 See Also 

1282 ======== 

1283 

1284 Intersection 

1285 

1286 References 

1287 ========== 

1288 

1289 .. [1] https://en.wikipedia.org/wiki/Union_%28set_theory%29 

1290 """ 

1291 is_Union = True 

1292 

1293 @property 

1294 def identity(self): 

1295 return S.EmptySet 

1296 

1297 @property 

1298 def zero(self): 

1299 return S.UniversalSet 

1300 

1301 def __new__(cls, *args, **kwargs): 

1302 evaluate = kwargs.get('evaluate', global_parameters.evaluate) 

1303 

1304 # flatten inputs to merge intersections and iterables 

1305 args = _sympify(args) 

1306 

1307 # Reduce sets using known rules 

1308 if evaluate: 

1309 args = list(cls._new_args_filter(args)) 

1310 return simplify_union(args) 

1311 

1312 args = list(ordered(args, Set._infimum_key)) 

1313 

1314 obj = Basic.__new__(cls, *args) 

1315 obj._argset = frozenset(args) 

1316 return obj 

1317 

1318 @property 

1319 def args(self): 

1320 return self._args 

1321 

1322 def _complement(self, universe): 

1323 # DeMorgan's Law 

1324 return Intersection(s.complement(universe) for s in self.args) 

1325 

1326 @property 

1327 def _inf(self): 

1328 # We use Min so that sup is meaningful in combination with symbolic 

1329 # interval end points. 

1330 return Min(*[set.inf for set in self.args]) 

1331 

1332 @property 

1333 def _sup(self): 

1334 # We use Max so that sup is meaningful in combination with symbolic 

1335 # end points. 

1336 return Max(*[set.sup for set in self.args]) 

1337 

1338 @property 

1339 def is_empty(self): 

1340 return fuzzy_and(set.is_empty for set in self.args) 

1341 

1342 @property 

1343 def is_finite_set(self): 

1344 return fuzzy_and(set.is_finite_set for set in self.args) 

1345 

1346 @property 

1347 def _measure(self): 

1348 # Measure of a union is the sum of the measures of the sets minus 

1349 # the sum of their pairwise intersections plus the sum of their 

1350 # triple-wise intersections minus ... etc... 

1351 

1352 # Sets is a collection of intersections and a set of elementary 

1353 # sets which made up those intersections (called "sos" for set of sets) 

1354 # An example element might of this list might be: 

1355 # ( {A,B,C}, A.intersect(B).intersect(C) ) 

1356 

1357 # Start with just elementary sets ( ({A}, A), ({B}, B), ... ) 

1358 # Then get and subtract ( ({A,B}, (A int B), ... ) while non-zero 

1359 sets = [(FiniteSet(s), s) for s in self.args] 

1360 measure = 0 

1361 parity = 1 

1362 while sets: 

1363 # Add up the measure of these sets and add or subtract it to total 

1364 measure += parity * sum(inter.measure for sos, inter in sets) 

1365 

1366 # For each intersection in sets, compute the intersection with every 

1367 # other set not already part of the intersection. 

1368 sets = ((sos + FiniteSet(newset), newset.intersect(intersection)) 

1369 for sos, intersection in sets for newset in self.args 

1370 if newset not in sos) 

1371 

1372 # Clear out sets with no measure 

1373 sets = [(sos, inter) for sos, inter in sets if inter.measure != 0] 

1374 

1375 # Clear out duplicates 

1376 sos_list = [] 

1377 sets_list = [] 

1378 for _set in sets: 

1379 if _set[0] in sos_list: 

1380 continue 

1381 else: 

1382 sos_list.append(_set[0]) 

1383 sets_list.append(_set) 

1384 sets = sets_list 

1385 

1386 # Flip Parity - next time subtract/add if we added/subtracted here 

1387 parity *= -1 

1388 return measure 

1389 

1390 def _kind(self): 

1391 kinds = tuple(arg.kind for arg in self.args if arg is not S.EmptySet) 

1392 if not kinds: 

1393 return SetKind() 

1394 elif all(i == kinds[0] for i in kinds): 

1395 return kinds[0] 

1396 else: 

1397 return SetKind(UndefinedKind) 

1398 

1399 @property 

1400 def _boundary(self): 

1401 def boundary_of_set(i): 

1402 """ The boundary of set i minus interior of all other sets """ 

1403 b = self.args[i].boundary 

1404 for j, a in enumerate(self.args): 

1405 if j != i: 

1406 b = b - a.interior 

1407 return b 

1408 return Union(*map(boundary_of_set, range(len(self.args)))) 

1409 

1410 def _contains(self, other): 

1411 return Or(*[s.contains(other) for s in self.args]) 

1412 

1413 def is_subset(self, other): 

1414 return fuzzy_and(s.is_subset(other) for s in self.args) 

1415 

1416 def as_relational(self, symbol): 

1417 """Rewrite a Union in terms of equalities and logic operators. """ 

1418 if (len(self.args) == 2 and 

1419 all(isinstance(i, Interval) for i in self.args)): 

1420 # optimization to give 3 args as (x > 1) & (x < 5) & Ne(x, 3) 

1421 # instead of as 4, ((1 <= x) & (x < 3)) | ((x <= 5) & (3 < x)) 

1422 # XXX: This should be ideally be improved to handle any number of 

1423 # intervals and also not to assume that the intervals are in any 

1424 # particular sorted order. 

1425 a, b = self.args 

1426 if a.sup == b.inf and a.right_open and b.left_open: 

1427 mincond = symbol > a.inf if a.left_open else symbol >= a.inf 

1428 maxcond = symbol < b.sup if b.right_open else symbol <= b.sup 

1429 necond = Ne(symbol, a.sup) 

1430 return And(necond, mincond, maxcond) 

1431 return Or(*[i.as_relational(symbol) for i in self.args]) 

1432 

1433 @property 

1434 def is_iterable(self): 

1435 return all(arg.is_iterable for arg in self.args) 

1436 

1437 def __iter__(self): 

1438 return roundrobin(*(iter(arg) for arg in self.args)) 

1439 

1440 

1441class Intersection(Set, LatticeOp): 

1442 """ 

1443 Represents an intersection of sets as a :class:`Set`. 

1444 

1445 Examples 

1446 ======== 

1447 

1448 >>> from sympy import Intersection, Interval 

1449 >>> Intersection(Interval(1, 3), Interval(2, 4)) 

1450 Interval(2, 3) 

1451 

1452 We often use the .intersect method 

1453 

1454 >>> Interval(1,3).intersect(Interval(2,4)) 

1455 Interval(2, 3) 

1456 

1457 See Also 

1458 ======== 

1459 

1460 Union 

1461 

1462 References 

1463 ========== 

1464 

1465 .. [1] https://en.wikipedia.org/wiki/Intersection_%28set_theory%29 

1466 """ 

1467 is_Intersection = True 

1468 

1469 @property 

1470 def identity(self): 

1471 return S.UniversalSet 

1472 

1473 @property 

1474 def zero(self): 

1475 return S.EmptySet 

1476 

1477 def __new__(cls, *args, **kwargs): 

1478 evaluate = kwargs.get('evaluate', global_parameters.evaluate) 

1479 

1480 # flatten inputs to merge intersections and iterables 

1481 args = list(ordered(set(_sympify(args)))) 

1482 

1483 # Reduce sets using known rules 

1484 if evaluate: 

1485 args = list(cls._new_args_filter(args)) 

1486 return simplify_intersection(args) 

1487 

1488 args = list(ordered(args, Set._infimum_key)) 

1489 

1490 obj = Basic.__new__(cls, *args) 

1491 obj._argset = frozenset(args) 

1492 return obj 

1493 

1494 @property 

1495 def args(self): 

1496 return self._args 

1497 

1498 @property 

1499 def is_iterable(self): 

1500 return any(arg.is_iterable for arg in self.args) 

1501 

1502 @property 

1503 def is_finite_set(self): 

1504 if fuzzy_or(arg.is_finite_set for arg in self.args): 

1505 return True 

1506 

1507 def _kind(self): 

1508 kinds = tuple(arg.kind for arg in self.args if arg is not S.UniversalSet) 

1509 if not kinds: 

1510 return SetKind(UndefinedKind) 

1511 elif all(i == kinds[0] for i in kinds): 

1512 return kinds[0] 

1513 else: 

1514 return SetKind() 

1515 

1516 @property 

1517 def _inf(self): 

1518 raise NotImplementedError() 

1519 

1520 @property 

1521 def _sup(self): 

1522 raise NotImplementedError() 

1523 

1524 def _contains(self, other): 

1525 return And(*[set.contains(other) for set in self.args]) 

1526 

1527 def __iter__(self): 

1528 sets_sift = sift(self.args, lambda x: x.is_iterable) 

1529 

1530 completed = False 

1531 candidates = sets_sift[True] + sets_sift[None] 

1532 

1533 finite_candidates, others = [], [] 

1534 for candidate in candidates: 

1535 length = None 

1536 try: 

1537 length = len(candidate) 

1538 except TypeError: 

1539 others.append(candidate) 

1540 

1541 if length is not None: 

1542 finite_candidates.append(candidate) 

1543 finite_candidates.sort(key=len) 

1544 

1545 for s in finite_candidates + others: 

1546 other_sets = set(self.args) - {s} 

1547 other = Intersection(*other_sets, evaluate=False) 

1548 completed = True 

1549 for x in s: 

1550 try: 

1551 if x in other: 

1552 yield x 

1553 except TypeError: 

1554 completed = False 

1555 if completed: 

1556 return 

1557 

1558 if not completed: 

1559 if not candidates: 

1560 raise TypeError("None of the constituent sets are iterable") 

1561 raise TypeError( 

1562 "The computation had not completed because of the " 

1563 "undecidable set membership is found in every candidates.") 

1564 

1565 @staticmethod 

1566 def _handle_finite_sets(args): 

1567 '''Simplify intersection of one or more FiniteSets and other sets''' 

1568 

1569 # First separate the FiniteSets from the others 

1570 fs_args, others = sift(args, lambda x: x.is_FiniteSet, binary=True) 

1571 

1572 # Let the caller handle intersection of non-FiniteSets 

1573 if not fs_args: 

1574 return 

1575 

1576 # Convert to Python sets and build the set of all elements 

1577 fs_sets = [set(fs) for fs in fs_args] 

1578 all_elements = reduce(lambda a, b: a | b, fs_sets, set()) 

1579 

1580 # Extract elements that are definitely in or definitely not in the 

1581 # intersection. Here we check contains for all of args. 

1582 definite = set() 

1583 for e in all_elements: 

1584 inall = fuzzy_and(s.contains(e) for s in args) 

1585 if inall is True: 

1586 definite.add(e) 

1587 if inall is not None: 

1588 for s in fs_sets: 

1589 s.discard(e) 

1590 

1591 # At this point all elements in all of fs_sets are possibly in the 

1592 # intersection. In some cases this is because they are definitely in 

1593 # the intersection of the finite sets but it's not clear if they are 

1594 # members of others. We might have {m, n}, {m}, and Reals where we 

1595 # don't know if m or n is real. We want to remove n here but it is 

1596 # possibly in because it might be equal to m. So what we do now is 

1597 # extract the elements that are definitely in the remaining finite 

1598 # sets iteratively until we end up with {n}, {}. At that point if we 

1599 # get any empty set all remaining elements are discarded. 

1600 

1601 fs_elements = reduce(lambda a, b: a | b, fs_sets, set()) 

1602 

1603 # Need fuzzy containment testing 

1604 fs_symsets = [FiniteSet(*s) for s in fs_sets] 

1605 

1606 while fs_elements: 

1607 for e in fs_elements: 

1608 infs = fuzzy_and(s.contains(e) for s in fs_symsets) 

1609 if infs is True: 

1610 definite.add(e) 

1611 if infs is not None: 

1612 for n, s in enumerate(fs_sets): 

1613 # Update Python set and FiniteSet 

1614 if e in s: 

1615 s.remove(e) 

1616 fs_symsets[n] = FiniteSet(*s) 

1617 fs_elements.remove(e) 

1618 break 

1619 # If we completed the for loop without removing anything we are 

1620 # done so quit the outer while loop 

1621 else: 

1622 break 

1623 

1624 # If any of the sets of remainder elements is empty then we discard 

1625 # all of them for the intersection. 

1626 if not all(fs_sets): 

1627 fs_sets = [set()] 

1628 

1629 # Here we fold back the definitely included elements into each fs. 

1630 # Since they are definitely included they must have been members of 

1631 # each FiniteSet to begin with. We could instead fold these in with a 

1632 # Union at the end to get e.g. {3}|({x}&{y}) rather than {3,x}&{3,y}. 

1633 if definite: 

1634 fs_sets = [fs | definite for fs in fs_sets] 

1635 

1636 if fs_sets == [set()]: 

1637 return S.EmptySet 

1638 

1639 sets = [FiniteSet(*s) for s in fs_sets] 

1640 

1641 # Any set in others is redundant if it contains all the elements that 

1642 # are in the finite sets so we don't need it in the Intersection 

1643 all_elements = reduce(lambda a, b: a | b, fs_sets, set()) 

1644 is_redundant = lambda o: all(fuzzy_bool(o.contains(e)) for e in all_elements) 

1645 others = [o for o in others if not is_redundant(o)] 

1646 

1647 if others: 

1648 rest = Intersection(*others) 

1649 # XXX: Maybe this shortcut should be at the beginning. For large 

1650 # FiniteSets it could much more efficient to process the other 

1651 # sets first... 

1652 if rest is S.EmptySet: 

1653 return S.EmptySet 

1654 # Flatten the Intersection 

1655 if rest.is_Intersection: 

1656 sets.extend(rest.args) 

1657 else: 

1658 sets.append(rest) 

1659 

1660 if len(sets) == 1: 

1661 return sets[0] 

1662 else: 

1663 return Intersection(*sets, evaluate=False) 

1664 

1665 def as_relational(self, symbol): 

1666 """Rewrite an Intersection in terms of equalities and logic operators""" 

1667 return And(*[set.as_relational(symbol) for set in self.args]) 

1668 

1669 

1670class Complement(Set): 

1671 r"""Represents the set difference or relative complement of a set with 

1672 another set. 

1673 

1674 $$A - B = \{x \in A \mid x \notin B\}$$ 

1675 

1676 

1677 Examples 

1678 ======== 

1679 

1680 >>> from sympy import Complement, FiniteSet 

1681 >>> Complement(FiniteSet(0, 1, 2), FiniteSet(1)) 

1682 {0, 2} 

1683 

1684 See Also 

1685 ========= 

1686 

1687 Intersection, Union 

1688 

1689 References 

1690 ========== 

1691 

1692 .. [1] https://mathworld.wolfram.com/ComplementSet.html 

1693 """ 

1694 

1695 is_Complement = True 

1696 

1697 def __new__(cls, a, b, evaluate=True): 

1698 a, b = map(_sympify, (a, b)) 

1699 if evaluate: 

1700 return Complement.reduce(a, b) 

1701 

1702 return Basic.__new__(cls, a, b) 

1703 

1704 @staticmethod 

1705 def reduce(A, B): 

1706 """ 

1707 Simplify a :class:`Complement`. 

1708 

1709 """ 

1710 if B == S.UniversalSet or A.is_subset(B): 

1711 return S.EmptySet 

1712 

1713 if isinstance(B, Union): 

1714 return Intersection(*(s.complement(A) for s in B.args)) 

1715 

1716 result = B._complement(A) 

1717 if result is not None: 

1718 return result 

1719 else: 

1720 return Complement(A, B, evaluate=False) 

1721 

1722 def _contains(self, other): 

1723 A = self.args[0] 

1724 B = self.args[1] 

1725 return And(A.contains(other), Not(B.contains(other))) 

1726 

1727 def as_relational(self, symbol): 

1728 """Rewrite a complement in terms of equalities and logic 

1729 operators""" 

1730 A, B = self.args 

1731 

1732 A_rel = A.as_relational(symbol) 

1733 B_rel = Not(B.as_relational(symbol)) 

1734 

1735 return And(A_rel, B_rel) 

1736 

1737 def _kind(self): 

1738 return self.args[0].kind 

1739 

1740 @property 

1741 def is_iterable(self): 

1742 if self.args[0].is_iterable: 

1743 return True 

1744 

1745 @property 

1746 def is_finite_set(self): 

1747 A, B = self.args 

1748 a_finite = A.is_finite_set 

1749 if a_finite is True: 

1750 return True 

1751 elif a_finite is False and B.is_finite_set: 

1752 return False 

1753 

1754 def __iter__(self): 

1755 A, B = self.args 

1756 for a in A: 

1757 if a not in B: 

1758 yield a 

1759 else: 

1760 continue 

1761 

1762 

1763class EmptySet(Set, metaclass=Singleton): 

1764 """ 

1765 Represents the empty set. The empty set is available as a singleton 

1766 as ``S.EmptySet``. 

1767 

1768 Examples 

1769 ======== 

1770 

1771 >>> from sympy import S, Interval 

1772 >>> S.EmptySet 

1773 EmptySet 

1774 

1775 >>> Interval(1, 2).intersect(S.EmptySet) 

1776 EmptySet 

1777 

1778 See Also 

1779 ======== 

1780 

1781 UniversalSet 

1782 

1783 References 

1784 ========== 

1785 

1786 .. [1] https://en.wikipedia.org/wiki/Empty_set 

1787 """ 

1788 is_empty = True 

1789 is_finite_set = True 

1790 is_FiniteSet = True 

1791 

1792 @property # type: ignore 

1793 @deprecated( 

1794 """ 

1795 The is_EmptySet attribute of Set objects is deprecated. 

1796 Use 's is S.EmptySet" or 's.is_empty' instead. 

1797 """, 

1798 deprecated_since_version="1.5", 

1799 active_deprecations_target="deprecated-is-emptyset", 

1800 ) 

1801 def is_EmptySet(self): 

1802 return True 

1803 

1804 @property 

1805 def _measure(self): 

1806 return 0 

1807 

1808 def _contains(self, other): 

1809 return false 

1810 

1811 def as_relational(self, symbol): 

1812 return false 

1813 

1814 def __len__(self): 

1815 return 0 

1816 

1817 def __iter__(self): 

1818 return iter([]) 

1819 

1820 def _eval_powerset(self): 

1821 return FiniteSet(self) 

1822 

1823 @property 

1824 def _boundary(self): 

1825 return self 

1826 

1827 def _complement(self, other): 

1828 return other 

1829 

1830 def _kind(self): 

1831 return SetKind() 

1832 

1833 def _symmetric_difference(self, other): 

1834 return other 

1835 

1836 

1837class UniversalSet(Set, metaclass=Singleton): 

1838 """ 

1839 Represents the set of all things. 

1840 The universal set is available as a singleton as ``S.UniversalSet``. 

1841 

1842 Examples 

1843 ======== 

1844 

1845 >>> from sympy import S, Interval 

1846 >>> S.UniversalSet 

1847 UniversalSet 

1848 

1849 >>> Interval(1, 2).intersect(S.UniversalSet) 

1850 Interval(1, 2) 

1851 

1852 See Also 

1853 ======== 

1854 

1855 EmptySet 

1856 

1857 References 

1858 ========== 

1859 

1860 .. [1] https://en.wikipedia.org/wiki/Universal_set 

1861 """ 

1862 

1863 is_UniversalSet = True 

1864 is_empty = False 

1865 is_finite_set = False 

1866 

1867 def _complement(self, other): 

1868 return S.EmptySet 

1869 

1870 def _symmetric_difference(self, other): 

1871 return other 

1872 

1873 @property 

1874 def _measure(self): 

1875 return S.Infinity 

1876 

1877 def _kind(self): 

1878 return SetKind(UndefinedKind) 

1879 

1880 def _contains(self, other): 

1881 return true 

1882 

1883 def as_relational(self, symbol): 

1884 return true 

1885 

1886 @property 

1887 def _boundary(self): 

1888 return S.EmptySet 

1889 

1890 

1891class FiniteSet(Set): 

1892 """ 

1893 Represents a finite set of Sympy expressions. 

1894 

1895 Examples 

1896 ======== 

1897 

1898 >>> from sympy import FiniteSet, Symbol, Interval, Naturals0 

1899 >>> FiniteSet(1, 2, 3, 4) 

1900 {1, 2, 3, 4} 

1901 >>> 3 in FiniteSet(1, 2, 3, 4) 

1902 True 

1903 >>> FiniteSet(1, (1, 2), Symbol('x')) 

1904 {1, x, (1, 2)} 

1905 >>> FiniteSet(Interval(1, 2), Naturals0, {1, 2}) 

1906 FiniteSet({1, 2}, Interval(1, 2), Naturals0) 

1907 >>> members = [1, 2, 3, 4] 

1908 >>> f = FiniteSet(*members) 

1909 >>> f 

1910 {1, 2, 3, 4} 

1911 >>> f - FiniteSet(2) 

1912 {1, 3, 4} 

1913 >>> f + FiniteSet(2, 5) 

1914 {1, 2, 3, 4, 5} 

1915 

1916 References 

1917 ========== 

1918 

1919 .. [1] https://en.wikipedia.org/wiki/Finite_set 

1920 """ 

1921 is_FiniteSet = True 

1922 is_iterable = True 

1923 is_empty = False 

1924 is_finite_set = True 

1925 

1926 def __new__(cls, *args, **kwargs): 

1927 evaluate = kwargs.get('evaluate', global_parameters.evaluate) 

1928 if evaluate: 

1929 args = list(map(sympify, args)) 

1930 

1931 if len(args) == 0: 

1932 return S.EmptySet 

1933 else: 

1934 args = list(map(sympify, args)) 

1935 

1936 # keep the form of the first canonical arg 

1937 dargs = {} 

1938 for i in reversed(list(ordered(args))): 

1939 if i.is_Symbol: 

1940 dargs[i] = i 

1941 else: 

1942 try: 

1943 dargs[i.as_dummy()] = i 

1944 except TypeError: 

1945 # e.g. i = class without args like `Interval` 

1946 dargs[i] = i 

1947 _args_set = set(dargs.values()) 

1948 args = list(ordered(_args_set, Set._infimum_key)) 

1949 obj = Basic.__new__(cls, *args) 

1950 obj._args_set = _args_set 

1951 return obj 

1952 

1953 

1954 def __iter__(self): 

1955 return iter(self.args) 

1956 

1957 def _complement(self, other): 

1958 if isinstance(other, Interval): 

1959 # Splitting in sub-intervals is only done for S.Reals; 

1960 # other cases that need splitting will first pass through 

1961 # Set._complement(). 

1962 nums, syms = [], [] 

1963 for m in self.args: 

1964 if m.is_number and m.is_real: 

1965 nums.append(m) 

1966 elif m.is_real == False: 

1967 pass # drop non-reals 

1968 else: 

1969 syms.append(m) # various symbolic expressions 

1970 if other == S.Reals and nums != []: 

1971 nums.sort() 

1972 intervals = [] # Build up a list of intervals between the elements 

1973 intervals += [Interval(S.NegativeInfinity, nums[0], True, True)] 

1974 for a, b in zip(nums[:-1], nums[1:]): 

1975 intervals.append(Interval(a, b, True, True)) # both open 

1976 intervals.append(Interval(nums[-1], S.Infinity, True, True)) 

1977 if syms != []: 

1978 return Complement(Union(*intervals, evaluate=False), 

1979 FiniteSet(*syms), evaluate=False) 

1980 else: 

1981 return Union(*intervals, evaluate=False) 

1982 elif nums == []: # no splitting necessary or possible: 

1983 if syms: 

1984 return Complement(other, FiniteSet(*syms), evaluate=False) 

1985 else: 

1986 return other 

1987 

1988 elif isinstance(other, FiniteSet): 

1989 unk = [] 

1990 for i in self: 

1991 c = sympify(other.contains(i)) 

1992 if c is not S.true and c is not S.false: 

1993 unk.append(i) 

1994 unk = FiniteSet(*unk) 

1995 if unk == self: 

1996 return 

1997 not_true = [] 

1998 for i in other: 

1999 c = sympify(self.contains(i)) 

2000 if c is not S.true: 

2001 not_true.append(i) 

2002 return Complement(FiniteSet(*not_true), unk) 

2003 

2004 return Set._complement(self, other) 

2005 

2006 def _contains(self, other): 

2007 """ 

2008 Tests whether an element, other, is in the set. 

2009 

2010 Explanation 

2011 =========== 

2012 

2013 The actual test is for mathematical equality (as opposed to 

2014 syntactical equality). In the worst case all elements of the 

2015 set must be checked. 

2016 

2017 Examples 

2018 ======== 

2019 

2020 >>> from sympy import FiniteSet 

2021 >>> 1 in FiniteSet(1, 2) 

2022 True 

2023 >>> 5 in FiniteSet(1, 2) 

2024 False 

2025 

2026 """ 

2027 if other in self._args_set: 

2028 return True 

2029 else: 

2030 # evaluate=True is needed to override evaluate=False context; 

2031 # we need Eq to do the evaluation 

2032 return fuzzy_or(fuzzy_bool(Eq(e, other, evaluate=True)) 

2033 for e in self.args) 

2034 

2035 def _eval_is_subset(self, other): 

2036 return fuzzy_and(other._contains(e) for e in self.args) 

2037 

2038 @property 

2039 def _boundary(self): 

2040 return self 

2041 

2042 @property 

2043 def _inf(self): 

2044 return Min(*self) 

2045 

2046 @property 

2047 def _sup(self): 

2048 return Max(*self) 

2049 

2050 @property 

2051 def measure(self): 

2052 return 0 

2053 

2054 def _kind(self): 

2055 if not self.args: 

2056 return SetKind() 

2057 elif all(i.kind == self.args[0].kind for i in self.args): 

2058 return SetKind(self.args[0].kind) 

2059 else: 

2060 return SetKind(UndefinedKind) 

2061 

2062 def __len__(self): 

2063 return len(self.args) 

2064 

2065 def as_relational(self, symbol): 

2066 """Rewrite a FiniteSet in terms of equalities and logic operators. """ 

2067 return Or(*[Eq(symbol, elem) for elem in self]) 

2068 

2069 def compare(self, other): 

2070 return (hash(self) - hash(other)) 

2071 

2072 def _eval_evalf(self, prec): 

2073 dps = prec_to_dps(prec) 

2074 return FiniteSet(*[elem.evalf(n=dps) for elem in self]) 

2075 

2076 def _eval_simplify(self, **kwargs): 

2077 from sympy.simplify import simplify 

2078 return FiniteSet(*[simplify(elem, **kwargs) for elem in self]) 

2079 

2080 @property 

2081 def _sorted_args(self): 

2082 return self.args 

2083 

2084 def _eval_powerset(self): 

2085 return self.func(*[self.func(*s) for s in subsets(self.args)]) 

2086 

2087 def _eval_rewrite_as_PowerSet(self, *args, **kwargs): 

2088 """Rewriting method for a finite set to a power set.""" 

2089 from .powerset import PowerSet 

2090 

2091 is2pow = lambda n: bool(n and not n & (n - 1)) 

2092 if not is2pow(len(self)): 

2093 return None 

2094 

2095 fs_test = lambda arg: isinstance(arg, Set) and arg.is_FiniteSet 

2096 if not all(fs_test(arg) for arg in args): 

2097 return None 

2098 

2099 biggest = max(args, key=len) 

2100 for arg in subsets(biggest.args): 

2101 arg_set = FiniteSet(*arg) 

2102 if arg_set not in args: 

2103 return None 

2104 return PowerSet(biggest) 

2105 

2106 def __ge__(self, other): 

2107 if not isinstance(other, Set): 

2108 raise TypeError("Invalid comparison of set with %s" % func_name(other)) 

2109 return other.is_subset(self) 

2110 

2111 def __gt__(self, other): 

2112 if not isinstance(other, Set): 

2113 raise TypeError("Invalid comparison of set with %s" % func_name(other)) 

2114 return self.is_proper_superset(other) 

2115 

2116 def __le__(self, other): 

2117 if not isinstance(other, Set): 

2118 raise TypeError("Invalid comparison of set with %s" % func_name(other)) 

2119 return self.is_subset(other) 

2120 

2121 def __lt__(self, other): 

2122 if not isinstance(other, Set): 

2123 raise TypeError("Invalid comparison of set with %s" % func_name(other)) 

2124 return self.is_proper_subset(other) 

2125 

2126 def __eq__(self, other): 

2127 if isinstance(other, (set, frozenset)): 

2128 return self._args_set == other 

2129 return super().__eq__(other) 

2130 

2131 __hash__ : Callable[[Basic], Any] = Basic.__hash__ 

2132 

2133_sympy_converter[set] = lambda x: FiniteSet(*x) 

2134_sympy_converter[frozenset] = lambda x: FiniteSet(*x) 

2135 

2136 

2137class SymmetricDifference(Set): 

2138 """Represents the set of elements which are in either of the 

2139 sets and not in their intersection. 

2140 

2141 Examples 

2142 ======== 

2143 

2144 >>> from sympy import SymmetricDifference, FiniteSet 

2145 >>> SymmetricDifference(FiniteSet(1, 2, 3), FiniteSet(3, 4, 5)) 

2146 {1, 2, 4, 5} 

2147 

2148 See Also 

2149 ======== 

2150 

2151 Complement, Union 

2152 

2153 References 

2154 ========== 

2155 

2156 .. [1] https://en.wikipedia.org/wiki/Symmetric_difference 

2157 """ 

2158 

2159 is_SymmetricDifference = True 

2160 

2161 def __new__(cls, a, b, evaluate=True): 

2162 if evaluate: 

2163 return SymmetricDifference.reduce(a, b) 

2164 

2165 return Basic.__new__(cls, a, b) 

2166 

2167 @staticmethod 

2168 def reduce(A, B): 

2169 result = B._symmetric_difference(A) 

2170 if result is not None: 

2171 return result 

2172 else: 

2173 return SymmetricDifference(A, B, evaluate=False) 

2174 

2175 def as_relational(self, symbol): 

2176 """Rewrite a symmetric_difference in terms of equalities and 

2177 logic operators""" 

2178 A, B = self.args 

2179 

2180 A_rel = A.as_relational(symbol) 

2181 B_rel = B.as_relational(symbol) 

2182 

2183 return Xor(A_rel, B_rel) 

2184 

2185 @property 

2186 def is_iterable(self): 

2187 if all(arg.is_iterable for arg in self.args): 

2188 return True 

2189 

2190 def __iter__(self): 

2191 

2192 args = self.args 

2193 union = roundrobin(*(iter(arg) for arg in args)) 

2194 

2195 for item in union: 

2196 count = 0 

2197 for s in args: 

2198 if item in s: 

2199 count += 1 

2200 

2201 if count % 2 == 1: 

2202 yield item 

2203 

2204 

2205 

2206class DisjointUnion(Set): 

2207 """ Represents the disjoint union (also known as the external disjoint union) 

2208 of a finite number of sets. 

2209 

2210 Examples 

2211 ======== 

2212 

2213 >>> from sympy import DisjointUnion, FiniteSet, Interval, Union, Symbol 

2214 >>> A = FiniteSet(1, 2, 3) 

2215 >>> B = Interval(0, 5) 

2216 >>> DisjointUnion(A, B) 

2217 DisjointUnion({1, 2, 3}, Interval(0, 5)) 

2218 >>> DisjointUnion(A, B).rewrite(Union) 

2219 Union(ProductSet({1, 2, 3}, {0}), ProductSet(Interval(0, 5), {1})) 

2220 >>> C = FiniteSet(Symbol('x'), Symbol('y'), Symbol('z')) 

2221 >>> DisjointUnion(C, C) 

2222 DisjointUnion({x, y, z}, {x, y, z}) 

2223 >>> DisjointUnion(C, C).rewrite(Union) 

2224 ProductSet({x, y, z}, {0, 1}) 

2225 

2226 References 

2227 ========== 

2228 

2229 https://en.wikipedia.org/wiki/Disjoint_union 

2230 """ 

2231 

2232 def __new__(cls, *sets): 

2233 dj_collection = [] 

2234 for set_i in sets: 

2235 if isinstance(set_i, Set): 

2236 dj_collection.append(set_i) 

2237 else: 

2238 raise TypeError("Invalid input: '%s', input args \ 

2239 to DisjointUnion must be Sets" % set_i) 

2240 obj = Basic.__new__(cls, *dj_collection) 

2241 return obj 

2242 

2243 @property 

2244 def sets(self): 

2245 return self.args 

2246 

2247 @property 

2248 def is_empty(self): 

2249 return fuzzy_and(s.is_empty for s in self.sets) 

2250 

2251 @property 

2252 def is_finite_set(self): 

2253 all_finite = fuzzy_and(s.is_finite_set for s in self.sets) 

2254 return fuzzy_or([self.is_empty, all_finite]) 

2255 

2256 @property 

2257 def is_iterable(self): 

2258 if self.is_empty: 

2259 return False 

2260 iter_flag = True 

2261 for set_i in self.sets: 

2262 if not set_i.is_empty: 

2263 iter_flag = iter_flag and set_i.is_iterable 

2264 return iter_flag 

2265 

2266 def _eval_rewrite_as_Union(self, *sets): 

2267 """ 

2268 Rewrites the disjoint union as the union of (``set`` x {``i``}) 

2269 where ``set`` is the element in ``sets`` at index = ``i`` 

2270 """ 

2271 

2272 dj_union = S.EmptySet 

2273 index = 0 

2274 for set_i in sets: 

2275 if isinstance(set_i, Set): 

2276 cross = ProductSet(set_i, FiniteSet(index)) 

2277 dj_union = Union(dj_union, cross) 

2278 index = index + 1 

2279 return dj_union 

2280 

2281 def _contains(self, element): 

2282 """ 

2283 ``in`` operator for DisjointUnion 

2284 

2285 Examples 

2286 ======== 

2287 

2288 >>> from sympy import Interval, DisjointUnion 

2289 >>> D = DisjointUnion(Interval(0, 1), Interval(0, 2)) 

2290 >>> (0.5, 0) in D 

2291 True 

2292 >>> (0.5, 1) in D 

2293 True 

2294 >>> (1.5, 0) in D 

2295 False 

2296 >>> (1.5, 1) in D 

2297 True 

2298 

2299 Passes operation on to constituent sets 

2300 """ 

2301 if not isinstance(element, Tuple) or len(element) != 2: 

2302 return False 

2303 

2304 if not element[1].is_Integer: 

2305 return False 

2306 

2307 if element[1] >= len(self.sets) or element[1] < 0: 

2308 return False 

2309 

2310 return element[0] in self.sets[element[1]] 

2311 

2312 def _kind(self): 

2313 if not self.args: 

2314 return SetKind() 

2315 elif all(i.kind == self.args[0].kind for i in self.args): 

2316 return self.args[0].kind 

2317 else: 

2318 return SetKind(UndefinedKind) 

2319 

2320 def __iter__(self): 

2321 if self.is_iterable: 

2322 

2323 iters = [] 

2324 for i, s in enumerate(self.sets): 

2325 iters.append(iproduct(s, {Integer(i)})) 

2326 

2327 return iter(roundrobin(*iters)) 

2328 else: 

2329 raise ValueError("'%s' is not iterable." % self) 

2330 

2331 def __len__(self): 

2332 """ 

2333 Returns the length of the disjoint union, i.e., the number of elements in the set. 

2334 

2335 Examples 

2336 ======== 

2337 

2338 >>> from sympy import FiniteSet, DisjointUnion, EmptySet 

2339 >>> D1 = DisjointUnion(FiniteSet(1, 2, 3, 4), EmptySet, FiniteSet(3, 4, 5)) 

2340 >>> len(D1) 

2341 7 

2342 >>> D2 = DisjointUnion(FiniteSet(3, 5, 7), EmptySet, FiniteSet(3, 5, 7)) 

2343 >>> len(D2) 

2344 6 

2345 >>> D3 = DisjointUnion(EmptySet, EmptySet) 

2346 >>> len(D3) 

2347 0 

2348 

2349 Adds up the lengths of the constituent sets. 

2350 """ 

2351 

2352 if self.is_finite_set: 

2353 size = 0 

2354 for set in self.sets: 

2355 size += len(set) 

2356 return size 

2357 else: 

2358 raise ValueError("'%s' is not a finite set." % self) 

2359 

2360 

2361def imageset(*args): 

2362 r""" 

2363 Return an image of the set under transformation ``f``. 

2364 

2365 Explanation 

2366 =========== 

2367 

2368 If this function cannot compute the image, it returns an 

2369 unevaluated ImageSet object. 

2370 

2371 .. math:: 

2372 \{ f(x) \mid x \in \mathrm{self} \} 

2373 

2374 Examples 

2375 ======== 

2376 

2377 >>> from sympy import S, Interval, imageset, sin, Lambda 

2378 >>> from sympy.abc import x 

2379 

2380 >>> imageset(x, 2*x, Interval(0, 2)) 

2381 Interval(0, 4) 

2382 

2383 >>> imageset(lambda x: 2*x, Interval(0, 2)) 

2384 Interval(0, 4) 

2385 

2386 >>> imageset(Lambda(x, sin(x)), Interval(-2, 1)) 

2387 ImageSet(Lambda(x, sin(x)), Interval(-2, 1)) 

2388 

2389 >>> imageset(sin, Interval(-2, 1)) 

2390 ImageSet(Lambda(x, sin(x)), Interval(-2, 1)) 

2391 >>> imageset(lambda y: x + y, Interval(-2, 1)) 

2392 ImageSet(Lambda(y, x + y), Interval(-2, 1)) 

2393 

2394 Expressions applied to the set of Integers are simplified 

2395 to show as few negatives as possible and linear expressions 

2396 are converted to a canonical form. If this is not desirable 

2397 then the unevaluated ImageSet should be used. 

2398 

2399 >>> imageset(x, -2*x + 5, S.Integers) 

2400 ImageSet(Lambda(x, 2*x + 1), Integers) 

2401 

2402 See Also 

2403 ======== 

2404 

2405 sympy.sets.fancysets.ImageSet 

2406 

2407 """ 

2408 from .fancysets import ImageSet 

2409 from .setexpr import set_function 

2410 

2411 if len(args) < 2: 

2412 raise ValueError('imageset expects at least 2 args, got: %s' % len(args)) 

2413 

2414 if isinstance(args[0], (Symbol, tuple)) and len(args) > 2: 

2415 f = Lambda(args[0], args[1]) 

2416 set_list = args[2:] 

2417 else: 

2418 f = args[0] 

2419 set_list = args[1:] 

2420 

2421 if isinstance(f, Lambda): 

2422 pass 

2423 elif callable(f): 

2424 nargs = getattr(f, 'nargs', {}) 

2425 if nargs: 

2426 if len(nargs) != 1: 

2427 raise NotImplementedError(filldedent(''' 

2428 This function can take more than 1 arg 

2429 but the potentially complicated set input 

2430 has not been analyzed at this point to 

2431 know its dimensions. TODO 

2432 ''')) 

2433 N = nargs.args[0] 

2434 if N == 1: 

2435 s = 'x' 

2436 else: 

2437 s = [Symbol('x%i' % i) for i in range(1, N + 1)] 

2438 else: 

2439 s = inspect.signature(f).parameters 

2440 

2441 dexpr = _sympify(f(*[Dummy() for i in s])) 

2442 var = tuple(uniquely_named_symbol( 

2443 Symbol(i), dexpr) for i in s) 

2444 f = Lambda(var, f(*var)) 

2445 else: 

2446 raise TypeError(filldedent(''' 

2447 expecting lambda, Lambda, or FunctionClass, 

2448 not \'%s\'.''' % func_name(f))) 

2449 

2450 if any(not isinstance(s, Set) for s in set_list): 

2451 name = [func_name(s) for s in set_list] 

2452 raise ValueError( 

2453 'arguments after mapping should be sets, not %s' % name) 

2454 

2455 if len(set_list) == 1: 

2456 set = set_list[0] 

2457 try: 

2458 # TypeError if arg count != set dimensions 

2459 r = set_function(f, set) 

2460 if r is None: 

2461 raise TypeError 

2462 if not r: 

2463 return r 

2464 except TypeError: 

2465 r = ImageSet(f, set) 

2466 if isinstance(r, ImageSet): 

2467 f, set = r.args 

2468 

2469 if f.variables[0] == f.expr: 

2470 return set 

2471 

2472 if isinstance(set, ImageSet): 

2473 # XXX: Maybe this should just be: 

2474 # f2 = set.lambda 

2475 # fun = Lambda(f2.signature, f(*f2.expr)) 

2476 # return imageset(fun, *set.base_sets) 

2477 if len(set.lamda.variables) == 1 and len(f.variables) == 1: 

2478 x = set.lamda.variables[0] 

2479 y = f.variables[0] 

2480 return imageset( 

2481 Lambda(x, f.expr.subs(y, set.lamda.expr)), *set.base_sets) 

2482 

2483 if r is not None: 

2484 return r 

2485 

2486 return ImageSet(f, *set_list) 

2487 

2488 

2489def is_function_invertible_in_set(func, setv): 

2490 """ 

2491 Checks whether function ``func`` is invertible when the domain is 

2492 restricted to set ``setv``. 

2493 """ 

2494 # Functions known to always be invertible: 

2495 if func in (exp, log): 

2496 return True 

2497 u = Dummy("u") 

2498 fdiff = func(u).diff(u) 

2499 # monotonous functions: 

2500 # TODO: check subsets (`func` in `setv`) 

2501 if (fdiff > 0) == True or (fdiff < 0) == True: 

2502 return True 

2503 # TODO: support more 

2504 return None 

2505 

2506 

2507def simplify_union(args): 

2508 """ 

2509 Simplify a :class:`Union` using known rules. 

2510 

2511 Explanation 

2512 =========== 

2513 

2514 We first start with global rules like 'Merge all FiniteSets' 

2515 

2516 Then we iterate through all pairs and ask the constituent sets if they 

2517 can simplify themselves with any other constituent. This process depends 

2518 on ``union_sets(a, b)`` functions. 

2519 """ 

2520 from sympy.sets.handlers.union import union_sets 

2521 

2522 # ===== Global Rules ===== 

2523 if not args: 

2524 return S.EmptySet 

2525 

2526 for arg in args: 

2527 if not isinstance(arg, Set): 

2528 raise TypeError("Input args to Union must be Sets") 

2529 

2530 # Merge all finite sets 

2531 finite_sets = [x for x in args if x.is_FiniteSet] 

2532 if len(finite_sets) > 1: 

2533 a = (x for set in finite_sets for x in set) 

2534 finite_set = FiniteSet(*a) 

2535 args = [finite_set] + [x for x in args if not x.is_FiniteSet] 

2536 

2537 # ===== Pair-wise Rules ===== 

2538 # Here we depend on rules built into the constituent sets 

2539 args = set(args) 

2540 new_args = True 

2541 while new_args: 

2542 for s in args: 

2543 new_args = False 

2544 for t in args - {s}: 

2545 new_set = union_sets(s, t) 

2546 # This returns None if s does not know how to intersect 

2547 # with t. Returns the newly intersected set otherwise 

2548 if new_set is not None: 

2549 if not isinstance(new_set, set): 

2550 new_set = {new_set} 

2551 new_args = (args - {s, t}).union(new_set) 

2552 break 

2553 if new_args: 

2554 args = new_args 

2555 break 

2556 

2557 if len(args) == 1: 

2558 return args.pop() 

2559 else: 

2560 return Union(*args, evaluate=False) 

2561 

2562 

2563def simplify_intersection(args): 

2564 """ 

2565 Simplify an intersection using known rules. 

2566 

2567 Explanation 

2568 =========== 

2569 

2570 We first start with global rules like 

2571 'if any empty sets return empty set' and 'distribute any unions' 

2572 

2573 Then we iterate through all pairs and ask the constituent sets if they 

2574 can simplify themselves with any other constituent 

2575 """ 

2576 

2577 # ===== Global Rules ===== 

2578 if not args: 

2579 return S.UniversalSet 

2580 

2581 for arg in args: 

2582 if not isinstance(arg, Set): 

2583 raise TypeError("Input args to Union must be Sets") 

2584 

2585 # If any EmptySets return EmptySet 

2586 if S.EmptySet in args: 

2587 return S.EmptySet 

2588 

2589 # Handle Finite sets 

2590 rv = Intersection._handle_finite_sets(args) 

2591 

2592 if rv is not None: 

2593 return rv 

2594 

2595 # If any of the sets are unions, return a Union of Intersections 

2596 for s in args: 

2597 if s.is_Union: 

2598 other_sets = set(args) - {s} 

2599 if len(other_sets) > 0: 

2600 other = Intersection(*other_sets) 

2601 return Union(*(Intersection(arg, other) for arg in s.args)) 

2602 else: 

2603 return Union(*s.args) 

2604 

2605 for s in args: 

2606 if s.is_Complement: 

2607 args.remove(s) 

2608 other_sets = args + [s.args[0]] 

2609 return Complement(Intersection(*other_sets), s.args[1]) 

2610 

2611 from sympy.sets.handlers.intersection import intersection_sets 

2612 

2613 # At this stage we are guaranteed not to have any 

2614 # EmptySets, FiniteSets, or Unions in the intersection 

2615 

2616 # ===== Pair-wise Rules ===== 

2617 # Here we depend on rules built into the constituent sets 

2618 args = set(args) 

2619 new_args = True 

2620 while new_args: 

2621 for s in args: 

2622 new_args = False 

2623 for t in args - {s}: 

2624 new_set = intersection_sets(s, t) 

2625 # This returns None if s does not know how to intersect 

2626 # with t. Returns the newly intersected set otherwise 

2627 

2628 if new_set is not None: 

2629 new_args = (args - {s, t}).union({new_set}) 

2630 break 

2631 if new_args: 

2632 args = new_args 

2633 break 

2634 

2635 if len(args) == 1: 

2636 return args.pop() 

2637 else: 

2638 return Intersection(*args, evaluate=False) 

2639 

2640 

2641def _handle_finite_sets(op, x, y, commutative): 

2642 # Handle finite sets: 

2643 fs_args, other = sift([x, y], lambda x: isinstance(x, FiniteSet), binary=True) 

2644 if len(fs_args) == 2: 

2645 return FiniteSet(*[op(i, j) for i in fs_args[0] for j in fs_args[1]]) 

2646 elif len(fs_args) == 1: 

2647 sets = [_apply_operation(op, other[0], i, commutative) for i in fs_args[0]] 

2648 return Union(*sets) 

2649 else: 

2650 return None 

2651 

2652 

2653def _apply_operation(op, x, y, commutative): 

2654 from .fancysets import ImageSet 

2655 d = Dummy('d') 

2656 

2657 out = _handle_finite_sets(op, x, y, commutative) 

2658 if out is None: 

2659 out = op(x, y) 

2660 

2661 if out is None and commutative: 

2662 out = op(y, x) 

2663 if out is None: 

2664 _x, _y = symbols("x y") 

2665 if isinstance(x, Set) and not isinstance(y, Set): 

2666 out = ImageSet(Lambda(d, op(d, y)), x).doit() 

2667 elif not isinstance(x, Set) and isinstance(y, Set): 

2668 out = ImageSet(Lambda(d, op(x, d)), y).doit() 

2669 else: 

2670 out = ImageSet(Lambda((_x, _y), op(_x, _y)), x, y) 

2671 return out 

2672 

2673 

2674def set_add(x, y): 

2675 from sympy.sets.handlers.add import _set_add 

2676 return _apply_operation(_set_add, x, y, commutative=True) 

2677 

2678 

2679def set_sub(x, y): 

2680 from sympy.sets.handlers.add import _set_sub 

2681 return _apply_operation(_set_sub, x, y, commutative=False) 

2682 

2683 

2684def set_mul(x, y): 

2685 from sympy.sets.handlers.mul import _set_mul 

2686 return _apply_operation(_set_mul, x, y, commutative=True) 

2687 

2688 

2689def set_div(x, y): 

2690 from sympy.sets.handlers.mul import _set_div 

2691 return _apply_operation(_set_div, x, y, commutative=False) 

2692 

2693 

2694def set_pow(x, y): 

2695 from sympy.sets.handlers.power import _set_pow 

2696 return _apply_operation(_set_pow, x, y, commutative=False) 

2697 

2698 

2699def set_function(f, x): 

2700 from sympy.sets.handlers.functions import _set_function 

2701 return _set_function(f, x) 

2702 

2703 

2704class SetKind(Kind): 

2705 """ 

2706 SetKind is kind for all Sets 

2707 

2708 Every instance of Set will have kind ``SetKind`` parametrised by the kind 

2709 of the elements of the ``Set``. The kind of the elements might be 

2710 ``NumberKind``, or ``TupleKind`` or something else. When not all elements 

2711 have the same kind then the kind of the elements will be given as 

2712 ``UndefinedKind``. 

2713 

2714 Parameters 

2715 ========== 

2716 

2717 element_kind: Kind (optional) 

2718 The kind of the elements of the set. In a well defined set all elements 

2719 will have the same kind. Otherwise the kind should 

2720 :class:`sympy.core.kind.UndefinedKind`. The ``element_kind`` argument is optional but 

2721 should only be omitted in the case of ``EmptySet`` whose kind is simply 

2722 ``SetKind()`` 

2723 

2724 Examples 

2725 ======== 

2726 

2727 >>> from sympy import Interval 

2728 >>> Interval(1, 2).kind 

2729 SetKind(NumberKind) 

2730 >>> Interval(1,2).kind.element_kind 

2731 NumberKind 

2732 

2733 See Also 

2734 ======== 

2735 

2736 sympy.core.kind.NumberKind 

2737 sympy.matrices.common.MatrixKind 

2738 sympy.core.containers.TupleKind 

2739 """ 

2740 def __new__(cls, element_kind=None): 

2741 obj = super().__new__(cls, element_kind) 

2742 obj.element_kind = element_kind 

2743 return obj 

2744 

2745 def __repr__(self): 

2746 if not self.element_kind: 

2747 return "SetKind()" 

2748 else: 

2749 return "SetKind(%s)" % self.element_kind