From 75a10e9a85d73799891dc8b48f8ada2ffb63d2fc Mon Sep 17 00:00:00 2001 From: elixyre Date: Wed, 19 Nov 2014 15:31:16 +0100 Subject: [PATCH 1/2] Ticket classes of combinatorial structures --- src/bin/sage-bdist | 0 src/sage/categories/all.py | 1 + .../classes_of_combinatorial_structures.py | 111 +++++++++ .../classes_of_combinatorial_structures.py | 209 ++++++++++++++++ src/sage/categories/sets_with_grading.py | 31 ++- src/sage/combinat/binary_tree.py | 67 +++++- src/sage/combinat/composition.py | 99 ++++++-- src/sage/combinat/permutation.py | 54 ++++- src/sage/combinat/structures/__init__.py | 223 ++++++++++++++++++ 9 files changed, 758 insertions(+), 37 deletions(-) mode change 100644 => 100755 src/bin/sage-bdist create mode 100644 src/sage/categories/classes_of_combinatorial_structures.py create mode 100644 src/sage/categories/examples/classes_of_combinatorial_structures.py create mode 100644 src/sage/combinat/structures/__init__.py diff --git a/src/bin/sage-bdist b/src/bin/sage-bdist old mode 100644 new mode 100755 diff --git a/src/sage/categories/all.py b/src/sage/categories/all.py index 233ea32ce9e..b8ea27adc2d 100644 --- a/src/sage/categories/all.py +++ b/src/sage/categories/all.py @@ -28,6 +28,7 @@ from sets_with_partial_maps import SetsWithPartialMaps from sets_with_grading import SetsWithGrading +from classes_of_combinatorial_structures import ClassesOfCombinatorialStructures from groupoid import Groupoid from permutation_groups import PermutationGroups diff --git a/src/sage/categories/classes_of_combinatorial_structures.py b/src/sage/categories/classes_of_combinatorial_structures.py new file mode 100644 index 00000000000..a90cb9a2147 --- /dev/null +++ b/src/sage/categories/classes_of_combinatorial_structures.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +""" +Classes of combinatorial structures + +A class of combinatorial structures is a *denumerable set* of discrete objects +(structures) on which a *degree* function is defined, satisfying the following +conditions: + + (i) the degree of an element is a non-negative integer; + (ii) the number of elements of any given degree is finite. + + +REFERENCES: +----------- + +.. [FlaSed] Analytic combinatorics, + Philippe Flajolet and Robert Sedgewick + +AUTHOR: + +- Jean-Baptiste Priez (2014) +""" +#***************************************************************************** +# Copyright (C) 2014 Jean-Baptiste Priez . +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# http://www.gnu.org/licenses/ +#***************************************************************************** +from sage.categories.category import Category +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.categories.sets_with_grading import SetsWithGrading +from sage.misc.abstract_method import abstract_method + + +class ClassesOfCombinatorialStructures(Category): + """ + A class of combinatorial structures is a *denumerable set* of discrete + objects (structures) on which a *degree* function is defined, satisfying the + following conditions: + + (i) the degree of a structure is a non-negative integer; + (ii) the number of structures of any given degree is finite. + + To implement this category, a parent must implement methods excepted in + the category ``SetsWithGrading`` and + """ + + def super_categories(self): + return [SetsWithGrading()] + + class ParentMethods: + + def _test_graded_components_2(self, **options): + """ + Test that some graded components of ``self`` are that the parent + has a properly implemented ``ambient`` and ``grade`` methods. + + EXAMPLE:: + + sage: ClassesOfCombinatorialStructures().example().\ + _test_graded_components_2() + + """ + tester = self._tester(**options) + for grade in self.grading_set().some_elements(): + G = self.graded_component(grade) + + for elt in G.some_elements(): + tester.assertEqual(G.grade(), elt.grade()) + + tester.assertEqual(G.ambient().graded_component(grade), G) + + class GradedComponents(Category): + """ + A graded component of a class of combinatorial structures `C` is an + finite set of structures which all have same degree `i`: + the graded component of degree `i`. + """ + + def super_categories(self): + return [FiniteEnumeratedSets()] + + class ParentMethods: + + @abstract_method(optional=False) + def ambient(self): + """ + The underlying class of the graded component. + + EXAMPLE:: + + sage: C = ClassesOfCombinatorialStructures().example(); C + Compositions of integers + sage: C.graded_component(3).ambient() + Compositions of integers + + """ + + @abstract_method(optional=False) + def grade(self): + """ + Return the degree associated to all structures of the component. + + EXEMPLE:: + + sage: ClassesOfCombinatorialStructures().example().\ + graded_component(42).grade() + 42 + + """ diff --git a/src/sage/categories/examples/classes_of_combinatorial_structures.py b/src/sage/categories/examples/classes_of_combinatorial_structures.py new file mode 100644 index 00000000000..e81043067a3 --- /dev/null +++ b/src/sage/categories/examples/classes_of_combinatorial_structures.py @@ -0,0 +1,209 @@ +# -*- coding: utf-8 -*- +""" +Example of classes of combinatorial structures +-------------------------------------------------------------- + +This module implements a simple version of the class of compositions of integer. + +"[..] a composition of an integer `n` is a way of writing `n` as the sum of a +sequence of (strictly) positive integers." Wikipedia + +This module provides a light implementation to rapid use. This example uses the +following pattern:: + + from sage.combinat.structures import Structures, Structure + + + class MyStructure(Structure): + + def check(self): + # a way to check if the structure is correct + + @lazy_class_attribute + def _auto_parent_(self): + # my default parent + return ClassOfStructures() + + ## + specific design of my structure + + class MyGradedComponent(Structures.GradedComponent): + + def __iter__(self): + # an iterator of the objets of the graded component + + class ClassOfStructures(Structures): + + def grading(self, obj): + # a way to way the grading of the graded component which contains + # the obj + + # we specify the class which defines the graded components + GradedComponent = MyGradedComponent + + +AUTHOR: + +- Jean-Baptiste Priez (2014) +""" +#***************************************************************************** +# Copyright (C) 2014 Jean-Baptiste Priez . +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# http://www.gnu.org/licenses/ +#***************************************************************************** +from itertools import imap +from sage.combinat.structures import StructuresClass, Structure +from sage.misc.lazy_attribute import lazy_class_attribute +from sage.rings.integer import Integer +from sage.structure.list_clone import ClonableIntArray +from sage.sets.positive_integers import PositiveIntegers + + +class Composition(Structure, ClonableIntArray): + """ + A composition could be represented as a vector of integers so one use + *ClonableIntArray* to implement our structures. + + In that example, we choose to use a more general structures: + *ElementWrapper* + + The class *Structure* is a simple class use to not (re)define a classcall + method. Usually, the classcall is use on elements to avoid explicit parent + in argument:: + + Composition([3,1,2], parent=Compositions()) + + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Composition + sage: I = Composition([2,1,3]); I + [2, 1, 3] + sage: I.parent() + Compositions of integers + sage: I.grade() + 6 + + """ + + def check(self): + """ + The check has to be given to specify the structure + + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Composition + sage: _ = Composition([2,1,3]) + sage: Composition([0,1]) + Traceback (most recent call last): + ... + AssertionError + + """ + assert(all(i in PositiveIntegers() for i in self)) + + @lazy_class_attribute + def _auto_parent_(self): + """ + I use this trick to not call a Composition with an explicit parent. + + (It is a lazy class attribute to avoid to conflict with *Compositions*) + + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Composition + sage: Composition._auto_parent_ + Compositions of integers + + """ + return Compositions() + + +class Compositions(StructuresClass): + """ + TESTS:: + + sage: C = ClassesOfCombinatorialStructures().example(); C + Compositions of integers + sage: TestSuite(C).run() + + """ + + def grading(self, I): + """ + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Composition,\ + Compositions + sage: I = Composition([2,1,3]); I + [2, 1, 3] + sage: I.parent().grading(I) + 6 + sage: Compositions().grading(I) + 6 + + """ + return sum(I) + + def _repr_(self): + """ + TESTS:: + + sage: ClassesOfCombinatorialStructures().example() + Compositions of integers + + """ + return "Compositions of integers" + + # I have to specify *Compositions* is the parent of the elements + # *Composition*. + Element = Composition + + class GradedComponent(StructuresClass.GradedComponent): + """ + TESTS:: + + sage: C = ClassesOfCombinatorialStructures().example() + sage: C42 = C.graded_component(42) + sage: TestSuite(C42).run() + + """ + + def cardinality(self): + """ + TESTS:: + + sage: ClassesOfCombinatorialStructures().example()\ + .graded_component(10).cardinality() + 512 + + """ + return Integer(2)**(max(0, self.grade()-1)) + + def __iter__(self): + """ + TESTS:: + + sage: ClassesOfCombinatorialStructures().example()\ + .graded_component(4).list() + [[4], [1, 3], [2, 2], [1, 1, 2], [3, 1], [1, 2, 1], + [2, 1, 1], [1, 1, 1, 1]] + + """ + # FIXME: this function is better than the current one. + def nested(k): + # little trick to avoid to create too many object *Composition*: + ## That avoid the trip: Composition(... list(Composition(list(Composition([1])) + [2])) + ...) + if k == 0: yield () + else: + for i in range(k): + for I in nested(i): + yield I + (k-i,) + + return imap(self._element_constructor_, nested(self.grade())) + +Example = Compositions \ No newline at end of file diff --git a/src/sage/categories/sets_with_grading.py b/src/sage/categories/sets_with_grading.py index 7ce69b0bb1c..60f1f8d2d09 100644 --- a/src/sage/categories/sets_with_grading.py +++ b/src/sage/categories/sets_with_grading.py @@ -183,6 +183,7 @@ def graded_component(self, grade): """ return self.subset(grade) + @abstract_method def grading(self, elt): """ Return the grading of the element ``elt`` of ``self``. @@ -191,12 +192,15 @@ def grading(self, elt): EXAMPLES:: - sage: N = SetsWithGrading().example(); N - Non negative integers - sage: N.grading(4) - 4 + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import \ + Compositions + sage: C = Compositions(); C + Compositions of integers + sage: C.grading(C([4,2,3])) + 9 + """ - return elt.grade() def generating_series(self): """ @@ -225,3 +229,20 @@ def generating_series(self): # theorem on asymptotic and be a tool to determine a strategy for # algorithms. + class ElementMethods: + + def grade(self): + """ + Return the grading of the element ``self``. It is its degree. + + EXAMPLES:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import \ + Compositions + sage: C = Compositions() + sage: C([3,1,3]).grade() + 7 + + """ + return self.parent().grading(self) \ No newline at end of file diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 6ff6fa22bf6..5a5d9bbc7f1 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -39,13 +39,21 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from sage.structure.list_clone import ClonableArray +from sage.categories.category import Category +from sage.categories.classes_of_combinatorial_structures import \ + ClassesOfCombinatorialStructures +from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.abstract_tree import (AbstractClonableTree, AbstractLabelledClonableTree) from sage.combinat.ordered_tree import LabelledOrderedTrees from sage.rings.integer import Integer -from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute +from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.combinat.combinatorial_map import combinatorial_map +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets +from sage.sets.family import Family +from sage.sets.non_negative_integers import NonNegativeIntegers + class BinaryTree(AbstractClonableTree, ClonableArray): """ @@ -2874,11 +2882,6 @@ def is_complete(self): from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.misc.classcall_metaclass import ClasscallMetaclass - -from sage.sets.non_negative_integers import NonNegativeIntegers -from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets -from sage.sets.family import Family from sage.misc.cachefunc import cached_method @@ -2955,7 +2958,7 @@ def leaf(self): ################################################################# # Enumerated set of all binary trees ################################################################# -class BinaryTrees_all(DisjointUnionEnumeratedSets, BinaryTrees): +class BinaryTrees_all(BinaryTrees, DisjointUnionEnumeratedSets): def __init__(self): """ @@ -2980,7 +2983,29 @@ def __init__(self): """ DisjointUnionEnumeratedSets.__init__( self, Family(NonNegativeIntegers(), BinaryTrees_size), - facade=True, keepkey = False) + facade=True, keepkey = False, + category=Category.join([ClassesOfCombinatorialStructures(), + InfiniteEnumeratedSets()])) + + def graded_component(self, n): + """ + TESTS:: + + sage: BinaryTrees().graded_component(4) + Binary trees of size 4 + + """ + return BinaryTrees_size(n) + + def grading(self, T): + """ + TESTS:: + + sage: BinaryTree([[],[]]).grade() + 3 + + """ + return T.node_number() def _repr_(self): """ @@ -3077,9 +3102,31 @@ def __init__(self, size): sage: S is BinaryTrees(3) True """ - super(BinaryTrees_size, self).__init__(category = FiniteEnumeratedSets()) + super(BinaryTrees_size, self).__init__( + category=ClassesOfCombinatorialStructures.GradedComponents() + ) self._size = size + def grade(self): + """ + TESTS:: + + sage: BinaryTrees(3).grade() + 3 + + """ + return self._size + + def ambient(self): + """ + TESTS:: + + sage: BinaryTrees(3).ambient() + Binary trees + + """ + return BinaryTrees_all() + def _repr_(self): """ TESTS:: @@ -3194,7 +3241,7 @@ def element_class(self): sage: S = BinaryTrees(3) sage: S.element_class - sage: S.first().__class__ == BinaryTrees().first().__class__ + sage: S.first().__class__ == BinaryTrees(5).first().__class__ True """ return self._parent_for.element_class diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 3c577ecf73a..3cdf30697a7 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -28,9 +28,12 @@ # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ #***************************************************************************** - +from itertools import imap +from sage.categories.classes_of_combinatorial_structures import \ + ClassesOfCombinatorialStructures from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.combinat.structures import StructuresClass from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.structure.element import Element @@ -226,9 +229,8 @@ def conjugate(self): TESTS:: sage: parent(list(Compositions(1))[0].conjugate()) - Compositions of 1 - sage: parent(list(Compositions(0))[0].conjugate()) - Compositions of 0 + Compositions of non-negative integers + """ comp = self if comp == []: @@ -1609,28 +1611,22 @@ def __init__(self, is_infinite=False): sage: TestSuite(C).run() """ if is_infinite: - Parent.__init__(self, category=InfiniteEnumeratedSets()) + Parent.__init__(self, category=ClassesOfCombinatorialStructures()) else: - Parent.__init__(self, category=FiniteEnumeratedSets()) + Parent.__init__(self, category=ClassesOfCombinatorialStructures.\ + GradedComponents()) Element = Composition def _element_constructor_(self, lst): """ - Construct an element with ``self`` as parent. - EXAMPLES:: sage: P = Compositions() sage: P([3,3,1]) # indirect doctest [3, 3, 1] """ - if isinstance(lst, Composition): - lst = list(lst) - elt = self.element_class(self, lst) - if elt not in self: - raise ValueError("%s not in %s"%(elt, self)) - return elt + return self.ambient()._element_constructor_(lst) def __contains__(self, x): """ @@ -1800,9 +1796,30 @@ def __init__(self): sage: C = Compositions() sage: TestSuite(C).run() + """ Compositions.__init__(self, True) + def graded_component(self, n): + """ + TESTS:: + + sage: Compositions().graded_component(42) == Compositions(42) + True + + """ + return Compositions_n(n) + + def grading(self, I): + """ + TESTS:: + + sage: Composition([1,2,1]).grade() + 4 + + """ + return sum(I[:]) + def _repr_(self): """ Return a string representation of ``self``. @@ -1847,6 +1864,24 @@ def __iter__(self): yield self.element_class(self, list(c)) n += 1 + + def _element_constructor_(self, lst): + """ + Construct an element with ``self`` as parent. + + EXAMPLES:: + + sage: P = Compositions() + sage: P([3,3,1]) # indirect doctest + [3, 3, 1] + """ + if isinstance(lst, Composition): + lst = list(lst) + elt = self.element_class(self, lst) + if elt not in self: + raise ValueError("%s not in %s"%(elt, self)) + return elt + class Compositions_n(Compositions): """ Class of compositions of a fixed `n`. @@ -1868,6 +1903,26 @@ def __classcall_private__(cls, n): """ return super(Compositions_n, cls).__classcall__(cls, Integer(n)) + def grade(self): + """ + TESTS:: + + sage: Compositions(4).grade() + 4 + + """ + return self.n + + def ambient(self): + """ + TESTS:: + + sage: Compositions(4).ambient() + Compositions of non-negative integers + + """ + return Compositions_all() + def __init__(self, n): """ TESTS:: @@ -1962,13 +2017,17 @@ def __iter__(self): sage: Compositions(0).list() [[]] """ - if self.n == 0: - yield self.element_class(self, []) - return + def nested(k): + # little trick to avoid to create too many object *Composition*: + ## That avoid the trip: Composition(... list(Composition(list(Composition([1])) + [2])) + ...) + if k == 0: yield () + else: + for i in range(1, k+1): + for I in nested(k-i): + yield (i,) + I + + return imap(self._element_constructor_, nested(self.grade())) - for i in range(1,self.n+1): - for c in Compositions_n(self.n-i): - yield self.element_class(self, [i]+list(c)) from sage.structure.sage_object import register_unpickle_override register_unpickle_override('sage.combinat.composition', 'Composition_class', Composition) diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 4e1cb1db212..7c3bbcc3cc8 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -225,6 +225,9 @@ from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.structure.parent import Parent +from sage.categories.category import Category +from sage.categories.classes_of_combinatorial_structures import \ + ClassesOfCombinatorialStructures from sage.structure.unique_representation import UniqueRepresentation from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -775,6 +778,8 @@ def size(self): """ return len(self) + grade = size + def cycle_string(self, singletons=False): """ Returns a string of the permutation in cycle notation. @@ -5658,8 +5663,31 @@ def __init__(self): sage: SP = Permutations() sage: TestSuite(SP).run() + + """ + Permutations.__init__(self, category=Category.join( + [ClassesOfCombinatorialStructures(), InfiniteEnumeratedSets()]) + ) + + def graded_component(self, n): + """ + TESTS:: + + sage: Permutations(4) == Permutations().graded_component(4) + True + + """ + return StandardPermutations_n(n) + + def grading(self, sig): + """ + TESTS:: + + sage: Permutation([1,3,2,4]).grade() + 4 + """ - Permutations.__init__(self, category=InfiniteEnumeratedSets()) + return len(sig) def _repr_(self): """ @@ -5731,7 +5759,29 @@ def __init__(self, n): sage: TestSuite(SP).run() """ self.n = n - Permutations.__init__(self, category=FiniteEnumeratedSets()) + Permutations.__init__(self, + category=ClassesOfCombinatorialStructures.\ + GradedComponents()) + + def grade(self): + """ + TESTS:: + + sage: Permutations(4).grade() + 4 + + """ + return self.n + + def ambient(self): + """ + TESTS:: + + sage: Permutations(4).ambient() + Standard permutations + + """ + return Permutations() def __call__(self, x): """ diff --git a/src/sage/combinat/structures/__init__.py b/src/sage/combinat/structures/__init__.py new file mode 100644 index 00000000000..56b881b1e17 --- /dev/null +++ b/src/sage/combinat/structures/__init__.py @@ -0,0 +1,223 @@ +# -*- coding: utf-8 -*- +""" +Framework of class of combinatorial structures + +A class of combinatorial structures is a *denumerable set* of discrete objects +(structures) on which a *degree* function is defined, satisfying the following +conditions: + + (i) the degree of an element is a non-negative integer; + (ii) the number of elements of any given degree is finite. + + +References: +----------- + +.. [FS] Analytic combinatorics + Philippe Flajolet and Robert Sedgewick + + +AUTHOR: + +- Jean-Baptiste Priez (2014) +""" +#***************************************************************************** +# Copyright (C) 2014 Jean-Baptiste Priez . +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# http://www.gnu.org/licenses/ +#***************************************************************************** +from sage.structure.element import Element +from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall +from sage.structure.parent import Parent +from sage.categories.classes_of_combinatorial_structures import \ + ClassesOfCombinatorialStructures +from sage.misc.lazy_attribute import lazy_attribute +from sage.structure.unique_representation import UniqueRepresentation + + +class Structure(Element): + """ + A *structure* is a discrete object with a degree notion. It is an element of + a combinatorial class of structures. + + For example, a (combinatorial) structure is a *composition of integer*. + """ + + __metaclass__ = ClasscallMetaclass + + @staticmethod + def __classcall__(cls, *args, **options): + """ + The constructor of an Element class must have explicit argument *parent* + but most of the time, the user does not want explicit this argument:: + + Permutation([1,3,2]) + + This method is called before the *__init__* method and provides a + compromise. + If user does not want specify a parent, this method looks for a method + *_auto_parent_*. Otherwise, the parent could be specified as an optional + argument "parent":: + + Composition([2,1,2], parent=Parent()) + + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Composition + sage: Composition([2,1,2], parent=Parent()).parent() + + sage: Composition([2,1,2]).parent() + Compositions of integers + + """ + par = "parent" + if options.has_key(par): + parent = options[par] + del options[par] + else: + try: + parent = cls._auto_parent_ + except AttributeError: + raise NotImplementedError("A *Structure* (%s) should"%cls + + " implement *_auto_parent_*") + + return typecall(cls, parent, *args, **options) + + +class StructuresClass(UniqueRepresentation, Parent): + """ + *Structures* is the python class of the classes of combinatorial structures. + + For example, the set of all *compositions of integers*. + + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: TestSuite(Compositions()).run() + + """ + + def __init__(self, category=ClassesOfCombinatorialStructures(), + *args, **options): + """ + + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: C = Compositions(); C + Compositions of integers + sage: C.graded_component(2) + Compositions of integers of degree 2 + sage: C.graded_component(18).ambient() + Compositions of integers + sage: C.graded_component(18).first().parent() + Compositions of integers + + """ + Parent.__init__(self, category=category) + + def _element_constructor_(self, *args, **options): + """ + Redefinition of that method to be coherent with the *_classcall_* of + *Structure*. + + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: C = Compositions() + sage: C([3,2,2]) + [3, 2, 2] + sage: C._element_constructor_([2,2,2]) + [2, 2, 2] + + """ + return self.element_class(parent=self, *args, **options) + + def graded_component(self, grading): + """ + Return the graded component of degree *grading*. + + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: Compositions().graded_component(4) + Compositions of integers of degree 4 + + """ + return self.GradedComponent(self, grading) + + def _an_element_(self): + """ + Default implementation + + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: I = Compositions()._an_element_(); I + [] + sage: I.parent() + Compositions of integers + + """ + for n in self.grading_set(): + try: + return self.graded_component(n).first() + except: + pass + + def some_elements(self): + """ + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: list(Compositions().some_elements()) + [[1], [2], [3], [4]] + + """ + for i in range(1,5): + if self.graded_component(i).cardinality() > 0: + yield self.graded_component(i).first() + + class GradedComponent(UniqueRepresentation, Parent): + """ + A *graded component* (of degree `n`) of a class of combinatorial structures + is the finite set of all structures of degree `n`. + + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: TestSuite(Compositions().graded_component(4)).run() + + """ + + def __init__(self, ambient, grading, + category=ClassesOfCombinatorialStructures.GradedComponents()): + """ + + """ + Parent.__init__(self, category=category) + self._ambient_ = ambient + self._grading_ = grading + + def _repr_(self): + return repr(self.ambient()) + " of degree " + repr(self.grade()) + + def ambient(self): + return self._ambient_ + + def grade(self): + return self._grading_ + + @lazy_attribute + def _element_constructor_(self, *args, **opts): + return self.ambient()._element_constructor_ From c0e3c3108492f407522cfc54a08882e80393f513 Mon Sep 17 00:00:00 2001 From: elixyre Date: Sat, 22 Nov 2014 09:39:59 +0100 Subject: [PATCH 2/2] ticket 17367: update documentation --- .../classes_of_combinatorial_structures.py | 2 +- src/sage/combinat/structures/__init__.py | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/classes_of_combinatorial_structures.py b/src/sage/categories/classes_of_combinatorial_structures.py index a90cb9a2147..21192a67a41 100644 --- a/src/sage/categories/classes_of_combinatorial_structures.py +++ b/src/sage/categories/classes_of_combinatorial_structures.py @@ -67,7 +67,7 @@ def _test_graded_components_2(self, **options): G = self.graded_component(grade) for elt in G.some_elements(): - tester.assertEqual(G.grade(), elt.grade()) + tester.assertEqual(G.grade(), self.grading(elt)) tester.assertEqual(G.ambient().graded_component(grade), G) diff --git a/src/sage/combinat/structures/__init__.py b/src/sage/combinat/structures/__init__.py index 56b881b1e17..d7736fa2258 100644 --- a/src/sage/combinat/structures/__init__.py +++ b/src/sage/combinat/structures/__init__.py @@ -203,6 +203,14 @@ class GradedComponent(UniqueRepresentation, Parent): def __init__(self, ambient, grading, category=ClassesOfCombinatorialStructures.GradedComponents()): """ + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: Compositions().graded_component(4).ambient() + Compositions of integers + sage: Compositions().graded_component(4).grade() + 4 """ Parent.__init__(self, category=category) @@ -210,14 +218,51 @@ def __init__(self, ambient, grading, self._grading_ = grading def _repr_(self): + """ + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: Compositions().graded_component(4) + Compositions of integers of degree 4 + """ return repr(self.ambient()) + " of degree " + repr(self.grade()) def ambient(self): + """ + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: Compositions().graded_component(4).ambient() + Compositions of integers + + """ return self._ambient_ def grade(self): + """ + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: Compositions().graded_component(4).grade() + 4 + + """ return self._grading_ @lazy_attribute def _element_constructor_(self, *args, **opts): + """ + TESTS:: + + sage: from sage.categories.examples.\ + classes_of_combinatorial_structures import Compositions + sage: I = Compositions().graded_component(4)([3,1,3]); I + [3, 1, 3] + sage: I.parent() + Compositions of integers + + """ return self.ambient()._element_constructor_