# Ticket #8910: trac_8910-subsets_an_element-fh.patch

File trac_8910-subsets_an_element-fh.patch, 16.3 KB (added by hivert, 10 years ago)
• ## sage/combinat/subset.py

```# HG changeset patch
# User Florent Hivert <Florent.Hivert@univ-rouen.fr>
# Date 1275319974 -7200
# Node ID c4217440241d89fd7e6591deff81a455e7b8e93d
# Parent  396ecfecef3602f2d2b350bd257fc176a3cc2d71
#8910: Have CombinatorialClass inherits from Parent (first step to get rid of it)

diff --git a/sage/combinat/subset.py b/sage/combinat/subset.py```
 a 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 information and examples. `\{1,2,...,n\}`. See :class:`Subsets` for more information and examples. AUTHORS: AUTHORS: """ #***************************************************************************** #       Copyright (C) 2007 Mike Hansen , #       Copyright (C) 2007 Mike Hansen , # #  Distributed under the terms of the GNU General Public License (GPL) # import __builtin__ import itertools from combinat import CombinatorialClass, CombinatorialObject from sage.sets.set import Set_object_enumerated from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets def Subsets(s, k=None, submultiset=False): def Subsets(s, k=None, submultiset=False 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. repeated elements usually called multisets. EXAMPLES:: sage: S = Subsets([1, 2, 3]); S Subsets of {1, 2, 3} sage: S.cardinality() def Subsets(s, k=None, submultiset=False {2} 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 Subsets of {1, 2, 3} of size 2 sage: S.list() def Subsets(s, k=None, submultiset=False [[], [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 SubMultiset of [1, 2, 2, 3] of size 3 sage: S.list() [[1, 2, 2], [1, 2, 3], [2, 2, 3]] """ if k is not None: k=Integer(k) if isinstance(s, (int, Integer)): if s < 0: raise ValueError, "s must be non-negative" def Subsets(s, k=None, submultiset=False #    if len(Set(s)) != len(s): #        multi = True if k is None: if submultiset: return SubMultiset_s(s) def Subsets(s, k=None, submultiset=False return SubMultiset_sk(s, k) else: return Subsets_sk(s, k) class Subsets_s(CombinatorialClass): def __init__(self, s): """ TESTS:: sage: s = Subsets(Set([1])) sage: e = s.first() sage: isinstance(e, s.element_class) True In the following "_test_elements" is temporarily disabled until :class:`sage.sets.set.Set_object_enumerated` objects pass the category tests:: sage: S = Subsets([1,2,3]) sage: TestSuite(S).run() sage: s = Subsets(Set([1])) sage: e = s.first() sage: isinstance(e, s.element_class) True sage: TestSuite(S).run(skip=["_test_elements"]) sage: S = sage.sets.set.Set_object_enumerated([1,2]) sage: TestSuite(S).run()         # todo: not implemented """ CombinatorialClass.__init__(self, category=FiniteEnumeratedSets()) self.s = Set(s) def __repr__(self): """ TESTS:: sage: repr(Subsets([1,2,3])) 'Subsets of {1, 2, 3}' """ class Subsets_s(CombinatorialClass): def __contains__(self, value): """ TESTS:: sage: S = Subsets([1,2,3]) sage: Set([1,2]) in S True class Subsets_s(CombinatorialClass): for v in value: if not v in self.s: return False return True return True def cardinality(self): r""" Returns the number of subsets of the set s. This is given by `2^{|s|}`. EXAMPLES:: sage: Subsets(Set([1,2,3])).cardinality() 8 sage: Subsets([1,2,3,3]).cardinality() class Subsets_s(CombinatorialClass): """ Returns the first subset of s. Since we aren't restricted to subsets of a certain size, this is always the empty set. EXAMPLES:: sage: Subsets([1,2,3]).first() {} sage: Subsets(3).first() class Subsets_s(CombinatorialClass): """ Returns the last subset of s. Since we aren't restricted to subsets of a certain size, this is always the set s itself. EXAMPLES:: sage: Subsets([1,2,3]).last() {1, 2, 3} sage: Subsets(3).last() class Subsets_s(CombinatorialClass): """ return self.s def __iter__(self): """ Iterates 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)] class Subsets_s(CombinatorialClass): """ Returns a random element of the class of subsets of s (in other words, a random subset of s). EXAMPLES:: sage: Subsets(3).random_element() {2} sage: Subsets([4,5,6]).random_element() class Subsets_s(CombinatorialClass): def rank(self, sub): """ Returns the rank of sub as a subset of s. EXAMPLES:: sage: Subsets(3).rank([]) 0 sage: Subsets(3).rank([1,2]) class Subsets_s(CombinatorialClass): {} sage: Subsets([2,4,5]).unrank(1) {2} sage: s = Subsets([2,4,5]) """ lset = __builtin__.list(self.s) class Subsets_s(CombinatorialClass): else: return Set([lset[i] for i in choose_nk.from_rank(r, n, k)]) def _an_element_(self): """ Returns an example of subset. EXAMPLES:: sage: Subsets(0)._an_element_() {} sage: Subsets(3)._an_element_() {1, 2} sage: Subsets([2,4,5])._an_element_() {2, 4} """ return self.unrank(self.cardinality() // 2) def _element_constructor_(self, x): """ TESTS:: class Subsets_sk(CombinatorialClass): def __init__(self, s, k): """ TESTS:: sage: s = Subsets(Set([1])) sage: e = s.first() sage: isinstance(e, s.element_class) True In the following "_test_elements" is temporarily disabled until :class:`sage.sets.set.Set_object_enumerated` objects pass the category tests:: sage: S = Subsets(3,2) sage: TestSuite(S).run() sage: s = Subsets(Set([1])) sage: e = s.first() sage: isinstance(e, s.element_class) True sage: TestSuite(S).run(skip=["_test_elements"]) """ CombinatorialClass.__init__(self, category=FiniteEnumeratedSets()) self.s = Set(s) self.k = k def __repr__(self): """ TESTS:: sage: repr(Subsets(3,2)) 'Subsets of {1, 2, 3} of size 2' """ class Subsets_sk(CombinatorialClass): for v in value: if not v in self.s: return False return True return True def cardinality(self): """ EXAMPLES:: sage: Subsets(Set([1,2,3]), 2).cardinality() 3 sage: Subsets([1,2,3,3], 2).cardinality() class Subsets_sk(CombinatorialClass): else: return binomial(len(self.s),self.k) def first(self): """ Returns the first subset of s of size k. EXAMPLES:: sage: Subsets(Set([1,2,3]), 2).first() {1, 2} sage: Subsets([1,2,3,3], 2).first() class Subsets_sk(CombinatorialClass): def last(self): """ Returns the last subset of s of size k. EXAMPLES:: sage: Subsets(Set([1,2,3]), 2).last() {2, 3} sage: Subsets([1,2,3,3], 2).last() class Subsets_sk(CombinatorialClass): def __iter__(self): """ Iterates through the subsets of s of size k. EXAMPLES:: sage: [sub for sub in Subsets(Set([1,2,3]), 2)] [{1, 2}, {1, 3}, {2, 3}] sage: [sub for sub in Subsets([1,2,3,3], 2)] class Subsets_sk(CombinatorialClass): """ if self.k not in range(len(self.s)+1): return lset = __builtin__.list(self.s) #We use the iterator for the subwords of range(len(self.s)) ind_set = lambda index_list: Set([lset[i] for i in index_list]) for sub in choose_nk.ChooseNK(len(lset),self.k): yield ind_set(sub) def random_element(self): """ Returns a random element of the class of subsets of s of size k (in other words, a random subset of s of size k). EXAMPLES:: sage: Subsets(3, 2).random_element() {1, 2} sage: Subsets(3,4).random_element() is None class Subsets_sk(CombinatorialClass): def rank(self, sub): """ Returns the rank of sub as a subset of s of size k. EXAMPLES:: sage: Subsets(3,2).rank([1,2]) 0 sage: Subsets([2,3,4],2).rank([3,4]) class Subsets_sk(CombinatorialClass): else: return Set([lset[i] for i in choose_nk.from_rank(r, n, self.k)]) def _an_element_(self): """ Returns an example of subset. EXAMPLES:: sage: Subsets(0,0)._an_element_() {} sage: Subsets(3,2)._an_element_() {1, 3} sage: Subsets([2,4,5],2)._an_element_() {2, 5} """ return self.unrank(self.cardinality() // 2) def _element_constructor_(self, x): """ TESTS:: class Subsets_sk(CombinatorialClass): 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).cardinality() class SubMultiset_s(CombinatorialClass): 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).cardinality() 12 """ CombinatorialClass.__init__(self, category=FiniteEnumeratedSets()) 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]]) class SubMultiset_s(CombinatorialClass): self._s = sorted(s) self._indices = indices self._multiplicities = multiplicities def __repr__(self): """ TESTS:: class SubMultiset_s(CombinatorialClass): 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 class SubMultiset_s(CombinatorialClass): False """ return sorted(s) in subword.Subwords(self._s) def __iter__(self): """ Iterates through the subsets of the multiset ``self._s``.  Note class SubMultiset_s(CombinatorialClass): in sage). EXAMPLES:: sage: S = Subsets([1,2,2,3], submultiset=True) sage: S.list() [[], class SubMultiset_s(CombinatorialClass): for k in range(len(self._s)+1): for s in SubMultiset_sk(self._s, k): yield s class SubMultiset_sk(SubMultiset_s): """ class SubMultiset_sk(SubMultiset_s): 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 class SubMultiset_sk(SubMultiset_s): 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]] class SubMultiset_sk(SubMultiset_s): TESTS:: sage: S = Subsets([1, 2, 2, 3], 3, submultiset=True); S SubMultiset of [1, 2, 2, 3] of size 3 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 class SubMultiset_sk(SubMultiset_s): False """ return sorted(s) in subword.Subwords(self._s, self._k) def __iter__(self): """ Iterates 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]] class SubMultiset_sk(SubMultiset_s): 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))], [])