Coverage for /usr/lib/python3/dist-packages/sympy/sets/fancysets.py: 22%
704 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1from functools import reduce
2from itertools import product
4from sympy.core.basic import Basic
5from sympy.core.containers import Tuple
6from sympy.core.expr import Expr
7from sympy.core.function import Lambda
8from sympy.core.logic import fuzzy_not, fuzzy_or, fuzzy_and
9from sympy.core.mod import Mod
10from sympy.core.numbers import oo, igcd, Rational
11from sympy.core.relational import Eq, is_eq
12from sympy.core.kind import NumberKind
13from sympy.core.singleton import Singleton, S
14from sympy.core.symbol import Dummy, symbols, Symbol
15from sympy.core.sympify import _sympify, sympify, _sympy_converter
16from sympy.functions.elementary.integers import ceiling, floor
17from sympy.functions.elementary.trigonometric import sin, cos
18from sympy.logic.boolalg import And, Or
19from .sets import Set, Interval, Union, FiniteSet, ProductSet, SetKind
20from sympy.utilities.misc import filldedent
23class Rationals(Set, metaclass=Singleton):
24 """
25 Represents the rational numbers. This set is also available as
26 the singleton ``S.Rationals``.
28 Examples
29 ========
31 >>> from sympy import S
32 >>> S.Half in S.Rationals
33 True
34 >>> iterable = iter(S.Rationals)
35 >>> [next(iterable) for i in range(12)]
36 [0, 1, -1, 1/2, 2, -1/2, -2, 1/3, 3, -1/3, -3, 2/3]
37 """
39 is_iterable = True
40 _inf = S.NegativeInfinity
41 _sup = S.Infinity
42 is_empty = False
43 is_finite_set = False
45 def _contains(self, other):
46 if not isinstance(other, Expr):
47 return False
48 return other.is_rational
50 def __iter__(self):
51 yield S.Zero
52 yield S.One
53 yield S.NegativeOne
54 d = 2
55 while True:
56 for n in range(d):
57 if igcd(n, d) == 1:
58 yield Rational(n, d)
59 yield Rational(d, n)
60 yield Rational(-n, d)
61 yield Rational(-d, n)
62 d += 1
64 @property
65 def _boundary(self):
66 return S.Reals
68 def _kind(self):
69 return SetKind(NumberKind)
72class Naturals(Set, metaclass=Singleton):
73 """
74 Represents the natural numbers (or counting numbers) which are all
75 positive integers starting from 1. This set is also available as
76 the singleton ``S.Naturals``.
78 Examples
79 ========
81 >>> from sympy import S, Interval, pprint
82 >>> 5 in S.Naturals
83 True
84 >>> iterable = iter(S.Naturals)
85 >>> next(iterable)
86 1
87 >>> next(iterable)
88 2
89 >>> next(iterable)
90 3
91 >>> pprint(S.Naturals.intersect(Interval(0, 10)))
92 {1, 2, ..., 10}
94 See Also
95 ========
97 Naturals0 : non-negative integers (i.e. includes 0, too)
98 Integers : also includes negative integers
99 """
101 is_iterable = True
102 _inf = S.One
103 _sup = S.Infinity
104 is_empty = False
105 is_finite_set = False
107 def _contains(self, other):
108 if not isinstance(other, Expr):
109 return False
110 elif other.is_positive and other.is_integer:
111 return True
112 elif other.is_integer is False or other.is_positive is False:
113 return False
115 def _eval_is_subset(self, other):
116 return Range(1, oo).is_subset(other)
118 def _eval_is_superset(self, other):
119 return Range(1, oo).is_superset(other)
121 def __iter__(self):
122 i = self._inf
123 while True:
124 yield i
125 i = i + 1
127 @property
128 def _boundary(self):
129 return self
131 def as_relational(self, x):
132 return And(Eq(floor(x), x), x >= self.inf, x < oo)
134 def _kind(self):
135 return SetKind(NumberKind)
138class Naturals0(Naturals):
139 """Represents the whole numbers which are all the non-negative integers,
140 inclusive of zero.
142 See Also
143 ========
145 Naturals : positive integers; does not include 0
146 Integers : also includes the negative integers
147 """
148 _inf = S.Zero
150 def _contains(self, other):
151 if not isinstance(other, Expr):
152 return S.false
153 elif other.is_integer and other.is_nonnegative:
154 return S.true
155 elif other.is_integer is False or other.is_nonnegative is False:
156 return S.false
158 def _eval_is_subset(self, other):
159 return Range(oo).is_subset(other)
161 def _eval_is_superset(self, other):
162 return Range(oo).is_superset(other)
165class Integers(Set, metaclass=Singleton):
166 """
167 Represents all integers: positive, negative and zero. This set is also
168 available as the singleton ``S.Integers``.
170 Examples
171 ========
173 >>> from sympy import S, Interval, pprint
174 >>> 5 in S.Naturals
175 True
176 >>> iterable = iter(S.Integers)
177 >>> next(iterable)
178 0
179 >>> next(iterable)
180 1
181 >>> next(iterable)
182 -1
183 >>> next(iterable)
184 2
186 >>> pprint(S.Integers.intersect(Interval(-4, 4)))
187 {-4, -3, ..., 4}
189 See Also
190 ========
192 Naturals0 : non-negative integers
193 Integers : positive and negative integers and zero
194 """
196 is_iterable = True
197 is_empty = False
198 is_finite_set = False
200 def _contains(self, other):
201 if not isinstance(other, Expr):
202 return S.false
203 return other.is_integer
205 def __iter__(self):
206 yield S.Zero
207 i = S.One
208 while True:
209 yield i
210 yield -i
211 i = i + 1
213 @property
214 def _inf(self):
215 return S.NegativeInfinity
217 @property
218 def _sup(self):
219 return S.Infinity
221 @property
222 def _boundary(self):
223 return self
225 def _kind(self):
226 return SetKind(NumberKind)
228 def as_relational(self, x):
229 return And(Eq(floor(x), x), -oo < x, x < oo)
231 def _eval_is_subset(self, other):
232 return Range(-oo, oo).is_subset(other)
234 def _eval_is_superset(self, other):
235 return Range(-oo, oo).is_superset(other)
238class Reals(Interval, metaclass=Singleton):
239 """
240 Represents all real numbers
241 from negative infinity to positive infinity,
242 including all integer, rational and irrational numbers.
243 This set is also available as the singleton ``S.Reals``.
246 Examples
247 ========
249 >>> from sympy import S, Rational, pi, I
250 >>> 5 in S.Reals
251 True
252 >>> Rational(-1, 2) in S.Reals
253 True
254 >>> pi in S.Reals
255 True
256 >>> 3*I in S.Reals
257 False
258 >>> S.Reals.contains(pi)
259 True
262 See Also
263 ========
265 ComplexRegion
266 """
267 @property
268 def start(self):
269 return S.NegativeInfinity
271 @property
272 def end(self):
273 return S.Infinity
275 @property
276 def left_open(self):
277 return True
279 @property
280 def right_open(self):
281 return True
283 def __eq__(self, other):
284 return other == Interval(S.NegativeInfinity, S.Infinity)
286 def __hash__(self):
287 return hash(Interval(S.NegativeInfinity, S.Infinity))
290class ImageSet(Set):
291 """
292 Image of a set under a mathematical function. The transformation
293 must be given as a Lambda function which has as many arguments
294 as the elements of the set upon which it operates, e.g. 1 argument
295 when acting on the set of integers or 2 arguments when acting on
296 a complex region.
298 This function is not normally called directly, but is called
299 from ``imageset``.
302 Examples
303 ========
305 >>> from sympy import Symbol, S, pi, Dummy, Lambda
306 >>> from sympy import FiniteSet, ImageSet, Interval
308 >>> x = Symbol('x')
309 >>> N = S.Naturals
310 >>> squares = ImageSet(Lambda(x, x**2), N) # {x**2 for x in N}
311 >>> 4 in squares
312 True
313 >>> 5 in squares
314 False
316 >>> FiniteSet(0, 1, 2, 3, 4, 5, 6, 7, 9, 10).intersect(squares)
317 {1, 4, 9}
319 >>> square_iterable = iter(squares)
320 >>> for i in range(4):
321 ... next(square_iterable)
322 1
323 4
324 9
325 16
327 If you want to get value for `x` = 2, 1/2 etc. (Please check whether the
328 `x` value is in ``base_set`` or not before passing it as args)
330 >>> squares.lamda(2)
331 4
332 >>> squares.lamda(S(1)/2)
333 1/4
335 >>> n = Dummy('n')
336 >>> solutions = ImageSet(Lambda(n, n*pi), S.Integers) # solutions of sin(x) = 0
337 >>> dom = Interval(-1, 1)
338 >>> dom.intersect(solutions)
339 {0}
341 See Also
342 ========
344 sympy.sets.sets.imageset
345 """
346 def __new__(cls, flambda, *sets):
347 if not isinstance(flambda, Lambda):
348 raise ValueError('First argument must be a Lambda')
350 signature = flambda.signature
352 if len(signature) != len(sets):
353 raise ValueError('Incompatible signature')
355 sets = [_sympify(s) for s in sets]
357 if not all(isinstance(s, Set) for s in sets):
358 raise TypeError("Set arguments to ImageSet should of type Set")
360 if not all(cls._check_sig(sg, st) for sg, st in zip(signature, sets)):
361 raise ValueError("Signature %s does not match sets %s" % (signature, sets))
363 if flambda is S.IdentityFunction and len(sets) == 1:
364 return sets[0]
366 if not set(flambda.variables) & flambda.expr.free_symbols:
367 is_empty = fuzzy_or(s.is_empty for s in sets)
368 if is_empty == True:
369 return S.EmptySet
370 elif is_empty == False:
371 return FiniteSet(flambda.expr)
373 return Basic.__new__(cls, flambda, *sets)
375 lamda = property(lambda self: self.args[0])
376 base_sets = property(lambda self: self.args[1:])
378 @property
379 def base_set(self):
380 # XXX: Maybe deprecate this? It is poorly defined in handling
381 # the multivariate case...
382 sets = self.base_sets
383 if len(sets) == 1:
384 return sets[0]
385 else:
386 return ProductSet(*sets).flatten()
388 @property
389 def base_pset(self):
390 return ProductSet(*self.base_sets)
392 @classmethod
393 def _check_sig(cls, sig_i, set_i):
394 if sig_i.is_symbol:
395 return True
396 elif isinstance(set_i, ProductSet):
397 sets = set_i.sets
398 if len(sig_i) != len(sets):
399 return False
400 # Recurse through the signature for nested tuples:
401 return all(cls._check_sig(ts, ps) for ts, ps in zip(sig_i, sets))
402 else:
403 # XXX: Need a better way of checking whether a set is a set of
404 # Tuples or not. For example a FiniteSet can contain Tuples
405 # but so can an ImageSet or a ConditionSet. Others like
406 # Integers, Reals etc can not contain Tuples. We could just
407 # list the possibilities here... Current code for e.g.
408 # _contains probably only works for ProductSet.
409 return True # Give the benefit of the doubt
411 def __iter__(self):
412 already_seen = set()
413 for i in self.base_pset:
414 val = self.lamda(*i)
415 if val in already_seen:
416 continue
417 else:
418 already_seen.add(val)
419 yield val
421 def _is_multivariate(self):
422 return len(self.lamda.variables) > 1
424 def _contains(self, other):
425 from sympy.solvers.solveset import _solveset_multi
427 def get_symsetmap(signature, base_sets):
428 '''Attempt to get a map of symbols to base_sets'''
429 queue = list(zip(signature, base_sets))
430 symsetmap = {}
431 for sig, base_set in queue:
432 if sig.is_symbol:
433 symsetmap[sig] = base_set
434 elif base_set.is_ProductSet:
435 sets = base_set.sets
436 if len(sig) != len(sets):
437 raise ValueError("Incompatible signature")
438 # Recurse
439 queue.extend(zip(sig, sets))
440 else:
441 # If we get here then we have something like sig = (x, y) and
442 # base_set = {(1, 2), (3, 4)}. For now we give up.
443 return None
445 return symsetmap
447 def get_equations(expr, candidate):
448 '''Find the equations relating symbols in expr and candidate.'''
449 queue = [(expr, candidate)]
450 for e, c in queue:
451 if not isinstance(e, Tuple):
452 yield Eq(e, c)
453 elif not isinstance(c, Tuple) or len(e) != len(c):
454 yield False
455 return
456 else:
457 queue.extend(zip(e, c))
459 # Get the basic objects together:
460 other = _sympify(other)
461 expr = self.lamda.expr
462 sig = self.lamda.signature
463 variables = self.lamda.variables
464 base_sets = self.base_sets
466 # Use dummy symbols for ImageSet parameters so they don't match
467 # anything in other
468 rep = {v: Dummy(v.name) for v in variables}
469 variables = [v.subs(rep) for v in variables]
470 sig = sig.subs(rep)
471 expr = expr.subs(rep)
473 # Map the parts of other to those in the Lambda expr
474 equations = []
475 for eq in get_equations(expr, other):
476 # Unsatisfiable equation?
477 if eq is False:
478 return False
479 equations.append(eq)
481 # Map the symbols in the signature to the corresponding domains
482 symsetmap = get_symsetmap(sig, base_sets)
483 if symsetmap is None:
484 # Can't factor the base sets to a ProductSet
485 return None
487 # Which of the variables in the Lambda signature need to be solved for?
488 symss = (eq.free_symbols for eq in equations)
489 variables = set(variables) & reduce(set.union, symss, set())
491 # Use internal multivariate solveset
492 variables = tuple(variables)
493 base_sets = [symsetmap[v] for v in variables]
494 solnset = _solveset_multi(equations, variables, base_sets)
495 if solnset is None:
496 return None
497 return fuzzy_not(solnset.is_empty)
499 @property
500 def is_iterable(self):
501 return all(s.is_iterable for s in self.base_sets)
503 def doit(self, **hints):
504 from sympy.sets.setexpr import SetExpr
505 f = self.lamda
506 sig = f.signature
507 if len(sig) == 1 and sig[0].is_symbol and isinstance(f.expr, Expr):
508 base_set = self.base_sets[0]
509 return SetExpr(base_set)._eval_func(f).set
510 if all(s.is_FiniteSet for s in self.base_sets):
511 return FiniteSet(*(f(*a) for a in product(*self.base_sets)))
512 return self
514 def _kind(self):
515 return SetKind(self.lamda.expr.kind)
518class Range(Set):
519 """
520 Represents a range of integers. Can be called as ``Range(stop)``,
521 ``Range(start, stop)``, or ``Range(start, stop, step)``; when ``step`` is
522 not given it defaults to 1.
524 ``Range(stop)`` is the same as ``Range(0, stop, 1)`` and the stop value
525 (just as for Python ranges) is not included in the Range values.
527 >>> from sympy import Range
528 >>> list(Range(3))
529 [0, 1, 2]
531 The step can also be negative:
533 >>> list(Range(10, 0, -2))
534 [10, 8, 6, 4, 2]
536 The stop value is made canonical so equivalent ranges always
537 have the same args:
539 >>> Range(0, 10, 3)
540 Range(0, 12, 3)
542 Infinite ranges are allowed. ``oo`` and ``-oo`` are never included in the
543 set (``Range`` is always a subset of ``Integers``). If the starting point
544 is infinite, then the final value is ``stop - step``. To iterate such a
545 range, it needs to be reversed:
547 >>> from sympy import oo
548 >>> r = Range(-oo, 1)
549 >>> r[-1]
550 0
551 >>> next(iter(r))
552 Traceback (most recent call last):
553 ...
554 TypeError: Cannot iterate over Range with infinite start
555 >>> next(iter(r.reversed))
556 0
558 Although ``Range`` is a :class:`Set` (and supports the normal set
559 operations) it maintains the order of the elements and can
560 be used in contexts where ``range`` would be used.
562 >>> from sympy import Interval
563 >>> Range(0, 10, 2).intersect(Interval(3, 7))
564 Range(4, 8, 2)
565 >>> list(_)
566 [4, 6]
568 Although slicing of a Range will always return a Range -- possibly
569 empty -- an empty set will be returned from any intersection that
570 is empty:
572 >>> Range(3)[:0]
573 Range(0, 0, 1)
574 >>> Range(3).intersect(Interval(4, oo))
575 EmptySet
576 >>> Range(3).intersect(Range(4, oo))
577 EmptySet
579 Range will accept symbolic arguments but has very limited support
580 for doing anything other than displaying the Range:
582 >>> from sympy import Symbol, pprint
583 >>> from sympy.abc import i, j, k
584 >>> Range(i, j, k).start
585 i
586 >>> Range(i, j, k).inf
587 Traceback (most recent call last):
588 ...
589 ValueError: invalid method for symbolic range
591 Better success will be had when using integer symbols:
593 >>> n = Symbol('n', integer=True)
594 >>> r = Range(n, n + 20, 3)
595 >>> r.inf
596 n
597 >>> pprint(r)
598 {n, n + 3, ..., n + 18}
599 """
601 def __new__(cls, *args):
602 if len(args) == 1:
603 if isinstance(args[0], range):
604 raise TypeError(
605 'use sympify(%s) to convert range to Range' % args[0])
607 # expand range
608 slc = slice(*args)
610 if slc.step == 0:
611 raise ValueError("step cannot be 0")
613 start, stop, step = slc.start or 0, slc.stop, slc.step or 1
614 try:
615 ok = []
616 for w in (start, stop, step):
617 w = sympify(w)
618 if w in [S.NegativeInfinity, S.Infinity] or (
619 w.has(Symbol) and w.is_integer != False):
620 ok.append(w)
621 elif not w.is_Integer:
622 if w.is_infinite:
623 raise ValueError('infinite symbols not allowed')
624 raise ValueError
625 else:
626 ok.append(w)
627 except ValueError:
628 raise ValueError(filldedent('''
629 Finite arguments to Range must be integers; `imageset` can define
630 other cases, e.g. use `imageset(i, i/10, Range(3))` to give
631 [0, 1/10, 1/5].'''))
632 start, stop, step = ok
634 null = False
635 if any(i.has(Symbol) for i in (start, stop, step)):
636 dif = stop - start
637 n = dif/step
638 if n.is_Rational:
639 if dif == 0:
640 null = True
641 else: # (x, x + 5, 2) or (x, 3*x, x)
642 n = floor(n)
643 end = start + n*step
644 if dif.is_Rational: # (x, x + 5, 2)
645 if (end - stop).is_negative:
646 end += step
647 else: # (x, 3*x, x)
648 if (end/stop - 1).is_negative:
649 end += step
650 elif n.is_extended_negative:
651 null = True
652 else:
653 end = stop # other methods like sup and reversed must fail
654 elif start.is_infinite:
655 span = step*(stop - start)
656 if span is S.NaN or span <= 0:
657 null = True
658 elif step.is_Integer and stop.is_infinite and abs(step) != 1:
659 raise ValueError(filldedent('''
660 Step size must be %s in this case.''' % (1 if step > 0 else -1)))
661 else:
662 end = stop
663 else:
664 oostep = step.is_infinite
665 if oostep:
666 step = S.One if step > 0 else S.NegativeOne
667 n = ceiling((stop - start)/step)
668 if n <= 0:
669 null = True
670 elif oostep:
671 step = S.One # make it canonical
672 end = start + step
673 else:
674 end = start + n*step
675 if null:
676 start = end = S.Zero
677 step = S.One
678 return Basic.__new__(cls, start, end, step)
680 start = property(lambda self: self.args[0])
681 stop = property(lambda self: self.args[1])
682 step = property(lambda self: self.args[2])
684 @property
685 def reversed(self):
686 """Return an equivalent Range in the opposite order.
688 Examples
689 ========
691 >>> from sympy import Range
692 >>> Range(10).reversed
693 Range(9, -1, -1)
694 """
695 if self.has(Symbol):
696 n = (self.stop - self.start)/self.step
697 if not n.is_extended_positive or not all(
698 i.is_integer or i.is_infinite for i in self.args):
699 raise ValueError('invalid method for symbolic range')
700 if self.start == self.stop:
701 return self
702 return self.func(
703 self.stop - self.step, self.start - self.step, -self.step)
705 def _kind(self):
706 return SetKind(NumberKind)
708 def _contains(self, other):
709 if self.start == self.stop:
710 return S.false
711 if other.is_infinite:
712 return S.false
713 if not other.is_integer:
714 return other.is_integer
715 if self.has(Symbol):
716 n = (self.stop - self.start)/self.step
717 if not n.is_extended_positive or not all(
718 i.is_integer or i.is_infinite for i in self.args):
719 return
720 else:
721 n = self.size
722 if self.start.is_finite:
723 ref = self.start
724 elif self.stop.is_finite:
725 ref = self.stop
726 else: # both infinite; step is +/- 1 (enforced by __new__)
727 return S.true
728 if n == 1:
729 return Eq(other, self[0])
730 res = (ref - other) % self.step
731 if res == S.Zero:
732 if self.has(Symbol):
733 d = Dummy('i')
734 return self.as_relational(d).subs(d, other)
735 return And(other >= self.inf, other <= self.sup)
736 elif res.is_Integer: # off sequence
737 return S.false
738 else: # symbolic/unsimplified residue modulo step
739 return None
741 def __iter__(self):
742 n = self.size # validate
743 if not (n.has(S.Infinity) or n.has(S.NegativeInfinity) or n.is_Integer):
744 raise TypeError("Cannot iterate over symbolic Range")
745 if self.start in [S.NegativeInfinity, S.Infinity]:
746 raise TypeError("Cannot iterate over Range with infinite start")
747 elif self.start != self.stop:
748 i = self.start
749 if n.is_infinite:
750 while True:
751 yield i
752 i += self.step
753 else:
754 for _ in range(n):
755 yield i
756 i += self.step
758 @property
759 def is_iterable(self):
760 # Check that size can be determined, used by __iter__
761 dif = self.stop - self.start
762 n = dif/self.step
763 if not (n.has(S.Infinity) or n.has(S.NegativeInfinity) or n.is_Integer):
764 return False
765 if self.start in [S.NegativeInfinity, S.Infinity]:
766 return False
767 if not (n.is_extended_nonnegative and all(i.is_integer for i in self.args)):
768 return False
769 return True
771 def __len__(self):
772 rv = self.size
773 if rv is S.Infinity:
774 raise ValueError('Use .size to get the length of an infinite Range')
775 return int(rv)
777 @property
778 def size(self):
779 if self.start == self.stop:
780 return S.Zero
781 dif = self.stop - self.start
782 n = dif/self.step
783 if n.is_infinite:
784 return S.Infinity
785 if n.is_extended_nonnegative and all(i.is_integer for i in self.args):
786 return abs(floor(n))
787 raise ValueError('Invalid method for symbolic Range')
789 @property
790 def is_finite_set(self):
791 if self.start.is_integer and self.stop.is_integer:
792 return True
793 return self.size.is_finite
795 @property
796 def is_empty(self):
797 try:
798 return self.size.is_zero
799 except ValueError:
800 return None
802 def __bool__(self):
803 # this only distinguishes between definite null range
804 # and non-null/unknown null; getting True doesn't mean
805 # that it actually is not null
806 b = is_eq(self.start, self.stop)
807 if b is None:
808 raise ValueError('cannot tell if Range is null or not')
809 return not bool(b)
811 def __getitem__(self, i):
812 ooslice = "cannot slice from the end with an infinite value"
813 zerostep = "slice step cannot be zero"
814 infinite = "slicing not possible on range with infinite start"
815 # if we had to take every other element in the following
816 # oo, ..., 6, 4, 2, 0
817 # we might get oo, ..., 4, 0 or oo, ..., 6, 2
818 ambiguous = "cannot unambiguously re-stride from the end " + \
819 "with an infinite value"
820 if isinstance(i, slice):
821 if self.size.is_finite: # validates, too
822 if self.start == self.stop:
823 return Range(0)
824 start, stop, step = i.indices(self.size)
825 n = ceiling((stop - start)/step)
826 if n <= 0:
827 return Range(0)
828 canonical_stop = start + n*step
829 end = canonical_stop - step
830 ss = step*self.step
831 return Range(self[start], self[end] + ss, ss)
832 else: # infinite Range
833 start = i.start
834 stop = i.stop
835 if i.step == 0:
836 raise ValueError(zerostep)
837 step = i.step or 1
838 ss = step*self.step
839 #---------------------
840 # handle infinite Range
841 # i.e. Range(-oo, oo) or Range(oo, -oo, -1)
842 # --------------------
843 if self.start.is_infinite and self.stop.is_infinite:
844 raise ValueError(infinite)
845 #---------------------
846 # handle infinite on right
847 # e.g. Range(0, oo) or Range(0, -oo, -1)
848 # --------------------
849 if self.stop.is_infinite:
850 # start and stop are not interdependent --
851 # they only depend on step --so we use the
852 # equivalent reversed values
853 return self.reversed[
854 stop if stop is None else -stop + 1:
855 start if start is None else -start:
856 step].reversed
857 #---------------------
858 # handle infinite on the left
859 # e.g. Range(oo, 0, -1) or Range(-oo, 0)
860 # --------------------
861 # consider combinations of
862 # start/stop {== None, < 0, == 0, > 0} and
863 # step {< 0, > 0}
864 if start is None:
865 if stop is None:
866 if step < 0:
867 return Range(self[-1], self.start, ss)
868 elif step > 1:
869 raise ValueError(ambiguous)
870 else: # == 1
871 return self
872 elif stop < 0:
873 if step < 0:
874 return Range(self[-1], self[stop], ss)
875 else: # > 0
876 return Range(self.start, self[stop], ss)
877 elif stop == 0:
878 if step > 0:
879 return Range(0)
880 else: # < 0
881 raise ValueError(ooslice)
882 elif stop == 1:
883 if step > 0:
884 raise ValueError(ooslice) # infinite singleton
885 else: # < 0
886 raise ValueError(ooslice)
887 else: # > 1
888 raise ValueError(ooslice)
889 elif start < 0:
890 if stop is None:
891 if step < 0:
892 return Range(self[start], self.start, ss)
893 else: # > 0
894 return Range(self[start], self.stop, ss)
895 elif stop < 0:
896 return Range(self[start], self[stop], ss)
897 elif stop == 0:
898 if step < 0:
899 raise ValueError(ooslice)
900 else: # > 0
901 return Range(0)
902 elif stop > 0:
903 raise ValueError(ooslice)
904 elif start == 0:
905 if stop is None:
906 if step < 0:
907 raise ValueError(ooslice) # infinite singleton
908 elif step > 1:
909 raise ValueError(ambiguous)
910 else: # == 1
911 return self
912 elif stop < 0:
913 if step > 1:
914 raise ValueError(ambiguous)
915 elif step == 1:
916 return Range(self.start, self[stop], ss)
917 else: # < 0
918 return Range(0)
919 else: # >= 0
920 raise ValueError(ooslice)
921 elif start > 0:
922 raise ValueError(ooslice)
923 else:
924 if self.start == self.stop:
925 raise IndexError('Range index out of range')
926 if not (all(i.is_integer or i.is_infinite
927 for i in self.args) and ((self.stop - self.start)/
928 self.step).is_extended_positive):
929 raise ValueError('Invalid method for symbolic Range')
930 if i == 0:
931 if self.start.is_infinite:
932 raise ValueError(ooslice)
933 return self.start
934 if i == -1:
935 if self.stop.is_infinite:
936 raise ValueError(ooslice)
937 return self.stop - self.step
938 n = self.size # must be known for any other index
939 rv = (self.stop if i < 0 else self.start) + i*self.step
940 if rv.is_infinite:
941 raise ValueError(ooslice)
942 val = (rv - self.start)/self.step
943 rel = fuzzy_or([val.is_infinite,
944 fuzzy_and([val.is_nonnegative, (n-val).is_nonnegative])])
945 if rel:
946 return rv
947 if rel is None:
948 raise ValueError('Invalid method for symbolic Range')
949 raise IndexError("Range index out of range")
951 @property
952 def _inf(self):
953 if not self:
954 return S.EmptySet.inf
955 if self.has(Symbol):
956 if all(i.is_integer or i.is_infinite for i in self.args):
957 dif = self.stop - self.start
958 if self.step.is_positive and dif.is_positive:
959 return self.start
960 elif self.step.is_negative and dif.is_negative:
961 return self.stop - self.step
962 raise ValueError('invalid method for symbolic range')
963 if self.step > 0:
964 return self.start
965 else:
966 return self.stop - self.step
968 @property
969 def _sup(self):
970 if not self:
971 return S.EmptySet.sup
972 if self.has(Symbol):
973 if all(i.is_integer or i.is_infinite for i in self.args):
974 dif = self.stop - self.start
975 if self.step.is_positive and dif.is_positive:
976 return self.stop - self.step
977 elif self.step.is_negative and dif.is_negative:
978 return self.start
979 raise ValueError('invalid method for symbolic range')
980 if self.step > 0:
981 return self.stop - self.step
982 else:
983 return self.start
985 @property
986 def _boundary(self):
987 return self
989 def as_relational(self, x):
990 """Rewrite a Range in terms of equalities and logic operators. """
991 if self.start.is_infinite:
992 assert not self.stop.is_infinite # by instantiation
993 a = self.reversed.start
994 else:
995 a = self.start
996 step = self.step
997 in_seq = Eq(Mod(x - a, step), 0)
998 ints = And(Eq(Mod(a, 1), 0), Eq(Mod(step, 1), 0))
999 n = (self.stop - self.start)/self.step
1000 if n == 0:
1001 return S.EmptySet.as_relational(x)
1002 if n == 1:
1003 return And(Eq(x, a), ints)
1004 try:
1005 a, b = self.inf, self.sup
1006 except ValueError:
1007 a = None
1008 if a is not None:
1009 range_cond = And(
1010 x > a if a.is_infinite else x >= a,
1011 x < b if b.is_infinite else x <= b)
1012 else:
1013 a, b = self.start, self.stop - self.step
1014 range_cond = Or(
1015 And(self.step >= 1, x > a if a.is_infinite else x >= a,
1016 x < b if b.is_infinite else x <= b),
1017 And(self.step <= -1, x < a if a.is_infinite else x <= a,
1018 x > b if b.is_infinite else x >= b))
1019 return And(in_seq, ints, range_cond)
1022_sympy_converter[range] = lambda r: Range(r.start, r.stop, r.step)
1024def normalize_theta_set(theta):
1025 r"""
1026 Normalize a Real Set `theta` in the interval `[0, 2\pi)`. It returns
1027 a normalized value of theta in the Set. For Interval, a maximum of
1028 one cycle $[0, 2\pi]$, is returned i.e. for theta equal to $[0, 10\pi]$,
1029 returned normalized value would be $[0, 2\pi)$. As of now intervals
1030 with end points as non-multiples of ``pi`` is not supported.
1032 Raises
1033 ======
1035 NotImplementedError
1036 The algorithms for Normalizing theta Set are not yet
1037 implemented.
1038 ValueError
1039 The input is not valid, i.e. the input is not a real set.
1040 RuntimeError
1041 It is a bug, please report to the github issue tracker.
1043 Examples
1044 ========
1046 >>> from sympy.sets.fancysets import normalize_theta_set
1047 >>> from sympy import Interval, FiniteSet, pi
1048 >>> normalize_theta_set(Interval(9*pi/2, 5*pi))
1049 Interval(pi/2, pi)
1050 >>> normalize_theta_set(Interval(-3*pi/2, pi/2))
1051 Interval.Ropen(0, 2*pi)
1052 >>> normalize_theta_set(Interval(-pi/2, pi/2))
1053 Union(Interval(0, pi/2), Interval.Ropen(3*pi/2, 2*pi))
1054 >>> normalize_theta_set(Interval(-4*pi, 3*pi))
1055 Interval.Ropen(0, 2*pi)
1056 >>> normalize_theta_set(Interval(-3*pi/2, -pi/2))
1057 Interval(pi/2, 3*pi/2)
1058 >>> normalize_theta_set(FiniteSet(0, pi, 3*pi))
1059 {0, pi}
1061 """
1062 from sympy.functions.elementary.trigonometric import _pi_coeff
1064 if theta.is_Interval:
1065 interval_len = theta.measure
1066 # one complete circle
1067 if interval_len >= 2*S.Pi:
1068 if interval_len == 2*S.Pi and theta.left_open and theta.right_open:
1069 k = _pi_coeff(theta.start)
1070 return Union(Interval(0, k*S.Pi, False, True),
1071 Interval(k*S.Pi, 2*S.Pi, True, True))
1072 return Interval(0, 2*S.Pi, False, True)
1074 k_start, k_end = _pi_coeff(theta.start), _pi_coeff(theta.end)
1076 if k_start is None or k_end is None:
1077 raise NotImplementedError("Normalizing theta without pi as coefficient is "
1078 "not yet implemented")
1079 new_start = k_start*S.Pi
1080 new_end = k_end*S.Pi
1082 if new_start > new_end:
1083 return Union(Interval(S.Zero, new_end, False, theta.right_open),
1084 Interval(new_start, 2*S.Pi, theta.left_open, True))
1085 else:
1086 return Interval(new_start, new_end, theta.left_open, theta.right_open)
1088 elif theta.is_FiniteSet:
1089 new_theta = []
1090 for element in theta:
1091 k = _pi_coeff(element)
1092 if k is None:
1093 raise NotImplementedError('Normalizing theta without pi as '
1094 'coefficient, is not Implemented.')
1095 else:
1096 new_theta.append(k*S.Pi)
1097 return FiniteSet(*new_theta)
1099 elif theta.is_Union:
1100 return Union(*[normalize_theta_set(interval) for interval in theta.args])
1102 elif theta.is_subset(S.Reals):
1103 raise NotImplementedError("Normalizing theta when, it is of type %s is not "
1104 "implemented" % type(theta))
1105 else:
1106 raise ValueError(" %s is not a real set" % (theta))
1109class ComplexRegion(Set):
1110 r"""
1111 Represents the Set of all Complex Numbers. It can represent a
1112 region of Complex Plane in both the standard forms Polar and
1113 Rectangular coordinates.
1115 * Polar Form
1116 Input is in the form of the ProductSet or Union of ProductSets
1117 of the intervals of ``r`` and ``theta``, and use the flag ``polar=True``.
1119 .. math:: Z = \{z \in \mathbb{C} \mid z = r\times (\cos(\theta) + I\sin(\theta)), r \in [\texttt{r}], \theta \in [\texttt{theta}]\}
1121 * Rectangular Form
1122 Input is in the form of the ProductSet or Union of ProductSets
1123 of interval of x and y, the real and imaginary parts of the Complex numbers in a plane.
1124 Default input type is in rectangular form.
1126 .. math:: Z = \{z \in \mathbb{C} \mid z = x + Iy, x \in [\operatorname{re}(z)], y \in [\operatorname{im}(z)]\}
1128 Examples
1129 ========
1131 >>> from sympy import ComplexRegion, Interval, S, I, Union
1132 >>> a = Interval(2, 3)
1133 >>> b = Interval(4, 6)
1134 >>> c1 = ComplexRegion(a*b) # Rectangular Form
1135 >>> c1
1136 CartesianComplexRegion(ProductSet(Interval(2, 3), Interval(4, 6)))
1138 * c1 represents the rectangular region in complex plane
1139 surrounded by the coordinates (2, 4), (3, 4), (3, 6) and
1140 (2, 6), of the four vertices.
1142 >>> c = Interval(1, 8)
1143 >>> c2 = ComplexRegion(Union(a*b, b*c))
1144 >>> c2
1145 CartesianComplexRegion(Union(ProductSet(Interval(2, 3), Interval(4, 6)), ProductSet(Interval(4, 6), Interval(1, 8))))
1147 * c2 represents the Union of two rectangular regions in complex
1148 plane. One of them surrounded by the coordinates of c1 and
1149 other surrounded by the coordinates (4, 1), (6, 1), (6, 8) and
1150 (4, 8).
1152 >>> 2.5 + 4.5*I in c1
1153 True
1154 >>> 2.5 + 6.5*I in c1
1155 False
1157 >>> r = Interval(0, 1)
1158 >>> theta = Interval(0, 2*S.Pi)
1159 >>> c2 = ComplexRegion(r*theta, polar=True) # Polar Form
1160 >>> c2 # unit Disk
1161 PolarComplexRegion(ProductSet(Interval(0, 1), Interval.Ropen(0, 2*pi)))
1163 * c2 represents the region in complex plane inside the
1164 Unit Disk centered at the origin.
1166 >>> 0.5 + 0.5*I in c2
1167 True
1168 >>> 1 + 2*I in c2
1169 False
1171 >>> unit_disk = ComplexRegion(Interval(0, 1)*Interval(0, 2*S.Pi), polar=True)
1172 >>> upper_half_unit_disk = ComplexRegion(Interval(0, 1)*Interval(0, S.Pi), polar=True)
1173 >>> intersection = unit_disk.intersect(upper_half_unit_disk)
1174 >>> intersection
1175 PolarComplexRegion(ProductSet(Interval(0, 1), Interval(0, pi)))
1176 >>> intersection == upper_half_unit_disk
1177 True
1179 See Also
1180 ========
1182 CartesianComplexRegion
1183 PolarComplexRegion
1184 Complexes
1186 """
1187 is_ComplexRegion = True
1189 def __new__(cls, sets, polar=False):
1190 if polar is False:
1191 return CartesianComplexRegion(sets)
1192 elif polar is True:
1193 return PolarComplexRegion(sets)
1194 else:
1195 raise ValueError("polar should be either True or False")
1197 @property
1198 def sets(self):
1199 """
1200 Return raw input sets to the self.
1202 Examples
1203 ========
1205 >>> from sympy import Interval, ComplexRegion, Union
1206 >>> a = Interval(2, 3)
1207 >>> b = Interval(4, 5)
1208 >>> c = Interval(1, 7)
1209 >>> C1 = ComplexRegion(a*b)
1210 >>> C1.sets
1211 ProductSet(Interval(2, 3), Interval(4, 5))
1212 >>> C2 = ComplexRegion(Union(a*b, b*c))
1213 >>> C2.sets
1214 Union(ProductSet(Interval(2, 3), Interval(4, 5)), ProductSet(Interval(4, 5), Interval(1, 7)))
1216 """
1217 return self.args[0]
1219 @property
1220 def psets(self):
1221 """
1222 Return a tuple of sets (ProductSets) input of the self.
1224 Examples
1225 ========
1227 >>> from sympy import Interval, ComplexRegion, Union
1228 >>> a = Interval(2, 3)
1229 >>> b = Interval(4, 5)
1230 >>> c = Interval(1, 7)
1231 >>> C1 = ComplexRegion(a*b)
1232 >>> C1.psets
1233 (ProductSet(Interval(2, 3), Interval(4, 5)),)
1234 >>> C2 = ComplexRegion(Union(a*b, b*c))
1235 >>> C2.psets
1236 (ProductSet(Interval(2, 3), Interval(4, 5)), ProductSet(Interval(4, 5), Interval(1, 7)))
1238 """
1239 if self.sets.is_ProductSet:
1240 psets = ()
1241 psets = psets + (self.sets, )
1242 else:
1243 psets = self.sets.args
1244 return psets
1246 @property
1247 def a_interval(self):
1248 """
1249 Return the union of intervals of `x` when, self is in
1250 rectangular form, or the union of intervals of `r` when
1251 self is in polar form.
1253 Examples
1254 ========
1256 >>> from sympy import Interval, ComplexRegion, Union
1257 >>> a = Interval(2, 3)
1258 >>> b = Interval(4, 5)
1259 >>> c = Interval(1, 7)
1260 >>> C1 = ComplexRegion(a*b)
1261 >>> C1.a_interval
1262 Interval(2, 3)
1263 >>> C2 = ComplexRegion(Union(a*b, b*c))
1264 >>> C2.a_interval
1265 Union(Interval(2, 3), Interval(4, 5))
1267 """
1268 a_interval = []
1269 for element in self.psets:
1270 a_interval.append(element.args[0])
1272 a_interval = Union(*a_interval)
1273 return a_interval
1275 @property
1276 def b_interval(self):
1277 """
1278 Return the union of intervals of `y` when, self is in
1279 rectangular form, or the union of intervals of `theta`
1280 when self is in polar form.
1282 Examples
1283 ========
1285 >>> from sympy import Interval, ComplexRegion, Union
1286 >>> a = Interval(2, 3)
1287 >>> b = Interval(4, 5)
1288 >>> c = Interval(1, 7)
1289 >>> C1 = ComplexRegion(a*b)
1290 >>> C1.b_interval
1291 Interval(4, 5)
1292 >>> C2 = ComplexRegion(Union(a*b, b*c))
1293 >>> C2.b_interval
1294 Interval(1, 7)
1296 """
1297 b_interval = []
1298 for element in self.psets:
1299 b_interval.append(element.args[1])
1301 b_interval = Union(*b_interval)
1302 return b_interval
1304 @property
1305 def _measure(self):
1306 """
1307 The measure of self.sets.
1309 Examples
1310 ========
1312 >>> from sympy import Interval, ComplexRegion, S
1313 >>> a, b = Interval(2, 5), Interval(4, 8)
1314 >>> c = Interval(0, 2*S.Pi)
1315 >>> c1 = ComplexRegion(a*b)
1316 >>> c1.measure
1317 12
1318 >>> c2 = ComplexRegion(a*c, polar=True)
1319 >>> c2.measure
1320 6*pi
1322 """
1323 return self.sets._measure
1325 def _kind(self):
1326 return self.args[0].kind
1328 @classmethod
1329 def from_real(cls, sets):
1330 """
1331 Converts given subset of real numbers to a complex region.
1333 Examples
1334 ========
1336 >>> from sympy import Interval, ComplexRegion
1337 >>> unit = Interval(0,1)
1338 >>> ComplexRegion.from_real(unit)
1339 CartesianComplexRegion(ProductSet(Interval(0, 1), {0}))
1341 """
1342 if not sets.is_subset(S.Reals):
1343 raise ValueError("sets must be a subset of the real line")
1345 return CartesianComplexRegion(sets * FiniteSet(0))
1347 def _contains(self, other):
1348 from sympy.functions import arg, Abs
1349 other = sympify(other)
1350 isTuple = isinstance(other, Tuple)
1351 if isTuple and len(other) != 2:
1352 raise ValueError('expecting Tuple of length 2')
1354 # If the other is not an Expression, and neither a Tuple
1355 if not isinstance(other, (Expr, Tuple)):
1356 return S.false
1357 # self in rectangular form
1358 if not self.polar:
1359 re, im = other if isTuple else other.as_real_imag()
1360 return fuzzy_or(fuzzy_and([
1361 pset.args[0]._contains(re),
1362 pset.args[1]._contains(im)])
1363 for pset in self.psets)
1365 # self in polar form
1366 elif self.polar:
1367 if other.is_zero:
1368 # ignore undefined complex argument
1369 return fuzzy_or(pset.args[0]._contains(S.Zero)
1370 for pset in self.psets)
1371 if isTuple:
1372 r, theta = other
1373 else:
1374 r, theta = Abs(other), arg(other)
1375 if theta.is_real and theta.is_number:
1376 # angles in psets are normalized to [0, 2pi)
1377 theta %= 2*S.Pi
1378 return fuzzy_or(fuzzy_and([
1379 pset.args[0]._contains(r),
1380 pset.args[1]._contains(theta)])
1381 for pset in self.psets)
1384class CartesianComplexRegion(ComplexRegion):
1385 r"""
1386 Set representing a square region of the complex plane.
1388 .. math:: Z = \{z \in \mathbb{C} \mid z = x + Iy, x \in [\operatorname{re}(z)], y \in [\operatorname{im}(z)]\}
1390 Examples
1391 ========
1393 >>> from sympy import ComplexRegion, I, Interval
1394 >>> region = ComplexRegion(Interval(1, 3) * Interval(4, 6))
1395 >>> 2 + 5*I in region
1396 True
1397 >>> 5*I in region
1398 False
1400 See also
1401 ========
1403 ComplexRegion
1404 PolarComplexRegion
1405 Complexes
1406 """
1408 polar = False
1409 variables = symbols('x, y', cls=Dummy)
1411 def __new__(cls, sets):
1413 if sets == S.Reals*S.Reals:
1414 return S.Complexes
1416 if all(_a.is_FiniteSet for _a in sets.args) and (len(sets.args) == 2):
1418 # ** ProductSet of FiniteSets in the Complex Plane. **
1419 # For Cases like ComplexRegion({2, 4}*{3}), It
1420 # would return {2 + 3*I, 4 + 3*I}
1422 # FIXME: This should probably be handled with something like:
1423 # return ImageSet(Lambda((x, y), x+I*y), sets).rewrite(FiniteSet)
1424 complex_num = []
1425 for x in sets.args[0]:
1426 for y in sets.args[1]:
1427 complex_num.append(x + S.ImaginaryUnit*y)
1428 return FiniteSet(*complex_num)
1429 else:
1430 return Set.__new__(cls, sets)
1432 @property
1433 def expr(self):
1434 x, y = self.variables
1435 return x + S.ImaginaryUnit*y
1438class PolarComplexRegion(ComplexRegion):
1439 r"""
1440 Set representing a polar region of the complex plane.
1442 .. math:: Z = \{z \in \mathbb{C} \mid z = r\times (\cos(\theta) + I\sin(\theta)), r \in [\texttt{r}], \theta \in [\texttt{theta}]\}
1444 Examples
1445 ========
1447 >>> from sympy import ComplexRegion, Interval, oo, pi, I
1448 >>> rset = Interval(0, oo)
1449 >>> thetaset = Interval(0, pi)
1450 >>> upper_half_plane = ComplexRegion(rset * thetaset, polar=True)
1451 >>> 1 + I in upper_half_plane
1452 True
1453 >>> 1 - I in upper_half_plane
1454 False
1456 See also
1457 ========
1459 ComplexRegion
1460 CartesianComplexRegion
1461 Complexes
1463 """
1465 polar = True
1466 variables = symbols('r, theta', cls=Dummy)
1468 def __new__(cls, sets):
1470 new_sets = []
1471 # sets is Union of ProductSets
1472 if not sets.is_ProductSet:
1473 for k in sets.args:
1474 new_sets.append(k)
1475 # sets is ProductSets
1476 else:
1477 new_sets.append(sets)
1478 # Normalize input theta
1479 for k, v in enumerate(new_sets):
1480 new_sets[k] = ProductSet(v.args[0],
1481 normalize_theta_set(v.args[1]))
1482 sets = Union(*new_sets)
1483 return Set.__new__(cls, sets)
1485 @property
1486 def expr(self):
1487 r, theta = self.variables
1488 return r*(cos(theta) + S.ImaginaryUnit*sin(theta))
1491class Complexes(CartesianComplexRegion, metaclass=Singleton):
1492 """
1493 The :class:`Set` of all complex numbers
1495 Examples
1496 ========
1498 >>> from sympy import S, I
1499 >>> S.Complexes
1500 Complexes
1501 >>> 1 + I in S.Complexes
1502 True
1504 See also
1505 ========
1507 Reals
1508 ComplexRegion
1510 """
1512 is_empty = False
1513 is_finite_set = False
1515 # Override property from superclass since Complexes has no args
1516 @property
1517 def sets(self):
1518 return ProductSet(S.Reals, S.Reals)
1520 def __new__(cls):
1521 return Set.__new__(cls)