Ticket #11688: trac_11688_graded_module.patch

File trac_11688_graded_module.patch, 14.9 KB (added by chapoton, 8 years ago)
  • sage/categories/category.py

    # HG changeset patch
    # User F. Chapoton <chapoton@math.univ-lyon1.fr>
    # Date 1277423971 25200
    # Node ID d78f4b69a715771879ec5b21ca00874e33deba90
    # Parent  d0943a747f6dd975386c499f666609c9b1e3d8c5
    #11688: an example of a graded module with basis
    
    This patch aims at an improvement of graded modules with basis.
    
    Done:
    
    * Make an example of graded module with basis (using partitions)
    * Add the function ''homogeneous_component'' for elements of graded modules
    * Add the function ''truncate'' for elements of graded modules
    
    diff --git a/sage/categories/category.py b/sage/categories/category.py
    a b class Category(UniqueRepresentation, Sag 
    16941694        full featured version is available elsewhere in Sage, and
    16951695        should be used insted.
    16961696
    1697         Technical note: by default FooBar(...).example() is
     1697        Technical note: by default ``FooBar(...).example()`` is
    16981698        constructed by looking up
    1699         sage.categories.examples.foo_bar.Example and calling it as
    1700         ``Example(category = FooBar)``. Extra positional or named
    1701         parameters are also passed down. Categories are welcome to
    1702         override this.
     1699        ``sage.categories.examples.foo_bar.Example`` and calling it as
     1700        ``Example()``. Extra positional or named parameters are also
     1701        passed down. For a category over base ring, the base ring is
     1702        further passed down as an optional argument.
     1703
     1704        Categories are welcome to override this default implementation.
    17031705
    17041706        EXAMPLES::
    17051707
    class Category(UniqueRepresentation, Sag 
    17231725            cls = module.Example
    17241726        except AttributeError:
    17251727            return NotImplemented
     1728        # Add the base ring as optional argument if this is a category over base ring
     1729        # This really should be in Category_over_base_ring.example,
     1730        # but that would mean duplicating the documentation above.
     1731        from category_types import Category_over_base_ring
     1732        if isinstance(self, Category_over_base_ring): # Huh, smelly Run Time Type Checking, isn't it?
     1733            if "base_ring" not in keywords:
     1734                keywords["base_ring"]=self.base_ring()
    17261735        return cls(*args, **keywords)
    17271736
    17281737
  • new file sage/categories/examples/graded_modules_with_basis.py

    diff --git a/sage/categories/examples/graded_modules_with_basis.py b/sage/categories/examples/graded_modules_with_basis.py
    new file mode 100644
    - +  
     1r"""
     2Examples of graded modules with basis
     3"""
     4#*****************************************************************************
     5#  Copyright (C) 2013 Frederic Chapoton <fchapoton2@gmail.com>
     6#
     7#  Distributed under the terms of the GNU General Public License (GPL)
     8#                  http://www.gnu.org/licenses/
     9#*****************************************************************************
     10
     11from sage.categories.graded_modules_with_basis import GradedModulesWithBasis
     12from sage.combinat.free_module import CombinatorialFreeModule
     13from sage.combinat.partition import Partitions
     14
     15
     16class GradedPartitionModule(CombinatorialFreeModule):
     17    r"""
     18    This class illustrates an implementation of a graded module
     19    with basis: the free module over partitions.
     20
     21    INPUT:
     22
     23    - ``R`` - base ring
     24
     25    The implementation involves the following:
     26
     27    - A choice of how to represent elements.  In this case, the basis
     28      elements are partitions. The algebra is constructed as a
     29      :class:`CombinatorialFreeModule
     30      <sage.combinat.free_module.CombinatorialFreeModule>` on the
     31      set of partitions, so it inherits all of the methods for such
     32      objects, and has operations like addition already defined.
     33
     34    ::
     35
     36        sage: A = GradedModulesWithBasis(QQ).example()
     37
     38    - A basis function - this module is graded by the non-negative
     39      integers, so there is a function defined in this module,
     40      creatively called :func:`basis`, which takes an integer
     41      `d` as input and returns a family of partitions representing a basis
     42      for the algebra in degree `d`.
     43
     44    ::
     45
     46        sage: A.basis(2)
     47        Lazy family (Term map from Partitions to An example of a graded module with basis: the free module on partitions over Rational Field(i))_{i in Partitions of the integer 2}
     48        sage: A.basis(6)[Partition([3,2,1])]
     49        P[3, 2, 1]
     50
     51    - If the algebra is called ``A``, then its basis function is
     52      stored as ``A.basis``.  Thus the function can be used to
     53      find a basis for the degree `d` piece: essentially, just call
     54      ``A.basis(d)``.  More precisely, call ``x`` for
     55      each ``x`` in ``A.basis(d)``.
     56
     57    ::
     58
     59    sage: [m for m in A.basis(4)]
     60    [P[4], P[3, 1], P[2, 2], P[2, 1, 1], P[1, 1, 1, 1]]
     61
     62    - For dealing with basis elements: :meth:`degree_on_basis`, and
     63      :meth:`_repr_term`. The first of these defines the degree of any
     64      monomial, and then the :meth:`degree
     65      <GradedModules.Element.degree>` method for elements --
     66      see the next item -- uses it to compute the degree for a linear
     67      combination of monomials.  The last of these determines the
     68      print representation for monomials, which automatically produces
     69      the print representation for general elements.
     70
     71    ::
     72
     73        sage: A.degree_on_basis(Partition([4,3]))
     74        7
     75        sage: A._repr_term(Partition([4,3]))
     76        'P[4, 3]'
     77
     78    - There is a class for elements, which inherits from
     79      :class:`CombinatorialFreeModuleElement
     80      <sage.combinat.free_module.CombinatorialFreeModuleElement>`.  An
     81      element is determined by a dictionary whose keys are partitions and whose
     82      corresponding values are the coefficients.  The class implements
     83      two things: an :meth:`is_homogeneous
     84      <GradedModules.Element.is_homogeneous>` method and a
     85      :meth:`degree <GradedModules.Element.degree>` method.
     86
     87    ::
     88
     89        sage: p = A.monomial(Partition([3,2,1])); p
     90        P[3, 2, 1]
     91        sage: p.is_homogeneous()
     92        True
     93        sage: p.degree()
     94        6
     95    """
     96    def __init__(self, base_ring):
     97        """
     98        EXAMPLES::
     99
     100            sage: A = GradedModulesWithBasis(QQ).example(); A
     101            An example of a graded module with basis: the free module on partitions over Rational Field
     102            sage: TestSuite(A).run()
     103        """
     104        CombinatorialFreeModule.__init__(self, base_ring, Partitions(),
     105                                         category=GradedModulesWithBasis(base_ring))
     106
     107    # FIXME: this is currently required, because the implementation of ``basis``
     108    # in CombinatorialFreeModule overrides that of GradedModulesWithBasis
     109    basis = GradedModulesWithBasis.ParentMethods.__dict__['basis']
     110
     111    # This could be a default implementation
     112    def degree_on_basis(self, t):
     113        """
     114        The degree of the element determined by the partition ``t`` in
     115        this graded module.
     116
     117        INPUT:
     118
     119        - ``t`` -- the index of an element of the basis of this module,
     120          i.e. a partition
     121
     122        OUTPUT: an integer, the degree of the corresponding basis element
     123
     124        EXAMPLES::
     125
     126            sage: A = GradedModulesWithBasis(QQ).example()
     127            sage: A.degree_on_basis(Partition((2,1)))
     128            3
     129            sage: A.degree_on_basis(Partition((4,2,1,1,1,1)))
     130            10
     131            sage: type(A.degree_on_basis(Partition((1,1))))
     132            <type 'sage.rings.integer.Integer'>
     133        """
     134        return t.size()
     135
     136    def _repr_(self):
     137        """
     138        Print representation
     139
     140        EXAMPLES::
     141
     142            sage: GradedModulesWithBasis(QQ).example()  # indirect doctest
     143            An example of a graded module with basis: the free module on partitions over Rational Field
     144        """
     145        return "An example of a graded module with basis: the free module on partitions over %s" % self.base_ring()
     146
     147    def _repr_term(self, t):
     148        """
     149        Print representation for the basis element represented by the
     150        partition ``t``.
     151
     152        This governs the behavior of the print representation of all elements
     153        of the algebra.
     154
     155        EXAMPLES::
     156
     157            sage: A = GradedModulesWithBasis(QQ).example()
     158            sage: A._repr_term(Partition((4,2,1)))
     159            'P[4, 2, 1]'
     160        """
     161        return 'P' + t._repr_()
     162
     163Example = GradedPartitionModule
  • sage/categories/graded_modules_with_basis.py

    diff --git a/sage/categories/graded_modules_with_basis.py b/sage/categories/graded_modules_with_basis.py
    a b from category_types import Category_over 
    1212from sage.categories.all import GradedModules, ModulesWithBasis
    1313from sage.misc.cachefunc import cached_method
    1414
     15
    1516class GradedModulesWithBasis(Category_over_base_ring):
    1617    """
    1718    The category of graded modules with a distinguished basis
    class GradedModulesWithBasis(Category_ov 
    4041        return [GradedModules(R), ModulesWithBasis(R)]
    4142
    4243    class ParentMethods:
    43         pass
     44
     45        # TODO: which syntax do we prefer?
     46        # A.basis(degree = 3)
     47        # A.basis().subset(degree=3)
     48
     49        # This is related to the following design question:
     50        # If F = (f_i)_{i\in I} is a family, should ``F.subset(degree = 3)``
     51        # be the elements of F of degree 3 or those whose index is of degree 3?
     52
     53        def basis(self, d=None):
     54            """
     55            Returns the basis for (an homogeneous component of) this graded module
     56
     57            INPUT:
     58
     59            - `d` -- non negative integer or ``None``, optional (default: ``None``)
     60
     61            If `d` is None, returns a basis of the module.
     62            Otherwise, returns the basis of the homogeneous component of degree `d`.
     63
     64            EXAMPLES::
     65
     66                sage: A = GradedModulesWithBasis(ZZ).example()
     67                sage: A.basis(4)
     68                Lazy family (Term map from Partitions to An example of a graded module with basis: the free module on partitions over Integer Ring(i))_{i in Partitions of the integer 4}
     69
     70            Without arguments, the full basis is returned::
     71
     72                sage: A.basis()
     73                Lazy family (Term map from Partitions to An example of a graded module with basis: the free module on partitions over Integer Ring(i))_{i in Partitions}
     74                sage: A.basis()
     75                Lazy family (Term map from Partitions to An example of a graded module with basis: the free module on partitions over Integer Ring(i))_{i in Partitions}
     76            """
     77            from sage.sets.family import Family
     78            if d is None:
     79                return Family(self._basis_keys, self.monomial)
     80            else:
     81                return Family(self._basis_keys.subset(size=d), self.monomial)
    4482
    4583    class ElementMethods:
    46         pass
     84
     85        def is_homogeneous(self):
     86            """
     87            Return whether this element is homogeneous.
     88
     89            EXAMPLES::
     90
     91                sage: A = GradedModulesWithBasis(ZZ).example()
     92                sage: x=A(Partition((3,2,1)))
     93                sage: y=A(Partition((4,4,1)))
     94                sage: z=A(Partition((2,2,2)))
     95                sage: (3*x).is_homogeneous()
     96                True
     97                sage: (x - y).is_homogeneous()
     98                False
     99                sage: (x+2*z).is_homogeneous()
     100                True
     101            """
     102            degree_on_basis = self.parent().degree_on_basis
     103            degree = None
     104            for m in self.support():
     105                if degree is None:
     106                    degree = degree_on_basis(m)
     107                else:
     108                    if degree != degree_on_basis(m):
     109                        return False
     110            return True
     111
     112        def degree(self):
     113            """
     114            The degree of this element in the graded module.
     115
     116            .. note::
     117
     118                This raises an error if the element is not homogeneous.
     119                Another implementation option would be to return the
     120                maximum of the degrees of the homogeneous summands.
     121
     122            EXAMPLES::
     123
     124                sage: A = GradedModulesWithBasis(ZZ).example()
     125                sage: x = A(Partition((3,2,1)))
     126                sage: y = A(Partition((4,4,1)))
     127                sage: z = A(Partition((2,2,2)))
     128                sage: x.degree()
     129                6
     130                sage: (x + 2*z).degree()
     131                6
     132                sage: (y - x).degree()
     133                Traceback (most recent call last):
     134                ...
     135                ValueError: Element is not homogeneous.
     136            """
     137            if not self.support():
     138                raise ValueError("The zero element does not have a well-defined degree.")
     139            if self.is_homogeneous():
     140                return self.parent().degree_on_basis(self.leading_support())
     141            else:
     142                raise ValueError("Element is not homogeneous.")
     143
     144        def homogeneous_component(self, n):
     145            """
     146            Return the homogeneous component of degree ``n`` of this
     147            element.
     148
     149            EXAMPLES::
     150
     151                sage: A = GradedModulesWithBasis(ZZ).example()
     152                sage: x = A.an_element(); x
     153                2*P[] + 2*P[1] + 3*P[2]
     154                sage: x.homogeneous_component(-1)
     155                0
     156                sage: x.homogeneous_component(0)
     157                2*P[]
     158                sage: x.homogeneous_component(1)
     159                2*P[1]
     160                sage: x.homogeneous_component(2)
     161                3*P[2]
     162                sage: x.homogeneous_component(3)
     163                0
     164
     165            TESTS:
     166
     167            Check that this really return ``A.zero()`` and not a plain ``0``::
     168
     169                sage: x.homogeneous_component(3).parent() is A
     170                True
     171            """
     172            degree_on_basis = self.parent().degree_on_basis
     173            return self.parent().sum_of_terms((i, c)
     174                                              for (i, c) in self
     175                                              if degree_on_basis(i) == n)
     176
     177        def truncate(self, n):
     178            """
     179            Return the sum of the homogeneous components of degree ``< n`` of this element
     180
     181            EXAMPLES::
     182
     183                sage: A = GradedModulesWithBasis(ZZ).example()
     184                sage: x = A.an_element(); x
     185                2*P[] + 2*P[1] + 3*P[2]
     186                sage: x.truncate(0)
     187                0
     188                sage: x.truncate(1)
     189                2*P[]
     190                sage: x.truncate(2)
     191                2*P[] + 2*P[1]
     192                sage: x.truncate(3)
     193                2*P[] + 2*P[1] + 3*P[2]
     194
     195            TESTS:
     196
     197            Check that this really return ``A.zero()`` and not a plain ``0``::
     198
     199                sage: x.truncate(0).parent() is A
     200                True
     201            """
     202            degree_on_basis = self.parent().degree_on_basis
     203            return self.parent().sum_of_terms((i, c) for (i, c) in self
     204                                              if degree_on_basis(i) < n)