Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Merge branch 'u/elixyre/class_of_combinatorial_structures' of git://t…
Browse files Browse the repository at this point in the history
…rac.sagemath.org/sage into t17367/class_of_comb_struct

and fix some documentation
  • Loading branch information
elixyre committed Sep 22, 2015
2 parents 7eb8510 + c0e3c31 commit 5a300c7
Show file tree
Hide file tree
Showing 8 changed files with 797 additions and 33 deletions.
1 change: 1 addition & 0 deletions src/sage/categories/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,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
Expand Down
109 changes: 109 additions & 0 deletions src/sage/categories/classes_of_combinatorial_structures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# -*- 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 <jbp@kerios.fr>.
#
# 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.
"""

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(), self.grading(elt))

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
"""
209 changes: 209 additions & 0 deletions src/sage/categories/examples/classes_of_combinatorial_structures.py
Original file line number Diff line number Diff line change
@@ -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 <jbp@kerios.fr>.
#
# 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 more efficient than the current one (Compositions_n.__iter__).
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
31 changes: 26 additions & 5 deletions src/sage/categories/sets_with_grading.py
Original file line number Diff line number Diff line change
Expand Up @@ -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``.
Expand All @@ -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):
"""
Expand Down Expand Up @@ -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)
Loading

0 comments on commit 5a300c7

Please sign in to comment.