Ticket #13125: trac_13125_realsets.patch

File trac_13125_realsets.patch, 26.2 KB (added by ares, 9 years ago)

Patch for realsets.py

  • sage/calculus/all.py

    # HG changeset patch
    # User Ares Ribo Mor <ares@canuda.net>
    # Date 1339891903 -7200
    # Node ID 4cb9b6eba7f1632356786161f3b7e470350b21ca
    # Parent  9ab4ab6e12d0ce97566db069205815303514de4d
    Trac 13125: Real sets consisting of intervals and isolated points
    
    diff --git a/sage/calculus/all.py b/sage/calculus/all.py
    a b  
    1515
    1616from var import (var, function, clear_vars)
    1717
     18from realsets import (RealSet, RInterval)
     19
    1820# We lazy_import the following modules since they import numpy which slows down sage startup
    1921from sage.misc.lazy_import import lazy_import
    2022lazy_import("sage.calculus.riemann",["Riemann_Map"])
  • new file sage/calculus/realsets.py

    diff --git a/sage/calculus/realsets.py b/sage/calculus/realsets.py
    new file mode 100644
    - +  
     1# -*- coding: utf8 -*-
     2r"""
     3    Reals sets consisting of union of real intervals and isolated points.
     4   
     5    This is based of previous work available from http://www.mail-archive.com/sage-support@googlegroups.com/msg21326.html
     6    but supporting now integration on real intervals and real sets.
     7   
     8    - Laurent Claessens (2010-12-10): Original Interval and ContinuousSet from 'http://www.mail-archive.com/sage-support@googlegroups.com/msg21326.html'.
     9        Defined a class Interval that represents an interval (can be open, closed, half open, unbounded), and implements union() and intersection() methods, as well
     10        as the __contains__() method that tests if a number is contained in the interval. Also defined the class ContinuousSet that represents finite union and
     11        intersections of intervals by a list of disjoint intervals. For the class ContinuousSet, union() and __contain__() methods are implemented.
     12
     13    - Ares Ribo (2011-10-24): Extended the previous work defining the class RealSet, that describes any real set as a list of disjoint intervals and a list of     
     14        isolated points. For this class, we implemented the intersection() ( union() and __contain__() as for ContinuousSets). We implemented the function 'subsets'
     15        which given two different real sets A and B returns if A is a (proper) subset of B, and the function 'setdiff' that returns the difference of two given real
     16        sets. Also we support definite integration over a RealSet, and we implemented the infimum and the supremum of a RealSet. We define the class RInterval of
     17        real intervals. A RInterval is now a RealSet, consituted as a list of disjoint intervals with a unique element and an empty list of isolated points.
     18
     19    - Jordi Saludes (2011-12-10): Documentation and file reorganization. Reimplementation of 'setdiff'. RInterval is now always an open interval. The boundary/ies
     20        can be added as isolated point/s if necessary, constituting a RealSet.
     21     
     22    Examples
     23   
     24    sage: A = RealSet([RInterval((1,2)),RInterval((3,4))],[1,2])
     25
     26    sage: A
     27    [ 1 :: 2 ] + ] 3 :: 4 [
     28
     29    sage: B = RealSet([RInterval((2,3))],[1])
     30
     31    sage: B
     32    ] 2 :: 3 [ + {1}
     33   
     34    """
     35
     36from sage.rings.infinity import Infinity
     37
     38
     39class RInterval(object):
     40    r"""
     41        Represents the real open interval between a and b: `(a,b)`
     42       
     43        sage: RInterval()
     44        ()
     45       
     46        it is the empty interval `\emptyset`.
     47       
     48        sage: RInterval().is_empty
     49        True
     50       
     51        sage: I = RInterval((2,4))
     52        sage: J = RInterval((1,3))
     53        sage: K = RInterval((0,1))
     54       
     55        sage: I2 = RInterval((2,+Infinity))
     56        sage: J3 = RInterval((-Infinity,3))
     57       
     58       
     59        Intersection of intervals give an interval:
     60       
     61        sage: I.intersection(J)
     62        (2, 3)
     63       
     64        sage: I.intersection(K)
     65        ()
     66       
     67        sage: I2.intersection(J3)
     68        (2, 3)
     69       
     70        Union returns a set of disjoint intervals:
     71       
     72        sage: I.union(J)
     73        [(1, 4)]
     74        sage: I.intersection(K)
     75        ()
     76        sage: I.union(K)
     77        [(2, 4), (0, 1)]
     78       
     79             
     80        Interval membership:
     81       
     82        sage: 3 in I
     83        True
     84       
     85        sage: 3 in J
     86        False
     87           
     88       
     89        Interval inclusion:
     90       
     91        sage: RInterval().included(I)
     92        True
     93       
     94        sage: I.included(RInterval())
     95        False
     96       
     97        sage: IJ = I.union(J)[0]
     98        sage: J.included(IJ)
     99        True
     100        sage: IJ.included(J)
     101        False
     102        sage: IJ.included(I)
     103        False
     104       
     105        """
     106   
     107    def __init__(self, bounds=None):
     108        r"""
     109            An open interval is defined by its bounds. See ``RInterval`` for full documentation.     
     110
     111            sage: RInterval((1,2))
     112            (1, 2)
     113            """
     114        if bounds and bounds[1] <= bounds[0]:
     115            raise ValueError, "Inverted bounds"
     116        self.bounds = bounds
     117
     118    def __hash__(self):
     119        r"""
     120            sage: I=RInterval((1,2))
     121            sage: hash(I)
     122            3713081631934410656
     123            """
     124        return hash(self.bounds)
     125 
     126    @property
     127    def is_empty(self):
     128        r"""
     129            Returns True if the interval is empty, and False otherwise.
     130
     131            sage: RInterval().is_empty
     132            True
     133            sage: RInterval((1,2)).is_empty
     134            False
     135            """
     136        return not self.bounds
     137
     138   
     139    def __repr__(self):
     140        r"""
     141            Returns the representation of the real interval from a to b as the string '(a,b)',
     142            and for the empty interval '()' is returned.
     143           
     144            sage: repr(RInterval((1,2)))
     145            '(1, 2)'
     146            sage: repr(RInterval())
     147            '()'
     148            """
     149        if self.bounds:
     150            return "(%s, %s)" % self.bounds
     151        else:
     152            return "()"
     153
     154    def __cmp__(self, other):
     155        r"""
     156            sage: I = RInterval((1,2))
     157            sage: J = RInterval((1,3))
     158            sage: I.__cmp__(J)
     159            -1
     160            """
     161        if self.is_empty:
     162            if other.is_empty: return 0
     163            return -1
     164        else:
     165            if other.is_empty: return 1
     166            a0,a1 = self.bounds
     167            b0,b1 = other.bounds
     168            if cmp(a0,b0) != 0:
     169                return cmp(a0,b0)
     170            else:
     171                return cmp(a1,b1)   
     172   
     173    def intersection(self, other):
     174        r"""
     175            Returns the interval intersection of intervals self and other
     176
     177            sage: I = RInterval((2,4))
     178            sage: J = RInterval((1,3))
     179            sage: K = RInterval((0,1))
     180       
     181            sage: I2 = RInterval((2,+Infinity))
     182            sage: J3 = RInterval((-Infinity,3))
     183         
     184            sage: I.intersection(J)
     185            (2, 3)
     186       
     187            sage: I.intersection(K)
     188            ()
     189       
     190            sage: I2.intersection(J3)
     191            (2, 3)
     192        """
     193
     194        if self.is_empty or other.is_empty:
     195            return RInterval()
     196        a0,a1 = self.bounds
     197        b0,b1 = other.bounds
     198        c0 = max(a0, b0)
     199        c1 = min(a1, b1)
     200        return c0 < c1 and RInterval((c0,c1)) or RInterval()
     201   
     202    def hull(self,other):
     203        r"""
     204            Returns the hull of the specified intervals, i.e. the smallest connected interval enclosing both intervals.
     205             
     206            sage: I=RInterval((1,2))
     207            sage: J=RInterval((3,4))
     208            sage: I.hull(J)
     209            (1, 4)
     210            """
     211 
     212        if self.is_empty: return other
     213        if other.is_empty: return self
     214        a0,a1 = self.bounds
     215        b0,b1 = other.bounds
     216        c0 = min(a0, b0)
     217        c1 = max(a1, b1)
     218        return c0 < c1 and RInterval((c0,c1)) or RInterval()
     219   
     220    def union(self,other):
     221        r"""
     222           The union of two intervals returns a set of disjoint intervals
     223           
     224           sage: I = RInterval((2,4))
     225           sage: J = RInterval((1,3))
     226           sage: K = RInterval((0,1))
     227       
     228           sage: I.union(J)
     229           [(1, 4)]
     230           sage: I.union(K)
     231           [(2, 4), (0, 1)]
     232           """   
     233
     234        if self.intersection(other).is_empty:
     235            return [self, other]
     236        else:
     237            return [self.hull(other)]
     238
     239   
     240    def __contains__(self,x):
     241        r"""
     242           Tests if a real number belongs to an interval
     243
     244           sage: I=RInterval((1,3))
     245           sage: 2 in I
     246           True
     247           sage: 1 in I
     248           False
     249           sage: 1.1 in I
     250           True
     251           """
     252        if self:
     253            x0,x1 = self.bounds
     254            return x0 < x and x < x1
     255        else:
     256            return False
     257
     258    def included(self, other):
     259        r"""
     260            Tests interval inclusion
     261           
     262            sage: I = RInterval((1,2))
     263            sage: J = RInterval((1,3))
     264            sage: K = RInterval((2,3))
     265            sage: I.included(J)
     266            True
     267            sage: J.included(K)
     268            False
     269            """
     270        return other.intersection(self) == self
     271
     272    def __neg__(self):
     273        """The opposite of an interval: `-(a, b) = (-b, -a)`
     274           sage: -RInterval((2, 3))
     275           (-3, -2)
     276        """
     277        if self.is_empty:
     278            return RInterval()
     279        a,b = self.bounds
     280        return RInterval((-b, -a))
     281
     282
     283    @classmethod
     284    def reduce(klass, intervals_list):
     285        """
     286            Return a set of disjoint intervals that represent the same set.
     287           
     288            sage: I = RInterval((1, 4))
     289            sage: J = RInterval((0, 2))
     290            sage: K = RInterval((3, 5))
     291            sage: L = RInterval((6, 7))
     292            sage: M = RInterval((7, 8))
     293            sage: RInterval.reduce([I,J,K,L,M])
     294            set([(0, 5), (6, 7), (7, 8)])
     295        """
     296        intervals = set(intervals_list)       
     297        while True:
     298            reduced1 = set()
     299            for I in intervals:
     300                for J in intervals:
     301                    reduced1 |= set(I.union(J))
     302            reduced2 = set(reduced1)
     303            for I in reduced1:
     304                for J in reduced1:
     305                    if I != J and I.included(J) and I in reduced2:
     306                            reduced2.remove(I)
     307            if intervals == reduced2:
     308                return intervals
     309            intervals = set(reduced2)
     310       
     311           
     312 
     313class RealSet(object):
     314    r"""
     315        Represent a set that can be the union of some intervals and isolated points.
     316       
     317        It consists of:
     318       
     319        - A list of disjoint open non-empty intervals.
     320       
     321        - A list of points. Each of these points belongs at most to one interval.
     322
     323        sage: RealSet([RInterval((1,2))],[1])
     324        [ 1 :: 2 [
     325        sage: RealSet([RInterval((1,2)), RInterval((3,4))],[1])
     326        [ 1 :: 2 [ + ] 3 :: 4 [
     327       
     328        A closed interval:
     329       
     330        sage: RealSet.cc_interval(1,4);
     331        [ 1 :: 4 ]
     332       
     333        A single point:
     334       
     335        sage: RealSet.singleton(1)
     336        {1}
     337       
     338        UNION
     339        Union is supported with intervals and can be nested :
     340       
     341        sage: I = RealSet.co_interval(1, 4)
     342        sage: J = RealSet.co_interval(4, 5)
     343        sage: M = RealSet.oc_interval(7, 8)
     344        sage: I.union(J).union(M)
     345        [ 1 :: 5 [ + ] 7 :: 8 ]
     346       
     347        INTERSECTION
     348       
     349        sage: I.intersection(J)
     350        {}
     351        sage: I.intersection(RealSet.cc_interval(2,5))
     352        [ 2 :: 4 [
     353       
     354        """
     355   
     356    def __init__(self, intervals=[], points=[]):
     357        r"""
     358            See ``RealSet`` for full documentation.     
     359
     360            sage: RealSet([RInterval((1,2))],[1])
     361            [ 1 :: 2 [
     362            sage: RealSet([RInterval((1,2)), RInterval((3,4))],[1])
     363            [ 1 :: 2 [ + ] 3 :: 4 [
     364            """
     365        self.intervals_list = intervals
     366        self.points_list = points
     367   
     368    @classmethod
     369    def cc_interval(klass, x0, x1):
     370        r"""
     371            Closed interval
     372
     373            sage: RealSet.cc_interval(1,2)
     374            [ 1 :: 2 ]
     375            """
     376        return RealSet([RInterval((x0,x1))], [x0,x1])
     377
     378    @classmethod
     379    def oc_interval(klass, x0, x1):
     380        r"""
     381            Right-half-open interval
     382   
     383            sage: RealSet.oc_interval(1,2)
     384            ] 1 :: 2 ]
     385            """
     386        return RealSet([RInterval((x0,x1))], [x1])
     387
     388    @classmethod
     389    def co_interval(klass, x0, x1):
     390        r"""
     391            Left-half-open interval
     392
     393            sage: RealSet.co_interval(1,2)
     394            [ 1 :: 2 [
     395            """
     396        return RealSet([RInterval((x0,x1))], [x0])
     397
     398    @classmethod
     399    def oo_interval(klass, x0, x1):
     400        r"""
     401            Open Interval
     402
     403            sage: RealSet.oo_interval(1,2)
     404            ] 1 :: 2 [
     405            """
     406        return RealSet([RInterval((x0,x1))], [])
     407
     408    @classmethod
     409    def singleton(klass, x):
     410        r"""
     411            A single point:
     412       
     413            sage: RealSet.singleton(1)
     414            {1}
     415            """
     416        return RealSet(points=[x])
     417
     418    @property
     419    def is_interval(self): 
     420        r"""Is this set a single interval ?
     421   
     422            sage: RealSet([RInterval((1,2))],[]).is_interval
     423            True
     424            sage: RealSet([RInterval((1,2))],[1]).is_interval
     425            True
     426            sage: RealSet([RInterval((1,2))],[1,2]).is_interval
     427            True
     428            sage: RealSet([RInterval((1,2))],[1,2,3]).is_interval
     429            False
     430            sage: RealSet([RInterval((1,2))],[1,3]).is_interval
     431            False
     432            sage: RealSet([RInterval((1,2)),RInterval((1,3))],[1,3])
     433            [ 1 :: 2 [ + ] 1 :: 3 ]
     434            sage: RealSet([RInterval((1,2)),RInterval((1,3))],[1,3]).is_interval
     435            True
     436            """
     437        self = self.reduce()
     438        if len(self.intervals_list) != 1 or len(self.points_list)>2:
     439            return False
     440        if len(self.points_list) == 1:
     441            return self.points_list[0] in self.intervals_list[0].bounds
     442        if len(self.points_list) == 2:
     443            return (self.points_list[0] in self.intervals_list[0].bounds) and (self.points_list[1] in self.intervals_list[0].bounds)
     444        else:    #len(self.intervals_list)==1 and not self.points_list
     445            return True   
     446 
     447    def bounds(self):     
     448        """Return the bounds provided it is an interval
     449           
     450           sage: RealSet.cc_interval(2, 3)
     451           [ 2 :: 3 ]
     452        """
     453        if self.is_interval:
     454            return self.intervals_list[0].bounds
     455        else:
     456            raise ValueError, "Not an interval."
     457
     458   
     459    def __contains__(self,x):
     460        """ is x in the realset?
     461             
     462            sage: I = RealSet.oo_interval(1, 3)
     463            sage: 2 in I
     464            True
     465            sage: 3 in I
     466            False
     467        """
     468        in_intervals = any(x in I for I in self.intervals_list)
     469        return in_intervals or x in self.points_list
     470
     471   
     472    def union(self, other):
     473        """
     474        sage: I = RealSet.oc_interval(0,1)
     475        sage: J = RealSet.oo_interval(1,2)
     476        sage: I.union(J)
     477        ] 0 :: 2 [
     478           
     479        """
     480        if self.is_empty: return other   
     481        if other.is_empty: return self
     482        intervals = list(self.intervals_list)
     483        intervals.extend(other.intervals_list)
     484        points = list(self.points_list)
     485        points.extend(other.points_list)
     486        points = list(set(points))
     487        return RealSet(intervals, points).reduce()
     488
     489
     490    def reduce(self):
     491        r"""Normalize Realset by:
     492            - replacing overlaping intervals with its union.
     493           
     494            - Removing points at the interior of intervals.
     495           
     496            - Replacing 'bridge points' and corresponding intervals with union. 
     497
     498            sage: RealSet([RInterval((1,2)),RInterval((1,4))],[1,3])
     499            [ 1 :: 2 [ + ] 1 :: 4 [ + {3}
     500            sage: RealSet([RInterval((1,2)),RInterval((1,4))],[1,3]).reduce()
     501            [ 1 :: 4 [
     502            sage: RealSet([RInterval((1,2)),RInterval((2,3))],[2])
     503            ] 1 :: 2 ] + ] 2 :: 3 [
     504            sage: RealSet([RInterval((1,2)),RInterval((2,3))],[2]).reduce()
     505            ] 1 :: 3 [
     506                     
     507            """
     508        intervals = RInterval.reduce(self.intervals_list)
     509        # No overlapping intervals now
     510        for p in self.points_list:
     511            if any(p in I for I in intervals):
     512                self.points_list.remove(p)
     513            bridge = [I for I in intervals if p in I.bounds]
     514            if len(bridge) == 2: # remove bridge
     515                K = bridge[0].hull(bridge[1])
     516                for I in bridge: intervals.remove(I)
     517                intervals.add(K)
     518                self.points_list.remove(p)
     519        # remaining points must be only in the boundary of intervals now
     520        self.intervals_list = list(intervals)
     521        return self
     522   
     523    def __repr__(self):
     524        r"""
     525            sage: repr(RealSet([RInterval((0,1)),RInterval((2,3))],[0,3,4,5]))
     526            '[ 0 :: 1 [ + ] 2 :: 3 ] + {4, 5}'
     527            sage: repr(RealSet())
     528            '{}'
     529            """
     530
     531        if self.is_empty: return '{}'
     532        points = list(self.points_list)
     533        def delim(p):
     534            b = p in points
     535            if b: points.remove(p)
     536            return b
     537        def stri(I):
     538            x0,x1 = I.bounds
     539            d0 = delim(x0) and '[ ' or '] '
     540            d1 = delim(x1) and ' ]' or ' ['
     541            return d0 + `x0` + ' :: ' + `x1` + d1
     542        str_intervals = " + ".join(map(stri, self.intervals_list))
     543        str_points = ', '.join([str(x) for x in points])
     544        if str_intervals and str_points:
     545            return str_intervals + ' + {%s}' % str_points
     546        if str_points:
     547            return '{%s}' % str_points
     548        return str_intervals
     549           
     550    @property
     551    def discrete(self):
     552        """
     553            RealSet is discrete (i.e: Does not contain intervals)?
     554           
     555            sage: RealSet.oo_interval(0,1).discrete
     556            False
     557            sage: RealSet(points=(1,2,3)).discrete
     558            True
     559        """
     560        return bool(len(self.intervals_list) == 0)
     561   
     562    @property
     563    def size(self):
     564        """The size of a discrete set is the number of points; the size of a real interval is Infinity:
     565           
     566           sage: RealSet(points=range(5)).size
     567           5
     568           sage: RealSet.oo_interval(0,3).size
     569           +Infinity
     570        """
     571        if self.discrete:
     572            return len(self.points_list)           
     573        else:   
     574            return Infinity
     575               
     576    def __eq__(self,other):
     577        """ Assume they are reduced
     578            sage: I = RealSet.oc_interval(0,1)
     579            sage: J = RealSet.co_interval(1,2)
     580            sage: I.intersection(J) == RealSet(points=[1])
     581            True
     582        """
     583        return self.subset(other) and other.subset(self)
     584               
     585    def different(self, A):
     586        r"""
     587            sage: A=RealSet([RInterval((1,2)),RInterval((1,4))],[1,3])
     588            sage: A
     589            [ 1 :: 2 [ + ] 1 :: 4 [ + {3}
     590            sage: B=RealSet([RInterval((1,2)),RInterval((1,4))],[1,3]).reduce()
     591            sage: B
     592            [ 1 :: 4 [
     593            sage: A.different(B)
     594            False
     595            sage: C=RealSet([RInterval((1,4))],[4])
     596            sage: A.different(C)
     597            True
     598            """
     599        self = self.reduce()
     600        A = A.reduce()
     601        return (self.points_list != A.points_list) or (self.intervals_list != A.intervals_list)
     602
     603    def subset(self, other, proper=False):
     604        """ A is subset of B
     605            sage: A = RealSet.oo_interval(0,1)
     606            sage: B = RealSet.cc_interval(0,1)
     607            sage: RealSet().subset(A)
     608            True
     609            sage: B.subset(A)
     610            False
     611            sage: A.subset(B)
     612            True
     613            sage: A.subset(A)
     614            True
     615            sage: A.subset(A, proper=True)
     616            False
     617        """
     618        if not all(p in other for p in self.points_list):
     619            return False
     620        for I in self.intervals_list:
     621            if not any(I.included(J) for J in other.intervals_list):
     622                return False
     623        return not (proper and other.subset(self))
     624
     625    def evalboundary(self, F):
     626        r""" It does not integration per se. You must provide the primitive.
     627            To obtain \int_I f dx , we must compute I.evalboundary(F) where F is the primitive of f, since I.evalboundary(F) = F(b) - F(a)
     628
     629            EXAMPLE:
     630            Integrate `f(x) = |x|` on a set.
     631            sage: F = lambda x: x**2/2.
     632            sage: I1 = RealSet.cc_interval(-1,0)
     633            sage: I2 = RealSet.cc_interval(1,2)
     634            sage: I1.union(I2).evalboundary(F)
     635            1.00000000000000
     636            sage: RealSet(points=range(10)).evalboundary(F)
     637            0
     638        """
     639        integral = 0   
     640        for I in self.intervals_list:
     641            a,b = I.bounds
     642            integral += F(b) - F(a)
     643        return integral
     644   
     645    def infimum(self):
     646        """Return the Infimum (greatest lower bound)
     647            sage: RealSet(points=range(3)).infimum()
     648            0
     649            sage: RealSet.oo_interval(1,3).infimum()
     650            1
     651            sage: RealSet().infimum()
     652            +Infinity
     653        """
     654        imin = min([I.bounds[0] for I in self.intervals_list] + [+Infinity])
     655        pmin = min(self.points_list + [+Infinity])
     656        return min(imin, pmin)
     657
     658    def __neg__(self):
     659        r"""The opposite of a set: `-A = \{-x\mid x\in A\}`
     660            sage: -RealSet.oo_interval(1,2)
     661            ] -2 :: -1 [
     662        """
     663        intervals = [-I for I in self.intervals_list]
     664        points = [-p for p in self.points_list]
     665        return RealSet(intervals, points)
     666   
     667    def supremum(self):
     668        """Return the Supremum (least upper bound)
     669           
     670           sage: RealSet(points=range(3)).supremum()
     671           2
     672           sage: RealSet.oo_interval(1,3).supremum()
     673           3
     674           sage: RealSet().supremum()
     675           -Infinity
     676        """
     677        return - (-self).infimum()
     678
     679    @property
     680    def is_empty(self):
     681        r"""
     682            sage: RealSet().is_empty
     683            True
     684            sage: RealSet([RInterval((1,2))],[]).is_empty
     685            False
     686            sage: RealSet([],[1]).is_empty
     687            False
     688            """
     689        return not self.intervals_list and not self.points_list
     690
     691    def complement(self):
     692        """The complementary of a set:
     693           
     694           sage: RealSet.oo_interval(2,3).complement()
     695           ] -Infinity :: 2 ] + [ 3 :: +Infinity [
     696           
     697           sage: RealSet(points=range(3)).complement()
     698           ] 0 :: 1 [ + ] 1 :: 2 [ + ] 2 :: +Infinity [ + ] -Infinity :: 0 [
     699        """
     700        def p_complement(p):
     701            left = RInterval((-Infinity,p))
     702            right = RInterval((p,+Infinity))
     703            return RealSet(intervals=[left,right])
     704        def i_complement(I):
     705            a,b = I.bounds
     706            left = a != -Infinity and RealSet.oc_interval(-Infinity,a) or RealSet()
     707            right = b != +Infinity and RealSet.co_interval(b,+Infinity) or RealSet()
     708            return left.union(right)
     709        s = RealSet.oo_interval(-Infinity, +Infinity)
     710        for I in self.intervals_list:
     711            s = s.intersection(i_complement(I))
     712        for p in self.points_list:
     713            s = s.intersection(p_complement(p))
     714        return s
     715       
     716    def setdiff(self, other):
     717        r"""The set difference of `A` and `B`: `\{x \in A, x\notin B\}`
     718           
     719            sage: I = RealSet.oo_interval(2,+Infinity)
     720            sage: J = RealSet.oo_interval(-Infinity, 5)
     721            sage: I.setdiff(J)
     722            [ 5 :: +Infinity [
     723            sage: J.setdiff(I)
     724            ] -Infinity :: 2 ]
     725         """
     726        return self.intersection(other.complement())
     727
     728   
     729    def intersection(self,other):
     730        """
     731            sage: I = RealSet.oc_interval(0,1)
     732            sage: J = RealSet.co_interval(1,2)
     733            sage: I.intersection(J)
     734            {1}
     735           
     736        """
     737        intervals = []
     738        for I in self.intervals_list:
     739            for J in other.intervals_list:
     740                ij_int = I.intersection(J)
     741                if not ij_int.is_empty:
     742                    intervals.append(ij_int)
     743        # border or isolated point in both sets
     744        points = set(self.points_list) &  set(other.points_list)
     745        # isolated/border points in self in the interior of other
     746        for p in self.points_list:
     747            if any(p in I for I in other.intervals_list):
     748                points.add(p)
     749        # isolated/border points in other in the interior of self
     750        for p in other.points_list:
     751            if any(p in I for I in self.intervals_list):
     752                points.add(p)
     753   
     754        return RealSet(intervals, list(points)).reduce()
     755
     756   
     757    def toGf(self):
     758        r"""only for interface with gf
     759
     760            sage: RealSet([RInterval((1,2)),RInterval((3,4))],[2,5])
     761            ] 1 :: 2 ] + ] 3 :: 4 [ + {5}
     762            sage: RealSet([RInterval((1,2)),RInterval((3,4))],[2,5]).toGf()
     763            '{ ] 1 , 2 ] , ] 3 , 4 [ , {5} }'
     764        """
     765        if self.is_empty: return '{}'
     766        points = list(self.points_list)
     767        def delim(p):
     768            b = p in points
     769            if b: points.remove(p)
     770            return b
     771        def stri(I):
     772            x0,x1 = I.bounds
     773            d0 = delim(x0) and '[ ' or '] '
     774            d1 = delim(x1) and ' ]' or ' ['
     775            return d0 + `x0` + ' , ' + `x1` + d1
     776        str_intervals = " , ".join(map(stri, self.intervals_list))
     777        str_points = ' , '.join([str(x) for x in points])
     778        if str_intervals and str_points:
     779            return '{ ' + str_intervals + ' , {%s}' % str_points  + ' }'
     780        if str_points:
     781            return '{%s}' % str_points   
     782        if len(self.intervals_list) == 1 :
     783            return str_intervals
     784        return '{ ' + str_intervals + ' }'
     785     
  • setup.py

    diff --git a/setup.py b/setup.py
    a b  
    10131013                     'sage.structure',
    10141014                     'sage.structure.proof',
    10151015
    1016                      'sage.tensor'
     1016                     'sage.tensor'     
    10171017                     ],
    10181018      scripts = [],
    10191019