Ticket #13125: trac_13125_misc.patch

File trac_13125_misc.patch, 21.2 KB (added by vbraun, 9 years ago)

Updated patch

  • sage/sets/real_set.py

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1371948249 14400
    #      Sat Jun 22 20:44:09 2013 -0400
    # Node ID ff34397e5471faf869896ab2351c2d4f39b9826f
    # Parent  5ff9faece6300cb5e5080570e869e623fed21b6f
    Further improvements to RealSet
    
    diff --git a/sage/sets/real_set.py b/sage/sets/real_set.py
    a b  
    1212    sage: RealSet((0,1), [2,3])
    1313    (0, 1) + [2, 3]
    1414    sage: RealSet(-oo, oo)
    15     (-Infinity, +Infinity)
     15    (-oo, +oo)
    1616
    1717Brackets must be balanced in Python, so the naive notation for
    1818half-open intervals does not work::
     
    3131    sage: RealSet.point(1/2)
    3232    {1/2}
    3333    sage: RealSet.unbounded_below_open(0)
    34     (-Infinity, 0)
     34    (-oo, 0)
    3535    sage: RealSet.unbounded_below_closed(0)
    36     (-Infinity, 0]
     36    (-oo, 0]
    3737    sage: RealSet.unbounded_above_open(1)
    38     (1, +Infinity)
     38    (1, +oo)
    3939    sage: RealSet.unbounded_above_closed(1)
    40     [1, +Infinity)
     40    [1, +oo)
     41
     42AUTHORS:
     43
     44- Laurent Claessens (2010-12-10): Interval and ContinuousSet, posted
     45  to sage-devel at
     46  http://www.mail-archive.com/sage-support@googlegroups.com/msg21326.html_.
     47
     48- Ares Ribo (2011-10-24): Extended the previous work defining the
     49  class RealSet.
     50
     51- Jordi Saludes (2011-12-10): Documentation and file reorganization.
     52
     53- Volker Braun (2013-06-22): Rewrite
     54
     55This module has, in part, received funding from the European Union's
     56Seventh Framework Programme (FP7/2007-2013) under grant agreement
     57FP7-ICT-247914.
    4158"""
    4259
    4360########################################################################
     
    5168
    5269from sage.structure.parent import Parent
    5370from sage.structure.unique_representation import UniqueRepresentation
     71from sage.rings.all import ZZ
    5472from sage.rings.real_lazy import LazyFieldElement, RLF
    5573from sage.rings.infinity import infinity, minus_infinity
    5674
     
    6482        You are not supposed to create :class:`RealInterval` objects
    6583        yourself. Always use :class:`RealSet` instead.
    6684
     85        INPUT:
     86
     87        - ``lower`` -- real or minus infinity. The lower bound of the
     88          interval.
     89
     90        - ``lower_closed`` -- boolean. Whether the interval is closed
     91          at the lower bound.
     92
     93        - ``upper`` -- real or (plus) infinity. The upper bound of the
     94          interval.
     95
     96        - ``upper_closed`` -- boolean. Whether the interval is closed
     97          at the upper bound.
     98
     99        - ``check`` -- boolean keyword argument. Whether to check the
     100          other arguments for validity.
     101
    67102        EXAMPLES::
    68103
    69104            sage: RealSet([0, oo])
     
    76111        self._lower_closed = lower_closed
    77112        self._upper_closed = upper_closed
    78113        if check:
    79             if not isinstance(lower, LazyFieldElement):
    80                 raise ValueError('lower bound must be in RLF')
    81             if not isinstance(upper, LazyFieldElement):
    82                 raise ValueError('upper bound must be in RLF')
     114            if not (isinstance(lower, LazyFieldElement) or lower is minus_infinity):
     115                raise ValueError('lower bound must be in RLF or minus infinity')
     116            if not (isinstance(upper, LazyFieldElement) or upper is infinity):
     117                raise ValueError('upper bound must be in RLF or plus infinity')
    83118            if not isinstance(lower_closed, bool):
    84119                raise ValueError('lower_closed must be boolean')
    85120            if not isinstance(upper_closed, bool):
    86121                raise ValueError('upper_closed must be boolean')
    87             if lower == infinity or upper == minus_infinity:
    88                 raise ValueError('only lower/upper bound can be minus/plus infinity')
    89             if lower > upper:
     122            # comparison of infinity with RLF is broken
     123            if not(lower is minus_infinity or upper is infinity) and lower > upper:
    90124                raise ValueError('lower/upper bounds are not sorted')
    91125            if (lower_closed and lower == minus_infinity):
    92126                raise ValueError('interval cannot be closed at -oo')
     
    110144            sage: I.is_empty()
    111145            False
    112146        """
    113         return (self._lower == self._upper) and not (self._lower_closed or self._upper_closed)
     147        return (self._lower == self._upper) and not (self._lower_closed and self._upper_closed)
    114148
    115149    def is_point(self):
    116150        """
     
    144178            sage: I.upper()
    145179            1
    146180        """
    147         return self._lower._value
    148 
     181        if self._lower is minus_infinity:
     182            return minus_infinity
     183        else:
     184            return self._lower._value
     185   
    149186    def upper(self):
    150187        """
    151188        Return the upper bound
     
    162199            sage: I.upper()
    163200            1
    164201        """
    165         return self._upper._value
     202        if self._upper is infinity:
     203            return infinity
     204        else:
     205            return self._upper._value
    166206               
    167207    def lower_closed(self):
    168208        """
     
    296336            {0}
    297337        """
    298338        if self.is_point():
    299             return '{' + str(self._lower._value) + '}'
     339            return '{' + str(self.lower()) + '}'
    300340        s =  '[' if self._lower_closed else '('
    301         s += str(self._lower._value)
     341        if self.lower() is minus_infinity:
     342            s += '-oo'
     343        else:
     344            s += str(self.lower())
    302345        s += ', '
    303         s += str(self._upper._value)
     346        if self.upper() is infinity:
     347            s += '+oo'
     348        else:
     349            s += str(self.upper())
    304350        s +=  ']' if self._upper_closed else ')'
    305351        return s
    306352
     
    317363            sage: RealSet.open(0,1)[0].closure()
    318364            [0, 1]
    319365            sage: RealSet.open(-oo,1)[0].closure()
    320             (-Infinity, 1]
     366            (-oo, 1]
    321367            sage: RealSet.open(0, oo)[0].closure()
    322             [0, +Infinity)
     368            [0, +oo)
    323369        """
    324370        lower_closed = (self._lower != minus_infinity)
    325371        upper_closed = (self._upper != infinity)
     
    338384            sage: RealSet.closed(0, 1)[0].interior()
    339385            (0, 1)
    340386            sage: RealSet.open_closed(-oo, 1)[0].interior()
    341             (-Infinity, 1)
     387            (-oo, 1)
    342388            sage: RealSet.closed_open(0, oo)[0].interior()
    343             (0, +Infinity)
     389            (0, +oo)
    344390        """
    345391        return RealInterval(self._lower, False, self._upper, False)
    346392       
     
    512558            lower = upper = RLF(0)
    513559            lower_closed = upper_closed = False
    514560        return RealInterval(lower, lower_closed, upper, upper_closed)
     561
     562    def contains(self, x):
     563        """
     564        Return whether `x` is contained in the interval
     565
     566        INPUT:
     567
     568        - ``x`` -- a real number.
     569
     570        OUTPUT:
     571
     572        Boolean.
     573
     574        EXAMPLES::
    515575       
     576            sage: i = RealSet.open_closed(0,2)[0]; i
     577            (0, 2]
     578            sage: i.contains(0)
     579            False
     580            sage: i.contains(1)
     581            True
     582            sage: i.contains(2)
     583            True
     584        """
     585        cmp_lower = cmp(self._lower, x)
     586        cmp_upper = cmp(x, self._upper)
     587        if cmp_lower == cmp_upper == -1:
     588            return True
     589        if cmp_lower == 0:
     590            return self._lower_closed
     591        if cmp_upper == 0:
     592            return self._upper_closed
     593        return False
    516594
    517595
    518596class RealSet(UniqueRepresentation, Parent):
     
    535613            sage: RealSet(RealSet.open_closed(0,1), RealSet.closed_open(2,3))
    536614            (0, 1] + [2, 3)
    537615        """
     616        if len(args) == 1 and isinstance(args[0], RealSet):
     617            return args[0]   # common optimization
    538618        intervals = []
    539619        if len(args) == 2:
    540620            # allow RealSet(0,1) interval constructor
     
    588668        """
    589669        self._intervals = intervals
    590670   
     671    def __cmp__(self, other):
     672        """
     673        Intervals are sorted by lower bound, then upper bound
     674
     675        OUTPUT:
     676
     677        `-1`, `0`, or `+1` depending on how the intervals compare.
     678       
     679        EXAMPLES::
     680
     681             sage: I1 = RealSet.open_closed(1, 3);  I1
     682             (1, 3]
     683             sage: I2 = RealSet.open_closed(0, 5);  I2
     684             (0, 5]
     685             sage: cmp(I1, I2)
     686             1
     687             sage: sorted([I1, I2])
     688             [(0, 5], (1, 3]]
     689             sage: I1 == I1
     690             True
     691        """
     692        # note that the interval representation is normalized into a
     693        # unique form
     694        return cmp(self._intervals, other._intervals)
     695
    591696    def __iter__(self):
    592697        """
    593698        Iterate over the component intervals is ascending order
     
    618723            sage: s = RealSet(RealSet.open_closed(0,1), RealSet.closed_open(2,3))
    619724            sage: s.n_components()
    620725            2
    621             sage: len(s)   # shorthand
    622             2
    623726        """
    624727        return len(self._intervals)
    625728
    626     __len__ = n_components
     729    def cardinality(self):
     730        """
     731        Return the cardinality of the subset of the real line.
     732
     733        OUTPUT:
     734       
     735        Integer or infinity. The size of a discrete set is the number
     736        of points; the size of a real interval is Infinity.
     737
     738        EXAMPLES::
     739
     740           sage: RealSet([0, 0], [1, 1], [3, 3]).cardinality()
     741           3
     742           sage: RealSet(0,3).cardinality()
     743           +Infinity
     744        """
     745        n = ZZ(0)
     746        for interval in self._intervals:
     747            if interval.is_point():
     748                n += 1
     749            else:
     750                return infinity
     751        return n
     752
     753    def is_empty(self):
     754        """
     755        Return whether the set is empty
     756       
     757        EXAMPLES::
     758
     759            sage: RealSet(0, 1).is_empty()
     760            False
     761            sage: RealSet(0, 0).is_empty()
     762            True
     763        """
     764        return len(self._intervals) == 0
    627765
    628766    def get_interval(self, i):
    629767        """
     
    734872            return ' + '.join(map(repr, self._intervals))
    735873
    736874    @staticmethod
    737     def _prep(lower, upper):
     875    def _prep(lower, upper=None):
    738876        """
    739877        Helper to prepare the lower and upper bound
    740878
     
    742880
    743881            sage: RealSet._prep(1, 0)
    744882            (0, 1)
     883            sage: RealSet._prep(oo)
     884            +Infinity
    745885        """
    746         lower = RLF(lower)
    747         upper = RLF(upper)
    748         if upper < lower:
     886        if lower == minus_infinity:
     887            lower = minus_infinity
     888        if lower == infinity:
     889            lower = infinity
     890        else:
     891            lower = RLF(lower)
     892        if upper is None:
     893            return lower
     894        if upper == minus_infinity:
     895            upper = minus_infinity
     896        if upper == infinity:
     897            upper = infinity
     898        else:
     899            upper = RLF(upper)
     900        if upper is infinity or lower is minus_infinity:
     901            return lower, upper
     902        elif lower is infinity or upper is minus_infinity:
     903            return upper, lower
     904        elif upper < lower:
    749905            return upper, lower
    750906        else:
    751907            return lower, upper
     
    801957
    802958        INPUT:
    803959
    804         - ``p``, ``upper`` -- a real number.
     960        - ``p`` -- a real number.
    805961
    806962        OUTPUT:
    807963
     
    812968            sage: RealSet.open(1, 0)
    813969            (0, 1)
    814970        """
    815         p = RLF(p)
     971        p = RealSet._prep(p)
    816972        return RealSet(RealInterval(p, True, p, True))
    817973   
    818974    @staticmethod
     
    8771033        EXAMPLES::
    8781034
    8791035            sage: RealSet.unbounded_below_closed(1)
    880             (-Infinity, 1]
     1036            (-oo, 1]
    8811037        """
    882         return RealSet(RealInterval(RLF(minus_infinity), False, RLF(bound), True))
     1038        bound = RealSet._prep(bound)
     1039        return RealSet(RealInterval(minus_infinity, False, bound, True))
    8831040
    8841041    @staticmethod
    8851042    def unbounded_below_open(bound):
     
    8971054        EXAMPLES::
    8981055
    8991056            sage: RealSet.unbounded_below_open(1)
    900             (-Infinity, 1)
     1057            (-oo, 1)
    9011058        """
     1059        bound = RealSet._prep(bound)
    9021060        return RealSet(RealInterval(RLF(minus_infinity), False, RLF(bound), False))
    9031061
    9041062    @staticmethod
     
    9181076        EXAMPLES::
    9191077
    9201078            sage: RealSet.unbounded_above_closed(1)
    921             [1, +Infinity)
     1079            [1, +oo)
    9221080        """
     1081        bound = RealSet._prep(bound)
    9231082        return RealSet(RealInterval(RLF(bound), True, RLF(infinity), False))
    9241083
    9251084    @staticmethod
     
    9391098        EXAMPLES::
    9401099
    9411100            sage: RealSet.unbounded_above_open(1)
    942             (1, +Infinity)
     1101            (1, +oo)
    9431102        """
     1103        bound = RealSet._prep(bound)
    9441104        return RealSet(RealInterval(RLF(bound), False, RLF(infinity), False))
    9451105
    946     def union(self, other):
     1106    def union(self, *other):
    9471107        """
    9481108        Return the union of the two sets
    9491109
    9501110        INPUT:
    9511111       
    952         - ``other`` -- a :class:`RealSet`.
     1112        - ``other`` -- a :class:`RealSet` or data that defines one.
    9531113
    9541114        OUTPUT:
    9551115       
     
    9611121            sage: s2 = RealSet(1,3)
    9621122            sage: s1.union(s2)
    9631123            (0, 3)
     1124            sage: s1.union(1,3)
     1125            (0, 3)
    9641126            sage: s1 | s2    # syntactic sugar
    9651127            (0, 3)
    9661128            sage: s1 + s2    # syntactic sugar
    9671129            (0, 3)
    9681130        """
     1131        other = RealSet(*other)
    9691132        intervals = self._intervals + other._intervals
    9701133        return RealSet(*intervals)
    9711134   
    9721135    __or__ = union
    9731136    __add__ = union
    9741137
    975     def intersection(self, other):
     1138    def intersection(self, *other):
    9761139        """
    9771140        Return the intersection of the two sets
    9781141
    9791142        INPUT:
    9801143       
    981         - ``other`` -- a :class:`RealSet`.
     1144        - ``other`` -- a :class:`RealSet` or data that defines one.
    9821145
    9831146        OUTPUT:
    9841147       
     
    9871150        EXAMPLES::
    9881151
    9891152            sage: s1 = RealSet(0,2) + RealSet.unbounded_above_closed(10);  s1
    990             (0, 2) + [10, +Infinity)
     1153            (0, 2) + [10, +oo)
    9911154            sage: s2 = RealSet(1,3) + RealSet.unbounded_below_closed(-10);  s2
    992             (-Infinity, -10] + (1, 3)
     1155            (-oo, -10] + (1, 3)
    9931156            sage: s1.intersection(s2)
    9941157            (1, 2)
    9951158            sage: s1 & s2    # syntactic sugar
    9961159            (1, 2)
     1160
     1161            sage: s1 = RealSet((0, 1), (2, 3));  s1
     1162            (0, 1) + (2, 3)
     1163            sage: s2 = RealSet([0, 1], [2, 3]);  s2
     1164            [0, 1] + [2, 3]
     1165            sage: s3 = RealSet([1, 2]);  s3
     1166            [1, 2]
     1167            sage: s1.intersection(s2)
     1168            (0, 1) + (2, 3)
     1169            sage: s1.intersection(s3)
     1170            {}
     1171            sage: s2.intersection(s3)
     1172            {1} + {2}
    9971173        """
     1174        other = RealSet(*other)
    9981175        # TODO: this can be done in linear time since the intervals are already sorted
    9991176        intervals = []
    10001177        for i1 in self._intervals:
     
    10151192        EXAMPLES::
    10161193
    10171194            sage: s1 = RealSet(0,2) + RealSet.unbounded_above_closed(10);  s1
    1018             (0, 2) + [10, +Infinity)
     1195            (0, 2) + [10, +oo)
    10191196            sage: s1.inf()
    10201197            0
    10211198
    10221199            sage: s2 = RealSet(1,3) + RealSet.unbounded_below_closed(-10);  s2
    1023             (-Infinity, -10] + (1, 3)
     1200            (-oo, -10] + (1, 3)
    10241201            sage: s2.inf()
    10251202            -Infinity
    10261203        """
     
    10391216        EXAMPLES::
    10401217
    10411218            sage: s1 = RealSet(0,2) + RealSet.unbounded_above_closed(10);  s1
    1042             (0, 2) + [10, +Infinity)
     1219            (0, 2) + [10, +oo)
    10431220            sage: s1.sup()
    10441221            +Infinity
    10451222
    10461223            sage: s2 = RealSet(1,3) + RealSet.unbounded_below_closed(-10);  s2
    1047             (-Infinity, -10] + (1, 3)
     1224            (-oo, -10] + (1, 3)
    10481225            sage: s2.sup()
    10491226            3
    10501227        """
     
    10631240        EXAMPLES::
    10641241
    10651242            sage: RealSet(0,1).complement()
    1066             (-Infinity, 0] + [1, +Infinity)
     1243            (-oo, 0] + [1, +oo)
    10671244       
    10681245            sage: s1 = RealSet(0,2) + RealSet.unbounded_above_closed(10);  s1
    1069             (0, 2) + [10, +Infinity)
     1246            (0, 2) + [10, +oo)
    10701247            sage: s1.complement()
    1071             (-Infinity, 0] + [2, 10)
     1248            (-oo, 0] + [2, 10)
    10721249
    10731250            sage: s2 = RealSet(1,3) + RealSet.unbounded_below_closed(-10);  s2
    1074             (-Infinity, -10] + (1, 3)
     1251            (-oo, -10] + (1, 3)
    10751252            sage: s2.complement()
    1076             (-10, 1] + [3, +Infinity)
     1253            (-10, 1] + [3, +oo)
    10771254        """
    10781255        n = self.n_components()
    10791256        if n == 0:
     
    10951272            intervals.append(i)
    10961273        return RealSet(*intervals)
    10971274                             
    1098     def difference(self, other):
     1275    def difference(self, *other):
    10991276        """
    11001277        Return ``self`` with ``other`` subtracted
    11011278
    11021279        INPUT:
    11031280       
    1104         - ``other`` -- a :class:`RealSet`.
     1281        - ``other`` -- a :class:`RealSet` or data that defines one.
    11051282
    11061283        OUTPUT:
    11071284       
     
    11131290        A new :class:`RealSet`
    11141291
    11151292            sage: s1 = RealSet(0,2) + RealSet.unbounded_above_closed(10);  s1
    1116             (0, 2) + [10, +Infinity)
     1293            (0, 2) + [10, +oo)
    11171294            sage: s2 = RealSet(1,3) + RealSet.unbounded_below_closed(-10);  s2
    1118             (-Infinity, -10] + (1, 3)
     1295            (-oo, -10] + (1, 3)
    11191296            sage: s1.difference(s2)
    1120             (0, 1] + [10, +Infinity)
     1297            (0, 1] + [10, +oo)
    11211298            sage: s1 - s2    # syntactic sugar
    1122             (0, 1] + [10, +Infinity)
     1299            (0, 1] + [10, +oo)
    11231300            sage: s2.difference(s1)
    1124             (-Infinity, -10] + [2, 3)
     1301            (-oo, -10] + [2, 3)
    11251302            sage: s2 - s1    # syntactic sugar
    1126             (-Infinity, -10] + [2, 3)
     1303            (-oo, -10] + [2, 3)
     1304            sage: s1.difference(1,11)
     1305            (0, 1] + [11, +oo)
    11271306        """
     1307        other = RealSet(*other)
    11281308        return self.intersection(other.complement())
    11291309
    11301310    __sub__ = difference
     1311
     1312    def contains(self, x):
     1313        """
     1314        Return whether `x` is contained in the set
     1315
     1316        INPUT:
     1317
     1318        - ``x`` -- a real number.
     1319
     1320        OUTPUT:
     1321
     1322        Boolean.
     1323
     1324        EXAMPLES::
     1325       
     1326            sage: s = RealSet(0,2) + RealSet.unbounded_above_closed(10);  s
     1327            (0, 2) + [10, +oo)
     1328            sage: s.contains(1)
     1329            True
     1330            sage: s.contains(0)
     1331            False
     1332            sage: 10 in s    # syntactic sugar
     1333            True
     1334        """
     1335        x = RLF(x)
     1336        for interval in self._intervals:
     1337            if interval.contains(x):
     1338                return True
     1339        return False
     1340   
     1341    __contains__ = contains
     1342   
     1343    def is_included_in(self, *other):
     1344        r"""
     1345        Tests interval inclusion
     1346           
     1347        INPUT:
     1348
     1349        - ``*args`` -- a :class:`RealSet` or something that defines
     1350          one.
     1351
     1352        OUTPUT:
     1353       
     1354        Boolean.
     1355
     1356        EXAMPLES::
     1357       
     1358            sage: I = RealSet((1,2))
     1359            sage: J = RealSet((1,3))
     1360            sage: K = RealSet((2,3))
     1361            sage: I.is_included_in(J)
     1362            True
     1363            sage: J.is_included_in(K)
     1364            False
     1365        """
     1366        return RealSet(*other).intersection(self) == self
     1367
     1368    def an_element(self):
     1369        """
     1370        Return a point of the set
     1371
     1372        OUTPUT:
     1373
     1374        A real number. ``ValueError` if the set is empty.
     1375
     1376        EXAMPLES:
     1377
     1378            sage: RealSet.open_closed(0, 1).an_element()
     1379            1
     1380            sage: RealSet(0, 1).an_element()
     1381            1/2
     1382        """
     1383        if len(self._intervals) == 0:
     1384            raise ValueError('set is empty')
     1385        i = self._intervals[0]
     1386        if i.lower_closed():
     1387            return i.lower()
     1388        if i.upper_closed():
     1389            return i.upper()
     1390        return (i.lower() + i.upper())/ZZ(2)
     1391
     1392    def is_disjoint_from(self, *other):
     1393        """
     1394        Test whether the two sets are disjoint
     1395
     1396        INPUT:
     1397
     1398        - ``other`` -- a :class:`RealSet` or data defining one.
     1399
     1400        OUTPUT:
     1401
     1402        Boolean.
     1403
     1404        EXAMPLES::
     1405
     1406            sage: s1 = RealSet((0, 1), (2, 3));  s1
     1407            (0, 1) + (2, 3)
     1408            sage: s2 = RealSet([1, 2]);  s2
     1409            [1, 2]
     1410            sage: s1.is_disjoint_from(s2)
     1411            True
     1412            sage: s1.is_disjoint_from([1, 2])
     1413            True
     1414        """
     1415        other = RealSet(*other)
     1416        return self.intersection(other).is_empty()
     1417
     1418    @staticmethod
     1419    def are_pairwise_disjoint(*real_set_collection):
     1420        """
     1421        Test whether sets are pairwise disjoint
     1422       
     1423        INPUT:
     1424
     1425        - ``*real_set_collection`` -- a list/tuple/iterable of
     1426          :class:`RealSet`.
     1427 
     1428        OUTPUT:
     1429       
     1430        Boolean.
     1431       
     1432        EXAMPLES::
     1433       
     1434            sage: s1 = RealSet((0, 1), (2, 3))
     1435            sage: s2 = RealSet((1, 2))
     1436            sage: s3 = RealSet.point(3)
     1437            sage: RealSet.are_pairwise_disjoint(s1, s2, s3)
     1438            True
     1439            sage: RealSet.are_pairwise_disjoint(s1, s2, s3, [10,10])
     1440            True
     1441            sage: RealSet.are_pairwise_disjoint(s1, s2, s3, [-1, 1/2])
     1442            False
     1443        """
     1444        sets = map(RealSet, real_set_collection)
     1445        for i in range(len(sets)):
     1446            for j in range(i):
     1447                si = sets[i]
     1448                sj = sets[j]
     1449                if not si.is_disjoint_from(sj):
     1450                    return False
     1451        return True
     1452
     1453