# 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 r""" Subsets The combinatorial class of the subsets of a finite set. The set can be given as a list or a Set or else as an integer `n` which encodes the set `\{1,2,...,n\}`. See the ``Subsets`` for more informations and examples. AUTHORS: - Mike Hansen: initial version - Florent Hivert (2009/02/06): doc improvements + new methods """ #***************************************************************************** #       Copyright (C) 2007 Mike Hansen , from sage.sets.set import Set from sage.rings.arith import binomial import sage.rings.integer from sage.rings.integer import Integer import sage.combinat.subword as subword import sage.combinat.choose_nk as choose_nk import sage.misc.prandom as rnd from combinat import CombinatorialClass, CombinatorialObject def Subsets(s, k=None, submultiset=False): """ Returns the combinatorial class of the subsets of the finite set s. The set can be given as a list, Set or any iterable convertible to a set. It can alternatively be given a non-negative integer `n` which encode the set `\{1,2,\dots,n\}` (i.e. the Sage ``range(1,s+1)``). A second optional parameter k can be given. In this case, Subsets returns the combinatorial class of subsets of s of size k. Finally the option ``submultiset`` allows one to deal with sets with repeated elements usually called multisets. def Subsets(s, k=None): """ Returns the combinatorial class of subsets of s. If s is a non-negative integer, it returns the subsets of range(1,s+1). If k is specified, it returns the subsets of s of size k. EXAMPLES:: sage: S = Subsets([1,2,3]); S sage: S = Subsets([1, 2, 3]); S Subsets of {1, 2, 3} sage: S.count() 8 sage: S.list() [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}] :: Here is the same example where the set is given as an integer:: sage: S = Subsets(3) sage: S.list() [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}] :: We demonstrate various the effect of the various options:: sage: S = Subsets(3,2); S sage: S = Subsets(3, 2); S Subsets of {1, 2, 3} of size 2 sage: S.list() [{1, 2}, {1, 3}, {2, 3}] sage: S = Subsets([1, 2, 2], submultiset=True); S SubMultiset of [1, 2, 2] sage: S.list() [[], [1], [2], [1, 2], [2, 2], [1, 2, 2]] sage: S = Subsets([1, 2, 2, 3], 3, submultiset=True); S SubMultiset of [1, 2, 2, 3] of size 3 sage: S.list() [[1, 2, 2], [1, 2, 3], [2, 2, 3]] """ if isinstance(s, (int, sage.rings.integer.Integer)): if k is not None: k=Integer(k) if isinstance(s, (int, Integer)): if s < 0: raise ValueError, "s must be non-negative" set = Set(range(1,s+1)) s = Set(range(1,s+1)) #    if len(Set(s)) != len(s): #        multi = True if k is None: if submultiset: return SubMultiset_s(s) else: return Subsets_s(s) else: set = Set(s) if k == None: return Subsets_s(set) else: if isinstance(k, (int, sage.rings.integer.Integer)): return Subsets_sk(set, k) if submultiset: return SubMultiset_sk(s, k) else: raise TypeError, "k must be an integer" return Subsets_sk(s, k) sage: S == loads(dumps(S)) True """ self.s = s self.s = Set(s) def __repr__(self): """ """ return "Subsets of %s"%self.s def __contains__(self, value): """ TESTS:: sage: S = Subsets([1,2,3]) sage: Set([1,2]) in S True sage: Set([1,4]) in S False sage: Set([]) in S True """ value = Set(value) for v in value: if not v in self.s: return False return True def count(self): r""" Returns the number of subsets of the set s. def iterator(self): """ An iterator for all the subsets of s. Iterate through the subsets of s. EXAMPLES:: sage: [sub for sub in Subsets(Set([1,2,3]))] [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}] sage: [sub for sub in Subsets(3)] [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}] sage: [sub for sub in Subsets([1,2,3,3])] [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}] sage: [sub for sub in Subsets(3)] [{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}] """ lset = __builtin__.list(self.s) #We use the iterator for the subwords of range(len(self.s)) sage: S == loads(dumps(S)) True """ self.s = s self.s = Set(s) self.k = k def __repr__(self): """ return "Subsets of %s of size %s"%(self.s, self.k) def __contains__(self, value): """ TESTS: sage: S = Subsets([1,2,3], 2) sage: Set([1,2]) in S True sage: Set([1,4]) in S False sage: Set([]) in S False """ value = Set(value) if len(value) != self.k: return False for v in value: if not v in self.s: return False return True def count(self): """ EXAMPLES:: sage: Subsets(Set([1,2,3]), 2).count() 3 sage: Subsets([1,2,3,3], 2).count() 3 sage: Subsets(Set([1,2,3]), 2).count() 3 sage: Subsets([1,2,3], 1).count() 3 sage: Subsets([1,2,3], 3).count() def iterator(self): """ An iterator for all the subsets of s of size k. Iterate through the subsets of s of size k. EXAMPLES:: return Set([lset[i] for i in choose_nk.from_rank(r, n, self.k)]) class SubMultiset_s(CombinatorialClass): """ The combinatorial class of the sub multisets of s. EXAMPLES:: sage: S = Subsets([1,2,2,3], submultiset=True) sage: S._s [1, 2, 2, 3] The positions of the unique elements in s are stored in:: sage: S._indices [0, 1, 3] and their multiplicities in:: sage: S._multiplicities [1, 2, 1] sage: Subsets([1,2,3,3], submultiset=True).count() 12 sage: S == loads(dumps(S)) True """ def __init__(self, s): """ Constructs the combinatorial class of the sub multisets of s. EXAMPLES:: sage: S = Subsets([1,2,2,3], submultiset=True) sage: Subsets([1,2,3,3], submultiset=True).count() 12 """ s = list(s) indices = list(sorted(Set([s.index(a) for a in s]))) multiplicities = [len([a for a in s if a == s[i]]) for i in indices] self._s = sorted(s) self._indices = indices self._multiplicities = multiplicities def __repr__(self): """ TESTS:: sage: S = Subsets([1, 2, 2, 3], submultiset=True); S SubMultiset of [1, 2, 2, 3] """ return "SubMultiset of %s"%self._s def __contains__(self, s): """ TESTS:: sage: S = Subsets([1,2,2,3], submultiset=True) sage: [] in S True sage: [1, 2, 2] in S True sage: all(i in S for i in S) True sage: [1, 2, 2, 2] in S False sage: [1, 3, 2, 2] in S True sage: [4] in S False """ return sorted(s) in subword.Subwords(self._s) def iterator(self): """ Iterate through the subsets of the multiset ``self._s``.  Note that each subset is represented by a list of its elements rather than a set since we can have multiplicities (no multiset data structure yet in sage). EXAMPLES:: sage: S = Subsets([1,2,2,3], submultiset=True) sage: S.list() [[], [1], [2], [3], [1, 2], [1, 3], [2, 2], [2, 3], [1, 2, 2], [1, 2, 3], [2, 2, 3], [1, 2, 2, 3]] """ for k in range(len(self._s)+1): for s in SubMultiset_sk(self._s, k): yield s class SubMultiset_sk(SubMultiset_s): """ The combinatorial class of all of the subsets of size k of a multiset s. Note that each subset is represented by a list of the elements rather than a set since we can have multiplicities (no multiset data structure yet in sage). EXAMPLES:: sage: S = Subsets([1,2,3,3],2, submultiset=True) sage: S._k 2 sage: S.count() 4 sage: S.first() [1, 2] sage: S.last() [3, 3] sage: [sub for sub in S] [[1, 2], [1, 3], [2, 3], [3, 3]] sage: S == loads(dumps(S)) True """ def __init__(self, s, k): """ TEST:: sage: S = Subsets([1,2,3,3],2, submultiset=True) sage: [sub for sub in S] [[1, 2], [1, 3], [2, 3], [3, 3]] """ SubMultiset_s.__init__(self, s) self._k = k def __repr__(self): """ TESTS:: sage: S = Subsets([1, 2, 2, 3], 3, submultiset=True); S SubMultiset of [1, 2, 2, 3] of size 3 """ return "SubMultiset of %s of size %s"%(self._s, self._k) def __contains__(self, s): """ TESTS:: sage: S = Subsets([1,2,2,3], 2, submultiset=True) sage: [] in S False sage: [1, 2, 2] in S False sage: all(i in S for i in S) True sage: [2, 2] in S True sage: [1, 3] in S True sage: [4] in S False sage: [3, 3] in S False """ return sorted(s) in subword.Subwords(self._s, self._k) def iterator(self): """ Iterate through the subsets of size ``self._k`` of the multiset ``self._s``. Note that each subset is represented by a list of the elements rather than a set since we can have multiplicities (no multiset data structure yet in sage). EXAMPLES:: sage: S = Subsets([1,2,2,3],2, submultiset=True) sage: S.list() [[1, 2], [1, 3], [2, 2], [2, 3]] """ from sage.combinat.integer_vector import IntegerVectors for iv in IntegerVectors(self._k, len(self._indices), outer=self._multiplicities): yield sum([ [self._s[self._indices[i]]]*iv[i] for i in range(len(iv))], [])
• ## sage/combinat/subword.py

`diff -r 5c72dbb92d82 -r d28082aa40f7 sage/combinat/subword.py`
 a r""" Subwords A subword of a word \$w\$ is a word obtained by deleting the letters at some (non necessarily adjacent) positions in `w`. It is not to be confused with the notion of factor where one keeps adjacent positions in `w`. Sometimes it is useful to allow repeated uses of the same letter of `w` in a "generalized" subword. We call this a subword with repetitions. For example: - "bnjr" is a subword of the word "bonjour" but not a factor; - "njo" is both a factor and a subword of the word "bonjour"; - "nr" is a subword of "bonjour"; - "rn" is not a subword of "bonjour"; - "nnu" is not a subword of "bonjour"; - "nnu" is a subword with repetitions of "bonjour"; A word can be given either as a string or as a list. AUTHORS: - Mike Hansen: initial version - Florent Hivert (2009/02/06): doc improvements + new methods + bug fixes """ #***************************************************************************** #       Copyright (C) 2007 Mike Hansen , # import itertools from combinat import CombinatorialClass, CombinatorialObject #A subword of a word w is a word obtaining by deleting the letters at #some of the positions in w. #Example: #    - [b,n,j,r] is a subword of [b,o,n,j,o,u,r] #    - [n,r] is a subword of [b,o,n,j,o,u,r] #    - [r,n] is not a subword of [b,o,n,j,o,u,r] #    - [n,n,u] is not a subword of [b,o,n,j,o,u,r] #    - [n,n,u] is a subword with repetitions of [b,o,n,j,o,u,r] def Subwords(w, k=None): """ Returns the combinatorial class of subwords of w. Returns the combinatorial class of subwords of w. The word w can be given by either a string or a list. If k is specified, then it returns the combinatorial class of subwords of w of length k. """ return "Subwords of %s"%self.w def __contains__(self, w): """ TESTS:: sage: [] in Subwords([1,2,3,4,3,4,4]) True sage: [2,3,3,4] in Subwords([1,2,3,4,3,4,4]) True sage: [5, 5, 3] in Subwords([1, 3, 3, 5, 4, 5, 3, 5]) True sage: [3, 5, 5, 3] in Subwords([1, 3, 3, 5, 4, 5, 3, 5]) True sage: [3, 5, 5, 3, 4] in Subwords([1, 3, 3, 5, 4, 5, 3, 5]) False sage: [2,3,3,4] in Subwords([1,2,3,4,3,4,4]) True sage: [2,3,3,1] in Subwords([1,2,3,4,3,4,4]) False """ if smallest_positions(self.w, w) != False: return True return False def count(self): """ EXAMPLES:: """ return "Subwords of %s of length %s"%(self.w, self.k) def __contains__(self, w): """ TESTS:: sage: [] in Subwords([1, 3, 3, 5, 4, 5, 3, 5],0) True sage: [2,3,3,4] in Subwords([1,2,3,4,3,4,4],4) True sage: [2,3,3,4] in Subwords([1,2,3,4,3,4,4],3) False sage: [5, 5, 3] in Subwords([1, 3, 3, 5, 4, 5, 3, 5],3) True sage: [5, 5, 3] in Subwords([1, 3, 3, 5, 4, 5, 3, 5],4) False """ if len(w) != self.k: return False if smallest_positions(self.w, w) != False: return True return False def count(self): r""" subword of word. If pos is specified, then it returns the positions of the first appearance of subword starting at pos. If subword is not found in word, then it returns False If subword is not found in word, then it returns False. EXAMPLES:: [1, 2] sage: sage.combinat.subword.smallest_positions([1,2,3,4], [5,5]) False sage: sage.combinat.subword.smallest_positions([1,3,3,4,5],[3,5]) [1, 4] sage: sage.combinat.subword.smallest_positions([1,3,3,5,4,5,3,5],[3,5,3]) [1, 3, 6] sage: sage.combinat.subword.smallest_positions([1,3,3,5,4,5,3,5],[3,5,3],2) [2, 3, 6] sage: sage.combinat.subword.smallest_positions([1,2,3,4,3,4,4],[2,3,3,1]) False sage: sage.combinat.subword.smallest_positions([1,3,3,5,4,5,3,5],[3,5,3],3) False """ pos -= 1 for i in range(len(subword)): for j in range(pos+1, len(word)): for j in range(pos+1, len(word)+1): if j == len(word): return False if word[j] == subword[i]: pos = j break if pos == -1: if pos != j: return False subword[i] = pos