Ticket #5200: subsets_subwords-5200-submitted.2.patch

File subsets_subwords-5200-submitted.2.patch, 17.0 KB (added by hivert, 12 years ago)

New patch after Nicolas review.

  • sage/combinat/subset.py

    # HG changeset patch
    # User Florent Hivert <Florent.Hivert@univ-rouen.fr>
    # Date 1237312279 -3600
    # Node ID d28082aa40f74996bf35d35118297c8af0064b59
    # Parent  5c72dbb92d8284101858a5e6f2b476a56e597e14
    * * *
    * * *
    
    diff -r 5c72dbb92d82 -r d28082aa40f7 sage/combinat/subset.py
    a b  
    11r"""
    22Subsets
     3
     4The combinatorial class of the subsets of a finite set. The set can
     5be given as a list or a Set or else as an integer `n` which encodes the set
     6`\{1,2,...,n\}`. See the ``Subsets`` for more informations and examples.
     7
     8AUTHORS:
     9
     10- Mike Hansen: initial version
     11
     12- Florent Hivert (2009/02/06): doc improvements + new methods
     13
    314"""
    415#*****************************************************************************
    516#       Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>,
     
    1829
    1930from sage.sets.set import Set
    2031from sage.rings.arith import binomial
    21 import sage.rings.integer
     32from sage.rings.integer import Integer
    2233import sage.combinat.subword as subword
    2334import sage.combinat.choose_nk as choose_nk
    2435import sage.misc.prandom as rnd
     
    2738from combinat import CombinatorialClass, CombinatorialObject
    2839
    2940
     41def Subsets(s, k=None, submultiset=False):
     42    """
     43    Returns the combinatorial class of the subsets of the finite set
     44    s. The set can be given as a list, Set or any iterable convertible
     45    to a set. It can alternatively be given a non-negative integer `n`
     46    which encode the set `\{1,2,\dots,n\}` (i.e. the Sage
     47    ``range(1,s+1)``).
     48   
     49    A second optional parameter k can be given. In this case, Subsets returns
     50    the combinatorial class of subsets of s of size k.
     51       
     52    Finally the option ``submultiset`` allows one to deal with sets with
     53    repeated elements usually called multisets.
    3054
    31 def Subsets(s, k=None):
    32     """
    33     Returns the combinatorial class of subsets of s.
    34    
    35     If s is a non-negative integer, it returns the subsets of
    36     range(1,s+1).
    37    
    38     If k is specified, it returns the subsets of s of size k.
    39    
    4055    EXAMPLES::
    4156   
    42         sage: S = Subsets([1,2,3]); S
     57        sage: S = Subsets([1, 2, 3]); S
    4358        Subsets of {1, 2, 3}
    4459        sage: S.count()
    4560        8
     
    5267        sage: S.list()
    5368        [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]
    5469   
    55     ::
     70    Here is the same example where the set is given as an integer::
    5671   
    5772        sage: S = Subsets(3)
    5873        sage: S.list()
    5974        [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]
    6075   
    61     ::
     76    We demonstrate various the effect of the various options::
    6277   
    63         sage: S = Subsets(3,2); S
     78        sage: S = Subsets(3, 2); S
    6479        Subsets of {1, 2, 3} of size 2
    6580        sage: S.list()
    6681        [{1, 2}, {1, 3}, {2, 3}]
     82
     83        sage: S = Subsets([1, 2, 2], submultiset=True); S
     84        SubMultiset of [1, 2, 2]
     85        sage: S.list()
     86        [[], [1], [2], [1, 2], [2, 2], [1, 2, 2]]
     87
     88        sage: S = Subsets([1, 2, 2, 3], 3, submultiset=True); S
     89        SubMultiset of [1, 2, 2, 3] of size 3       
     90        sage: S.list()
     91        [[1, 2, 2], [1, 2, 3], [2, 2, 3]]
    6792    """
    68     if isinstance(s, (int, sage.rings.integer.Integer)):
     93    if k is not None:
     94        k=Integer(k)
     95   
     96    if isinstance(s, (int, Integer)):
    6997        if s < 0:
    7098            raise ValueError, "s must be non-negative"
    71         set = Set(range(1,s+1))
     99        s = Set(range(1,s+1))
     100
     101#    if len(Set(s)) != len(s):
     102#        multi = True
     103   
     104    if k is None:
     105        if submultiset:
     106            return SubMultiset_s(s)
     107        else:
     108            return Subsets_s(s)
    72109    else:
    73         set = Set(s)
    74    
    75     if k == None:
    76         return Subsets_s(set)
    77     else:
    78         if isinstance(k, (int, sage.rings.integer.Integer)):
    79             return Subsets_sk(set, k)
     110        if submultiset:
     111            return SubMultiset_sk(s, k)
    80112        else:
    81             raise TypeError, "k must be an integer"
     113            return Subsets_sk(s, k)
     114           
    82115
    83116
    84117
     
    92125            sage: S == loads(dumps(S))
    93126            True
    94127        """
    95         self.s = s
     128        self.s = Set(s)
    96129
    97130    def __repr__(self):
    98131        """
     
    103136        """
    104137        return "Subsets of %s"%self.s
    105138
     139    def __contains__(self, value):
     140        """
     141        TESTS::
     142       
     143            sage: S = Subsets([1,2,3])
     144            sage: Set([1,2]) in S
     145            True
     146            sage: Set([1,4]) in S
     147            False
     148            sage: Set([]) in S
     149            True
     150        """
     151        value = Set(value)
     152        for v in value:
     153            if not v in self.s:
     154                return False
     155        return True   
     156       
    106157    def count(self):
    107158        r"""
    108159        Returns the number of subsets of the set s.
     
    151202   
    152203    def iterator(self):
    153204        """
    154         An iterator for all the subsets of s.
     205        Iterate through the subsets of s.
    155206       
    156207        EXAMPLES::
    157208       
    158209            sage: [sub for sub in Subsets(Set([1,2,3]))]
    159210            [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]
     211            sage: [sub for sub in Subsets(3)]
     212            [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]
    160213            sage: [sub for sub in Subsets([1,2,3,3])]
    161214            [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]
    162             sage: [sub for sub in Subsets(3)]
    163             [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]
     215
    164216        """
    165217        lset = __builtin__.list(self.s)
    166218        #We use the iterator for the subwords of range(len(self.s))
     
    253305            sage: S == loads(dumps(S))
    254306            True
    255307        """
    256         self.s = s
     308        self.s = Set(s)
    257309        self.k = k
    258310
    259311    def __repr__(self):
     
    265317        """
    266318        return "Subsets of %s of size %s"%(self.s, self.k)
    267319
     320    def __contains__(self, value):
     321        """
     322        TESTS:
     323            sage: S = Subsets([1,2,3], 2)
     324            sage: Set([1,2]) in S
     325            True
     326            sage: Set([1,4]) in S
     327            False
     328            sage: Set([]) in S
     329            False
     330        """
     331        value = Set(value)
     332        if len(value) != self.k:
     333            return False
     334        for v in value:
     335            if not v in self.s:
     336                return False
     337        return True   
     338
    268339    def count(self):
    269340        """
    270341        EXAMPLES::
    271342       
     343            sage: Subsets(Set([1,2,3]), 2).count()
     344            3
    272345            sage: Subsets([1,2,3,3], 2).count()
    273346            3
    274             sage: Subsets(Set([1,2,3]), 2).count()
    275             3
    276347            sage: Subsets([1,2,3], 1).count()
    277348            3
    278349            sage: Subsets([1,2,3], 3).count()
     
    337408
    338409    def iterator(self):
    339410        """
    340         An iterator for all the subsets of s of size k.
     411        Iterate through the subsets of s of size k.
    341412       
    342413        EXAMPLES::
    343414       
     
    436507            return Set([lset[i] for i in choose_nk.from_rank(r, n, self.k)])           
    437508
    438509
     510class SubMultiset_s(CombinatorialClass):
     511    """
     512    The combinatorial class of the sub multisets of s.
     513   
     514    EXAMPLES::
     515       
     516        sage: S = Subsets([1,2,2,3], submultiset=True)
     517        sage: S._s
     518        [1, 2, 2, 3]
     519
     520    The positions of the unique elements in s are stored in::
     521           
     522        sage: S._indices
     523        [0, 1, 3]
     524
     525    and their multiplicities in::
     526       
     527        sage: S._multiplicities
     528        [1, 2, 1]
     529        sage: Subsets([1,2,3,3], submultiset=True).count()
     530        12
     531        sage: S == loads(dumps(S))
     532        True
     533    """
     534    def __init__(self, s):
     535        """
     536        Constructs the combinatorial class of the sub multisets of s.
     537
     538        EXAMPLES::
     539       
     540            sage: S = Subsets([1,2,2,3], submultiset=True)
     541            sage: Subsets([1,2,3,3], submultiset=True).count()
     542            12
     543        """
     544        s = list(s)
     545        indices = list(sorted(Set([s.index(a) for a in s])))
     546        multiplicities = [len([a for a in s if a == s[i]])
     547                          for i in indices]
     548        self._s = sorted(s)
     549        self._indices = indices
     550        self._multiplicities = multiplicities
     551       
     552    def __repr__(self):
     553        """
     554        TESTS::
     555
     556            sage: S = Subsets([1, 2, 2, 3], submultiset=True); S
     557            SubMultiset of [1, 2, 2, 3]
     558        """
     559        return "SubMultiset of %s"%self._s
     560       
     561    def __contains__(self, s):
     562        """
     563        TESTS::
     564       
     565            sage: S = Subsets([1,2,2,3], submultiset=True)
     566            sage: [] in S
     567            True
     568            sage: [1, 2, 2] in S
     569            True
     570            sage: all(i in S for i in S)
     571            True
     572            sage: [1, 2, 2, 2] in S
     573            False
     574            sage: [1, 3, 2, 2] in S
     575            True
     576            sage: [4] in S
     577            False
     578        """
     579        return sorted(s) in subword.Subwords(self._s)
     580       
     581    def iterator(self):
     582        """
     583        Iterate through the subsets of the multiset ``self._s``.  Note
     584        that each subset is represented by a list of its elements rather than
     585        a set since we can have multiplicities (no multiset data structure yet
     586        in sage).
     587
     588        EXAMPLES::
     589       
     590            sage: S = Subsets([1,2,2,3], submultiset=True)
     591            sage: S.list()
     592            [[],
     593             [1],
     594             [2],
     595             [3],
     596             [1, 2],
     597             [1, 3],
     598             [2, 2],
     599             [2, 3],
     600             [1, 2, 2],
     601             [1, 2, 3],
     602             [2, 2, 3],
     603             [1, 2, 2, 3]]
     604
     605        """
     606        for k in range(len(self._s)+1):
     607            for s in SubMultiset_sk(self._s, k):
     608                yield s
     609   
     610
     611class SubMultiset_sk(SubMultiset_s):
     612    """
     613    The combinatorial class of all of the subsets of size k of a multiset s.
     614    Note that each subset is represented by a list of the elements rather than
     615    a set since we can have multiplicities (no multiset data structure yet in
     616    sage).
     617           
     618    EXAMPLES::
     619       
     620        sage: S = Subsets([1,2,3,3],2, submultiset=True)
     621        sage: S._k
     622        2
     623        sage: S.count()
     624        4
     625        sage: S.first()
     626        [1, 2]
     627        sage: S.last()
     628        [3, 3]
     629        sage: [sub for sub in S]
     630        [[1, 2], [1, 3], [2, 3], [3, 3]]
     631        sage: S == loads(dumps(S))
     632        True
     633        """
     634    def __init__(self, s, k):
     635        """
     636        TEST::
     637       
     638            sage: S = Subsets([1,2,3,3],2, submultiset=True)
     639            sage: [sub for sub in S]
     640            [[1, 2], [1, 3], [2, 3], [3, 3]]
     641        """
     642        SubMultiset_s.__init__(self, s)
     643        self._k = k
     644
     645    def __repr__(self):
     646        """
     647        TESTS::
     648
     649            sage: S = Subsets([1, 2, 2, 3], 3, submultiset=True); S
     650            SubMultiset of [1, 2, 2, 3] of size 3       
     651        """
     652        return "SubMultiset of %s of size %s"%(self._s, self._k)
     653
     654    def __contains__(self, s):
     655        """
     656        TESTS::
     657       
     658            sage: S = Subsets([1,2,2,3], 2, submultiset=True)
     659            sage: [] in S
     660            False
     661            sage: [1, 2, 2] in S
     662            False
     663            sage: all(i in S for i in S)
     664            True
     665            sage: [2, 2] in S
     666            True
     667            sage: [1, 3] in S
     668            True
     669            sage: [4] in S
     670            False
     671            sage: [3, 3] in S
     672            False
     673        """
     674        return sorted(s) in subword.Subwords(self._s, self._k)
     675       
     676    def iterator(self):
     677        """
     678        Iterate through the subsets of size ``self._k`` of the multiset
     679        ``self._s``. Note that each subset is represented by a list of the
     680        elements rather than a set since we can have multiplicities (no
     681        multiset data structure yet in sage).
     682       
     683        EXAMPLES::
     684       
     685            sage: S = Subsets([1,2,2,3],2, submultiset=True)
     686            sage: S.list()
     687            [[1, 2], [1, 3], [2, 2], [2, 3]]
     688        """
     689        from sage.combinat.integer_vector import IntegerVectors
     690        for iv in IntegerVectors(self._k, len(self._indices), outer=self._multiplicities):
     691            yield sum([ [self._s[self._indices[i]]]*iv[i] for i in range(len(iv))], [])
     692           
  • sage/combinat/subword.py

    diff -r 5c72dbb92d82 -r d28082aa40f7 sage/combinat/subword.py
    a b  
    11r"""
    22Subwords
     3
     4A subword of a word $w$ is a word obtained by deleting the letters at some
     5(non necessarily adjacent) positions in `w`. It is not to be confused with the
     6notion of factor where one keeps adjacent positions in `w`. Sometimes it is
     7useful to allow repeated uses of the same letter of `w` in a "generalized"
     8subword. We call this a subword with repetitions.
     9
     10For example:
     11
     12- "bnjr" is a subword of the word "bonjour" but not a factor;
     13
     14- "njo" is both a factor and a subword of the word "bonjour";
     15
     16- "nr" is a subword of "bonjour";
     17
     18- "rn" is not a subword of "bonjour";
     19
     20- "nnu" is not a subword of "bonjour";
     21
     22- "nnu" is a subword with repetitions of "bonjour";
     23 
     24A word can be given either as a string or as a list.
     25
     26AUTHORS:
     27
     28- Mike Hansen: initial version
     29
     30- Florent Hivert (2009/02/06): doc improvements + new methods + bug fixes
     31
     32
    333"""
     34
    435#*****************************************************************************
    536#       Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>,
    637#
     
    2152import itertools
    2253from combinat import CombinatorialClass, CombinatorialObject
    2354
    24 #A subword of a word w is a word obtaining by deleting the letters at
    25 #some of the positions in w.
    26 
    27 #Example:
    28 #    - [b,n,j,r] is a subword of [b,o,n,j,o,u,r]
    29 #    - [n,r] is a subword of [b,o,n,j,o,u,r]
    30 #    - [r,n] is not a subword of [b,o,n,j,o,u,r]
    31 #    - [n,n,u] is not a subword of [b,o,n,j,o,u,r]
    32 #    - [n,n,u] is a subword with repetitions of [b,o,n,j,o,u,r]
    33 
    3455
    3556def Subwords(w, k=None):
    3657    """
    37     Returns the combinatorial class of subwords of w.
     58    Returns the combinatorial class of subwords of w. The word w can be given
     59    by either a string or a list.
    3860   
    3961    If k is specified, then it returns the combinatorial class of
    4062    subwords of w of length k.
     
    86108        """
    87109        return "Subwords of %s"%self.w
    88110
     111    def __contains__(self, w):
     112        """
     113        TESTS::
     114       
     115            sage: [] in Subwords([1,2,3,4,3,4,4])
     116            True
     117            sage: [2,3,3,4] in Subwords([1,2,3,4,3,4,4])
     118            True
     119            sage: [5, 5, 3] in Subwords([1, 3, 3, 5, 4, 5, 3, 5])
     120            True
     121            sage: [3, 5, 5, 3] in Subwords([1, 3, 3, 5, 4, 5, 3, 5])
     122            True
     123            sage: [3, 5, 5, 3, 4] in Subwords([1, 3, 3, 5, 4, 5, 3, 5])
     124            False
     125            sage: [2,3,3,4] in Subwords([1,2,3,4,3,4,4])
     126            True
     127            sage: [2,3,3,1] in Subwords([1,2,3,4,3,4,4])
     128            False
     129        """
     130        if smallest_positions(self.w, w) != False:
     131            return True
     132        return False   
     133       
    89134    def count(self):
    90135        """
    91136        EXAMPLES::
     
    147192        """
    148193        return "Subwords of %s of length %s"%(self.w, self.k)
    149194
     195    def __contains__(self, w):
     196        """
     197        TESTS::
     198       
     199            sage: [] in Subwords([1, 3, 3, 5, 4, 5, 3, 5],0)
     200            True
     201            sage: [2,3,3,4] in Subwords([1,2,3,4,3,4,4],4)
     202            True
     203            sage: [2,3,3,4] in Subwords([1,2,3,4,3,4,4],3)
     204            False
     205            sage: [5, 5, 3] in Subwords([1, 3, 3, 5, 4, 5, 3, 5],3)
     206            True
     207            sage: [5, 5, 3] in Subwords([1, 3, 3, 5, 4, 5, 3, 5],4)
     208            False
     209        """
     210        if len(w) != self.k:
     211            return False
     212        if smallest_positions(self.w, w) != False:
     213            return True
     214        return False   
    150215   
    151216    def count(self):
    152217        r"""
     
    211276    subword of word. If pos is specified, then it returns the positions
    212277    of the first appearance of subword starting at pos.
    213278   
    214     If subword is not found in word, then it returns False
     279    If subword is not found in word, then it returns False.
    215280   
    216281    EXAMPLES::
    217282   
     
    229294        [1, 2]
    230295        sage: sage.combinat.subword.smallest_positions([1,2,3,4], [5,5])
    231296        False
     297        sage: sage.combinat.subword.smallest_positions([1,3,3,4,5],[3,5])
     298        [1, 4]
     299        sage: sage.combinat.subword.smallest_positions([1,3,3,5,4,5,3,5],[3,5,3])
     300        [1, 3, 6]
     301        sage: sage.combinat.subword.smallest_positions([1,3,3,5,4,5,3,5],[3,5,3],2)
     302        [2, 3, 6]
     303        sage: sage.combinat.subword.smallest_positions([1,2,3,4,3,4,4],[2,3,3,1])
     304        False
     305        sage: sage.combinat.subword.smallest_positions([1,3,3,5,4,5,3,5],[3,5,3],3)
     306        False
    232307    """
    233308    pos -= 1
    234309    for i in range(len(subword)):
    235         for j in range(pos+1, len(word)):
     310        for j in range(pos+1, len(word)+1):
     311            if j == len(word):
     312                return False
    236313            if word[j] == subword[i]:
    237314                pos = j
    238315                break
    239         if pos == -1:
     316        if pos != j:
    240317            return False
    241318        subword[i] = pos
    242319