Ticket #10193: trac_10193-graded_sets-rebased.patch

File trac_10193-graded_sets-rebased.patch, 22.5 KB (added by chapoton, 5 years ago)
  • doc/en/reference/categories/index.rst

    # HG changeset patch
    # User Vincent Delecroix <20100.delecroix at gmail.com>
    # Date 1360881387 18000
    # Node ID 38775d106cc5e8dc628b4d6a42b9efaac1034fc0
    # Parent  b80acf19629092f84fa6e075de752561a342651d
    trac #10193: Create the category of GradedEnumeratedSets
    
    diff --git a/doc/en/reference/categories/index.rst b/doc/en/reference/categories/index.rst
    a b Categories 
    127127   sage/categories/semigroups
    128128   sage/categories/semirings
    129129   sage/categories/sets_cat
     130   sage/categories/sets_with_grading   
    130131   sage/categories/unique_factorization_domains
    131132   sage/categories/vector_spaces
    132133   sage/categories/weyl_groups
  • sage/categories/all.py

    diff --git a/sage/categories/all.py b/sage/categories/all.py
    a b from g_sets import GSets 
    2828from pointed_sets import PointedSets
    2929
    3030from sets_with_partial_maps import SetsWithPartialMaps
     31from sets_with_grading import SetsWithGrading
     32
    3133from groupoid import Groupoid
    3234
    3335# enumerated sets
  • new file sage/categories/examples/sets_with_grading.py

    diff --git a/sage/categories/examples/sets_with_grading.py b/sage/categories/examples/sets_with_grading.py
    new file mode 100644
    - +  
     1r"""
     2An example of graded set: non-negative integers graded by themselves.
     3"""
     4
     5from sage.structure.parent import Parent
     6from sage.structure.unique_representation import UniqueRepresentation
     7from sage.categories.sets_with_grading import SetsWithGrading
     8
     9from sage.rings.integer_ring import IntegerRing
     10from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
     11
     12class NonNegativeIntegers(UniqueRepresentation, Parent):
     13    r"""
     14    Non negative integers graded by themselves.
     15
     16    EXAMPLES::
     17
     18        sage: E = SetsWithGrading().example()
     19        sage: E
     20        Non negative integers
     21        sage: E.graded_component(0)
     22        {0}
     23        sage: E.graded_component(100)
     24        {100}
     25    """
     26    def __init__(self):
     27        r"""
     28        TESTS::
     29
     30            sage: TestSuite(SetsWithGrading().example()).run()
     31        """
     32        Parent.__init__(self, category=SetsWithGrading(), facade=IntegerRing())
     33
     34    def an_element(self):
     35        r"""
     36        Returns 0.
     37
     38        EXAMPLES::
     39
     40            sage: SetsWithGrading().example().an_element()
     41            0
     42        """
     43        return 0
     44
     45    def _repr_(self):
     46        r"""
     47        TESTS::
     48
     49            sage: SetsWithGrading().example() # indirect example
     50            Non negative integers
     51        """
     52        return "Non negative integers"
     53
     54    def graded_component(self, grade):
     55        r"""
     56        Returns the component with grade ``grade``.
     57
     58        EXAMPLES::
     59
     60            sage: N = SetsWithGrading().example()
     61            sage: N.graded_component(65)
     62            {65}
     63        """
     64        return FiniteEnumeratedSet([grade])
     65
     66    def grading(self, elt):
     67        r"""
     68        Returns the grade of ``elt``.
     69
     70        EXAMPLES::
     71
     72            sage: N = SetsWithGrading().example()
     73            sage: N.grading(10)
     74            10
     75        """
     76        return elt
     77
     78    def generating_series(self, var='z'):
     79        r"""
     80        Returns `1 / (1-z)`.
     81
     82
     83        EXAMPLES::
     84
     85            sage: N = SetsWithGrading().example(); N
     86            Non negative integers
     87            sage: f = N.generating_series(); f
     88            1/(-z + 1)
     89            sage: LaurentSeriesRing(ZZ,'z')(f)
     90            1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + z^8 + z^9 + z^10 + z^11 + z^12 + z^13 + z^14 + z^15 + z^16 + z^17 + z^18 + z^19 + O(z^20)
     91        """
     92        from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
     93        from sage.rings.integer import Integer
     94        R = PolynomialRing(IntegerRing(), var)
     95        z = R.gen()
     96        return Integer(1) / (Integer(1)-z)
     97
     98Example = NonNegativeIntegers
  • new file sage/categories/sets_with_grading.py

    diff --git a/sage/categories/sets_with_grading.py b/sage/categories/sets_with_grading.py
    new file mode 100644
    - +  
     1r"""
     2Sets With a Grading
     3"""
     4#*****************************************************************************
     5#  Copyright (C) 2010-2012 Nicolas M. Thiery <nthiery at users.sf.net>
     6#
     7#  Distributed under the terms of the GNU General Public License (GPL)
     8#                  http://www.gnu.org/licenses/
     9#******************************************************************************
     10
     11from sage.misc.cachefunc import cached_method
     12from sage.misc.abstract_method import abstract_method
     13from category_types import Category
     14from sage.categories.sets_cat import Sets
     15from sage.categories.enumerated_sets import EnumeratedSets
     16from sage.sets.non_negative_integers import NonNegativeIntegers
     17
     18class SetsWithGrading(Category):
     19    r"""
     20    The category of sets with a grading.
     21
     22    An *set with a grading* is a set `S` equipped with a
     23    grading by some other set `I` (by default the set `\NN` of the non
     24    negative integers):
     25
     26    .. math::
     27
     28         S = \biguplus_{i\in I} S_i
     29
     30    where the *graded components* `S_i` are (usually finite)
     31    sets. The *grading* function maps each element `s` of
     32    `S` to its *grade* `i`, so that `s\in S_i`.
     33
     34    From implementation point of vue, if the graded set is enumerated then each
     35    graded component should be enumerated (there is a check in the method
     36    :meth:`~SetsWithGrading.ParentMethods._test_graded_components`). The
     37    contrary needs not be true.
     38
     39    EXAMPLES:
     40
     41    A typical example of set with grading is the set of non-negative integers
     42    graded by themselves::
     43
     44        sage: N = SetsWithGrading().example(); N
     45        Non negative integers
     46        sage: N.category()
     47        Category of facade sets with grading
     48
     49    It is graded by `\NN`::
     50
     51        sage: N.grading_set()
     52        Non negative integers
     53
     54    The *grading function* is given by ``N.grading``::
     55
     56        sage: N.grading(4)
     57        4
     58
     59    The graded component `S_i` is the set of all integer partitions of
     60    `i`::
     61
     62        sage: N.graded_component(grade = 5)
     63        {5}
     64        sage: N.graded_component(grade = 42)
     65        {42}
     66
     67    Here are some information about this category::
     68
     69        sage: SetsWithGrading()
     70        Category of sets with grading
     71        sage: SetsWithGrading().super_categories()
     72        [Category of sets]
     73        sage: SetsWithGrading().all_super_categories()
     74        [Category of sets with grading,
     75         Category of sets,
     76         Category of sets with partial maps,
     77         Category of objects]
     78
     79    .. TODO::
     80
     81        - This should be moved to Sets().WithGrading()
     82        - Should the grading set be a parameter for this category?
     83        - Does the enumeration need to be compatible with the grading? Be
     84          careful that the fact that graded components are allowed to be finite
     85          or infinite make the answer complicated.
     86
     87    TESTS::
     88
     89        sage: C = SetsWithGrading()
     90        sage: TestSuite(C).run()
     91    """
     92
     93    @cached_method
     94    def super_categories(self):
     95        """
     96        EXAMPLES::
     97
     98            sage: SetsWithGrading().super_categories()
     99            [Category of sets]
     100        """
     101        return [Sets()]
     102
     103    class ParentMethods:
     104
     105        def _test_graded_components(self, **options):
     106            r"""
     107            Test that some graded components of ``self`` are parent with
     108            initialized category and that the parent has a properly implemented
     109            ``grading`` method.
     110
     111            EXAMPLES::
     112
     113                sage: SetsWithGrading().example()._test_graded_components()
     114            """
     115            tester = self._tester(**options)
     116            for grade in self.grading_set().some_elements():
     117                G = self.graded_component(grade)
     118                if self in EnumeratedSets():
     119                    tester.assertTrue(G in EnumeratedSets())
     120                else:
     121                    tester.assertTrue(G in Sets())
     122                for elt in G.some_elements():
     123                    tester.assertEqual(self.grading(elt), grade)
     124
     125        def grading_set(self):
     126            """
     127            Returns the set ``self`` is graded by. By default, this is
     128            the set of non negative integers.
     129
     130            EXAMPLES::
     131
     132                sage: SetsWithGrading().example().grading_set()
     133                Non negative integers
     134            """
     135            return NonNegativeIntegers()
     136
     137        # TODO:
     138        #  - Should this method be in EnumeratedSets? With a default implementation
     139        #    a la ``filter``?
     140        #  - Do we want to enforce implementing subset rather than graded_component?
     141        @abstract_method(optional=True)
     142        def subset(self, *args, **options):
     143            """
     144            Returns the subset of ``self`` described by the given parameters
     145
     146            See also: :meth:`graded_component`
     147
     148            EXAMPLES::
     149
     150                sage: W = WeightedIntegerVectors([3,2,1]); W
     151                Integer vectors weighted by [3, 2, 1]
     152                sage: W.subset(4)
     153                Integer vectors of 4 weighted by [3, 2, 1]
     154            """
     155
     156        def graded_component(self, grade):
     157            """
     158            Return the graded component of ``self`` with grade ``grade``.
     159
     160            The default implementation just calls the method :meth:`subset` with
     161            the argument ``grade``.
     162
     163            EXAMPLES::
     164
     165                sage: N = SetsWithGrading().example(); N
     166                Non negative integers
     167                sage: N.graded_component(3)
     168                {3}
     169            """
     170            return self.subset(grade)
     171
     172        def grading(self, elt):
     173            """
     174            Return the grading of the element ``elt`` of self.`
     175
     176            This default implementation calls ``elt.grade()``.
     177
     178            EXAMPLES::
     179
     180                sage: N = SetsWithGrading().example(); N
     181                Non negative integers
     182                sage: N.grading(4)
     183                4
     184            """
     185            return elt.grade()
     186
     187        def generating_series(self):
     188            """
     189            Default implementation for generating series.
     190
     191            OUTPUT: a series, indexed by the grading set
     192
     193            EXAMPLES::
     194
     195                sage: N = SetsWithGrading().example(); N
     196                Non negative integers
     197                sage: N.generating_series()
     198                1/(-z + 1)
     199            """
     200            from sage.combinat.species.series import LazyPowerSeriesRing
     201            from sage.rings.integer_ring import ZZ
     202            R = LazyPowerSeriesRing(ZZ)
     203            R(self.graded_component(grade).cardinality() for grade in self.grading_set())
     204
     205        # TODO:
     206        #   * asymptotic behavior: we need an object for asymptotic behavior and
     207        #   a default name for the method that should be here. Such method will
     208        #   have two goals (and perhaps need two implementations): give a
     209        #   theorem on asymptotic and be a tool to determine a strategy for
     210        #   algorithms.
     211
  • sage/combinat/integer_vector_weighted.py

    diff --git a/sage/combinat/integer_vector_weighted.py b/sage/combinat/integer_vector_weighted.py
    a b  
    11"""
    22Weighted Integer Vectors
    33
     4AUTHORS:
     5
     6 - Mike Hansen (2007): initial version, ported from MuPAD-Combinat
     7 - Nicolas M. Thiery (2010-10-30): WeightedIntegerVectors(weights) + cleanup
     8
    49.. WARNING::
    510
    6    The list(self) function in this file used the :class:`Permutation_class` class improperly, returning
    7    the list of, generally speaking, invalid permutations (repeated entries, including 0).
     11    The list(self) function in this file used the :class:`Permutation_class` class improperly, returning
     12    the list of, generally speaking, invalid permutations (repeated entries, including 0).
    813"""
    914#*****************************************************************************
    10 #       Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>,
     15#  Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>
     16#                2010 Nicolas M. Thiery <nthiery at users.sf.net>
    1117#
    1218#  Distributed under the terms of the GNU General Public License (GPL)
    1319#
    14 #    This code is distributed in the hope that it will be useful,
    15 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
    16 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    17 #    General Public License for more details.
    18 #
    19 #  The full text of the GPL is available at:
    20 #
    2120#                  http://www.gnu.org/licenses/
    2221#*****************************************************************************
    23 
    24 from combinat import CombinatorialClass
     22from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
     23from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
     24from sage.categories.sets_with_grading import SetsWithGrading
    2525from __builtin__ import list as builtinlist
    2626from sage.rings.integer import Integer
     27from sage.structure.unique_representation import UniqueRepresentation
     28from sage.structure.parent import Parent
     29from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets
    2730from sage.combinat.words.word import Word
    2831from permutation import Permutation_class
    2932
    30 def WeightedIntegerVectors(n, weight):
     33def WeightedIntegerVectors(n = None, weight = None):
    3134    """
    32     Returns the combinatorial class of integer vectors of n weighted by
    33     weight, that is, the nonnegative integer vectors `(v_1,\\dots,v_{length(weight)})`
    34     satisfying `\\sum_i v_i weight[i]==n`.
    35    
     35    Returns the combinatorial class of integer vectors of ``n``
     36    weighted by ``weight``, that is, the nonnegative integer vectors
     37    `(v_1,\\dots,v_{length(weight)})` satisfying `\\sum_i v_i
     38    weight[i]==n`.
     39
     40    INPUT:
     41
     42     - ``n`` -- a non negative integer (optional)
     43
     44     - ``weight`` -- a tuple (or list or iterable) of positive integers
     45
    3646    EXAMPLES::
    37    
     47
    3848        sage: WeightedIntegerVectors(8, [1,1,2])
    3949        Integer vectors of 8 weighted by [1, 1, 2]
    4050        sage: WeightedIntegerVectors(8, [1,1,2]).first()
    def WeightedIntegerVectors(n, weight): 
    4555        25
    4656        sage: WeightedIntegerVectors(8, [1,1,2]).random_element()
    4757        [1, 1, 3]
     58
     59        sage: WeightedIntegerVectors([1,1,2])
     60        Integer vectors weighted by [1, 1, 2]
     61        sage: WeightedIntegerVectors([1,1,2]).cardinality()
     62        +Infinity
     63        sage: WeightedIntegerVectors([1,1,2]).first()
     64        [0, 0, 0]
     65
     66    TESTS::
     67
     68        sage: WeightedIntegerVectors(None,None)
     69        Traceback (most recent call last):
     70        ...
     71        ValueError: weights should be specified
     72
     73    .. TODO::
     74
     75        should the order of the arguments ``n`` and ``weight`` be
     76        exchanged to simplify the logic ?
    4877    """
    49     return WeightedIntegerVectors_nweight(n, weight)
     78    if weight is None and n is not None:
     79        weight = n
     80        n = None
     81    if weight is None:
     82        raise ValueError("weights should be specified")
     83    weight = tuple(weight)
     84    if n is None:
     85        return WeightedIntegerVectors_all(weight)
     86    else:
     87        return WeightedIntegerVectors_nweight(n, weight)
    5088
    51 class WeightedIntegerVectors_nweight(CombinatorialClass):
     89class WeightedIntegerVectors_all(DisjointUnionEnumeratedSets):
     90    r"""
     91    Set of weighted integer vectors.
     92
     93    EXAMPLES::
     94
     95        sage: W = WeightedIntegerVectors([3,1,1,2,1]); W
     96        Integer vectors weighted by [3, 1, 1, 2, 1]
     97        sage: W.cardinality()
     98        +Infinity
     99
     100        sage: W12 = W.graded_component(12)
     101        sage: W12.an_element()
     102        [4, 0, 0, 0, 0]
     103        sage: W12.last()
     104        [0, 12, 0, 0, 0]
     105        sage: W12.cardinality()
     106        441
     107        sage: for w in W12: print w
     108        [4, 0, 0, 0, 0]
     109        [3, 0, 0, 1, 1]
     110        [3, 0, 1, 1, 0]
     111        ...
     112        [0, 11, 1, 0, 0]
     113        [0, 12, 0, 0, 0]
     114    """
     115    def __init__(self, weights):
     116        """
     117        TESTS::
     118
     119            sage: C = WeightedIntegerVectors([2,1,3])
     120            sage: C.__class__
     121            <class 'sage.combinat.integer_vector_weighted.WeightedIntegerVectors_all_with_category'>
     122            sage: C.category()
     123            Join of Category of sets with grading and Category of infinite enumerated sets
     124            sage: TestSuite(C).run()
     125        """
     126        self._weights = weights
     127        from sage.sets.all import Family, NonNegativeIntegers
     128        # Use "partial" to make the basis function (with the weights
     129        # argument specified) pickleable.  Otherwise, it seems to
     130        # cause problems...
     131        from functools import partial
     132        F = Family(NonNegativeIntegers(), partial(WeightedIntegerVectors, weight = weights))
     133        DisjointUnionEnumeratedSets.__init__(self, F, facade=True, keepkey=False,
     134                                             category = (SetsWithGrading(), InfiniteEnumeratedSets()))
     135
     136    def _repr_(self):
     137        """
     138        EXAMPLES::
     139
     140            sage: WeightedIntegerVectors([2,1,3])
     141            Integer vectors weighted by [2, 1, 3]
     142        """
     143        return "Integer vectors weighted by %s"%list(self._weights)
     144
     145    def __contains__(self, x):
     146        """
     147        EXAMPLES::
     148
     149            sage: [] in WeightedIntegerVectors([])
     150            True
     151            sage: [3,0,0] in WeightedIntegerVectors([2,1,1])
     152            True
     153            sage: [3,0] in WeightedIntegerVectors([2,1,1])
     154            False
     155            sage: [3,-1,0] in WeightedIntegerVectors([2,1,1])
     156            False
     157        """
     158        return isinstance(x, (builtinlist, Permutation_class)) and \
     159            len(x) == len(self._weights)   and \
     160            all(isinstance(i, (int, Integer)) and i>=0 for i in x)
     161
     162    def subset(self, size = None):
     163        """
     164        EXAMPLES::
     165
     166            sage: C = WeightedIntegerVectors([2,1,3])
     167            sage: C.subset(4)
     168            Integer vectors of 4 weighted by [2, 1, 3]
     169        """
     170        if size is None:
     171            return self
     172        return self._family[size]
     173
     174    def grading(self, x): # or degree / grading
     175        """
     176        EXAMPLES::
     177
     178            sage: C = WeightedIntegerVectors([2,1,3])
     179            sage: C.grading((2,1,1))
     180            8
     181        """
     182        return sum([exp*deg for exp,deg in zip(x, self._weights)])
     183
     184class WeightedIntegerVectors_nweight(UniqueRepresentation, Parent):
    52185    def __init__(self, n, weight):
    53186        """
    54187        TESTS::
    55        
    56             sage: WIV = WeightedIntegerVectors(8, [1,1,2])
    57             sage: WIV == loads(dumps(WIV))
    58             True
     188
     189            sage: C = WeightedIntegerVectors(8, [1,1,2])
     190            sage: C.__class__
     191            <class 'sage.combinat.integer_vector_weighted.WeightedIntegerVectors_nweight_with_category'>
     192            sage: TestSuite(C).run()
    59193        """
    60         self.n = n
    61         self.weight = weight
    62        
    63     def __repr__(self):
     194        Parent.__init__(self, category = FiniteEnumeratedSets())
     195        self._n = n
     196        self._weights = weight
     197
     198    def _repr_(self):
    64199        """
    65200        TESTS::
    66        
     201
    67202            sage: repr(WeightedIntegerVectors(8, [1,1,2]))
    68203            'Integer vectors of 8 weighted by [1, 1, 2]'
    69204        """
    70         return "Integer vectors of %s weighted by %s"%(self.n, self.weight)
     205        return "Integer vectors of %s weighted by %s"%(self._n, list(self._weights))
    71206
    72207    def __contains__(self, x):
    73208        """
    74         TESTS::
    75        
     209        EXAMPLES::
     210
    76211            sage: [] in WeightedIntegerVectors(0, [])
    77212            True
    78213            sage: [] in WeightedIntegerVectors(1, [])
    class WeightedIntegerVectors_nweight(Com 
    96231            sage: [0] in WeightedIntegerVectors(0, [])
    97232            False
    98233        """
    99         if not isinstance(x, builtinlist):
     234        if not isinstance(x, (builtinlist, Permutation_class)):
    100235            return False
    101         if len(self.weight) != len(x):
     236        if len(self._weights) != len(x):
    102237            return False
    103238        s = 0
    104239        for i in range(len(x)):
    105240            if not isinstance(x[i], (int, Integer)):
    106241                return False
    107             s += x[i]*self.weight[i]
    108         if s != self.n:
     242            s += x[i]*self._weights[i]
     243        if s != self._n:
    109244            return False
    110245
    111246        return True
    class WeightedIntegerVectors_nweight(Com 
    113248    def _recfun(self, n, l):
    114249        """
    115250        EXAMPLES::
    116        
     251
    117252            sage: w = WeightedIntegerVectors(3, [2,1,1])
    118             sage: w._recfun(3, [1,1,2])
     253            sage: list(w._recfun(3, [1,1,2]))
    119254            [[0, 1, 1], [1, 0, 1], [0, 3, 0], [1, 2, 0], [2, 1, 0], [3, 0, 0]]
    120255        """
    121         result = []
    122256        w = l[-1]
    123257        l = l[:-1]
    124258        if l == []:
    125259            d = int(n) / int(w)
    126             if n%w == 0:
    127                 return [[d]]
    128             else:
    129                 return [] #bad branch...
    130            
     260            if n % w == 0:
     261                yield [d]
     262                # Otherwise: bad branch
     263            return
     264
    131265        for d in range(int(n)/int(w), -1, -1):
    132             result += [ x + [d] for x in self._recfun(n-d*w, l) ]
     266            for x in self._recfun(n-d*w, l):
     267                yield x + [d]
    133268
    134         return result
    135    
    136     def list(self):
     269    def __iter__(self):
    137270        """
    138271        TESTS::
    139        
     272
    140273            sage: WeightedIntegerVectors(7, [2,2]).list()
    141274            []
    142275            sage: WeightedIntegerVectors(3, [2,1,1]).list()
    143276            [[1, 0, 1], [1, 1, 0], [0, 0, 3], [0, 1, 2], [0, 2, 1], [0, 3, 0]]
    144        
     277
    145278        ::
    146        
     279
    147280            sage: ivw = [ WeightedIntegerVectors(k, [1,1,1]) for k in range(11) ]
    148281            sage: iv  = [ IntegerVectors(k, 3) for k in range(11) ]
    149282            sage: all( [ sorted(iv[k].list()) == sorted(ivw[k].list()) for k in range(11) ] )
    150283            True
    151        
     284
    152285        ::
    153        
     286
    154287            sage: ivw = [ WeightedIntegerVectors(k, [2,3,7]) for k in range(11) ]
    155288            sage: all( [ i.cardinality() == len(i.list()) for i in ivw] )
    156289            True
    157290        """
    158         if len(self.weight) == 0:
    159             if self.n == 0:
    160                 return [[]]
    161             else:
    162                 return []
     291        if len(self._weights) == 0:
     292            if self._n == 0:
     293                yield []
     294            return
    163295
    164         perm = Word(self.weight).standard_permutation()
    165         l = [x for x in sorted(self.weight)]
    166         return [perm.action(_) for _ in self._recfun(self.n,l)]
     296        perm = Word(self._weights).standard_permutation()
     297        l = [x for x in sorted(self._weights)]
     298        for x in self._recfun(self._n, l):
     299            yield perm.action(x)
     300            #_left_to_right_multiply_on_right(Permutation_class(x))