Ticket #11641: trac_11641-combinatorial_maps_decorator-cs.patch

File trac_11641-combinatorial_maps_decorator-cs.patch, 16.1 KB (added by jdemeyer, 9 years ago)
  • doc/en/reference/combinat/index.rst

    # HG changeset patch
    # User Christian Stump <christian.stump at gmail.com>
    # Date 1354268007 -3600
    # Node ID 3f30b3ceac60a97424c2458e0b264a8fb9670e02
    # Parent  f4cbda7c354e4f5c27adb054b495dcafce5d5db1
    trac 11641: Implementation of a decorator for combinatorial maps
    
    diff --git a/doc/en/reference/combinat/index.rst b/doc/en/reference/combinat/index.rst
    a b  
    6969
    7070   ../sage/combinat/dict_addition
    7171   ../sage/combinat/misc
     72   ../sage/combinat/combinatorial_map
    7273
  • new file sage/combinat/combinatorial_map.py

    diff --git a/sage/combinat/combinatorial_map.py b/sage/combinat/combinatorial_map.py
    new file mode 100644
    - +  
     1"""
     2Combinatorial maps
     3"""
     4#*****************************************************************************
     5#       Copyright (C) 2011 Christian Stump <christian.stump at gmail.com>
     6#
     7#  Distributed under the terms of the GNU General Public License (GPL)
     8#                  http://www.gnu.org/licenses/
     9#*****************************************************************************
     10
     11def combinatorial_map(f=None, order=None, name=None):
     12    r"""
     13    Combinatorial maps
     14
     15    We call a method a *combinatorial map* if it is a map between two
     16    combinatorial sets.
     17
     18    INPUT:
     19
     20    - ``f`` -- (default: ``None``, if combinatorial_map is used as a decorator) a function
     21    - ``name`` -- (default: ``None``) the name for nicer outputs on combinatorial maps
     22    - ``order`` -- (default: ``None``) the order of the combinatorial map, if it is known. Is not used, but might be helpful later
     23
     24    OUTPUT:
     25
     26    - A combinatorial map. This is an instance of the :class:`CombinatorialMap`
     27
     28    The decorator :obj:`combinatorial_map` can be used to declare
     29    methods as combinatorial maps.
     30
     31    EXAMPLES::
     32
     33        sage: p = Permutation([1,3,2,4])
     34        sage: p.left_tableau
     35        Combinatorial map: Robinson-Schensted insertion tableau
     36
     37    We define a class illustrating the use of the decorator
     38    :obj:`combinatorial_map` with the various arguments::
     39
     40        sage: from sage.combinat.combinatorial_map import combinatorial_map
     41        sage: class MyPermutation(object):
     42        ...
     43        ...       @combinatorial_map()
     44        ...       def reverse(self):
     45        ...           '''
     46        ...           Reverse the permutation
     47        ...           '''
     48        ...           pass
     49        ...
     50        ...       @combinatorial_map(order=2)
     51        ...       def inverse(self):
     52        ...           '''
     53        ...           The inverse of the permutation
     54        ...           '''
     55        ...           pass
     56        ...
     57        ...       @combinatorial_map(name='descent set of permutation')
     58        ...       def descent_set(self):
     59        ...           '''
     60        ...           The descent set of the permutation
     61        ...           '''
     62        ...           pass
     63        ...
     64        ...       def major_index(self):
     65        ...           '''
     66        ...           The major index of the permutation
     67        ...           '''
     68        ...           pass
     69        sage: MyPermutation.reverse
     70        Combinatorial map: reverse
     71        sage: MyPermutation.descent_set
     72        Combinatorial map: descent set of permutation
     73        sage: MyPermutation.inverse
     74        Combinatorial map: inverse
     75
     76    One can determine all the combinatorial maps associated with a given object
     77    as follows::
     78
     79        sage: from sage.combinat.combinatorial_map import combinatorial_maps_in_class
     80        sage: X = combinatorial_maps_in_class(MyPermutation); X # random
     81        [Combinatorial map: reverse,
     82         Combinatorial map: descent set of permutation,
     83         Combinatorial map: inverse]
     84
     85    The method ``major_index`` defined about is not a combinatorial map::
     86
     87        sage: MyPermutation.major_index
     88        <unbound method MyPermutation.major_index>
     89
     90    But one can define a function that turns ``major_index`` into a combinatorial map::
     91
     92        sage: def major_index(p):
     93        ...       return p.major_index()
     94        ...
     95        sage: major_index
     96        <function major_index at ...>
     97        sage: combinatorial_map(major_index)
     98        Combinatorial map: major_index
     99
     100    """
     101    if f is None:
     102        return lambda f: CombinatorialMap(f, order=order, name=name)
     103    else:
     104        return CombinatorialMap(f, order=order, name=name)
     105
     106class CombinatorialMap(object):
     107    r"""
     108    This is a wrapper class for methods that are *combinatorial maps*.
     109
     110    For further details and doctests, see :func:`combinatorial_map`.
     111    """
     112    def __init__(self, f, order=None, name=None):
     113        """
     114        Constructor for combinatorial maps
     115
     116        EXAMPLES::
     117
     118            sage: from sage.combinat.combinatorial_map import combinatorial_map
     119            sage: def f(x):
     120            ...       "doc of f"
     121            ...       return x
     122            ...
     123            sage: x = combinatorial_map(f); x
     124            Combinatorial map: f
     125            sage: x.__doc__
     126            'doc of f'
     127            sage: x.__name__
     128            'f'
     129            sage: x.__module__
     130            '__main__'
     131        """
     132        import types
     133        if not isinstance(f, types.FunctionType):
     134            raise ValueError, "Only plain functions are supported"
     135        self._f = f
     136        self._order = order
     137        self._name = name
     138        if hasattr(f, "func_doc"):
     139            self.__doc__ = f.func_doc
     140        if hasattr(f, "func_name"):
     141            self.__name__ = f.func_name
     142        else:
     143            self.__name__ = "..."
     144        if hasattr(f, "__module__"):
     145            self.__module__ = f.__module__
     146
     147    def __repr__(self):
     148        """
     149        EXAMPLES::
     150
     151            sage: p = Permutation([1,3,2,4])
     152            sage: p.left_tableau.__repr__()
     153            'Combinatorial map: Robinson-Schensted insertion tableau'
     154        """
     155        name = self._name if self._name else self.__name__
     156        return "Combinatorial map: %s" % name
     157
     158    def _sage_src_lines_(self):
     159        """
     160        Returns the source code location for the wrapped function.
     161
     162        EXAMPLES::
     163
     164            sage: p = Permutation([1,3,2,4])
     165            sage: cm = p.left_tableau; cm
     166            Combinatorial map: Robinson-Schensted insertion tableau
     167            sage: (src, lines) = cm._sage_src_lines_()
     168            sage: src[0]
     169            "    @combinatorial_map(name='Robinson-Schensted insertion tableau')\n"
     170            sage: lines # random
     171            2653
     172        """
     173        from sage.misc.sageinspect import sage_getsourcelines
     174        return sage_getsourcelines(self._f)
     175
     176    def __get__(self, inst, cls=None):
     177        """
     178        Bounds the method of self to the given instance.
     179
     180        EXAMPLES::
     181
     182            sage: p = Permutation([1,3,2,4])
     183            sage: p.left_tableau #indirect doctest
     184            Combinatorial map: Robinson-Schensted insertion tableau
     185        """
     186        self._inst = inst
     187        return self
     188
     189    def __call__(self, *args, **kwds):
     190        """
     191        Calls the combinatorial map.
     192
     193        EXAMPLES::
     194
     195            sage: p = Permutation([1,3,2,4])
     196            sage: cm = type(p).left_tableau; cm
     197            Combinatorial map: Robinson-Schensted insertion tableau
     198            sage: cm(p)
     199            [[1, 2, 4], [3]]
     200            sage: cm(Permutation([4,3,2,1]))
     201            [[1], [2], [3], [4]]
     202        """
     203        if self._inst is not None:
     204            return self._f(self._inst, *args, **kwds)
     205        else:
     206            return self._f(*args, **kwds)
     207
     208    def order(self):
     209        """
     210        Returns the order of ``self``, or ``None`` if the order is not known.
     211
     212        EXAMPLES::
     213
     214            sage: from sage.combinat.combinatorial_map import combinatorial_map
     215            sage: class CombinatorialClass:
     216            ...       @combinatorial_map(order=2)
     217            ...       def to_self_1(): pass
     218            ...       @combinatorial_map()
     219            ...       def to_self_2(): pass
     220            sage: CombinatorialClass.to_self_1.order()
     221            2
     222            sage: CombinatorialClass.to_self_2.order() is None
     223            True
     224        """
     225        return self._order
     226
     227    def name(self):
     228        """
     229        If given, returns the name of a combinatorial map; ``None`` otherwise.
     230        This is used for the string representation of ``self``.
     231
     232        EXAMPLES::
     233
     234            sage: from sage.combinat.combinatorial_map import combinatorial_map
     235            sage: class CombinatorialClass:
     236            ...       @combinatorial_map(name='map1')
     237            ...       def to_self_1(): pass
     238            ...       @combinatorial_map()
     239            ...       def to_self_2(): pass
     240            sage: CombinatorialClass.to_self_1.name()
     241            'map1'
     242            sage: CombinatorialClass.to_self_2.name() is None
     243            True
     244        """
     245        return self._name
     246
     247def combinatorial_maps_in_class(cls):
     248    """
     249    Returns the combinatorial maps of the class as a list of combinatorial maps.
     250
     251    EXAMPLES::
     252
     253        sage: from sage.combinat.combinatorial_map import combinatorial_maps_in_class
     254        sage: p = Permutation([1,3,2,4])
     255        sage: cmaps = combinatorial_maps_in_class(p)
     256        sage: cmaps # random
     257        [Combinatorial map: Robinson-Schensted insertion tableau,
     258         Combinatorial map: Robinson-Schensted recording tableau,
     259         Combinatorial map: Robinson-Schensted tableau shape,
     260         Combinatorial map: complement,
     261         Combinatorial map: descent composition,
     262         Combinatorial map: inverse, ...]
     263        sage: p.left_tableau in cmaps
     264        True
     265        sage: p.right_tableau in cmaps
     266        True
     267        sage: p.complement in cmaps
     268        True
     269    """
     270    result = set()
     271    for method in dir(cls):
     272        entry = getattr(cls, method)
     273        if isinstance(entry, CombinatorialMap):
     274            result.add(entry)
     275    return list(result)
  • sage/combinat/dyck_word.py

    diff --git a/sage/combinat/dyck_word.py b/sage/combinat/dyck_word.py
    a b  
    4444#*****************************************************************************
    4545
    4646from combinat import CombinatorialClass, CombinatorialObject, catalan_number, InfiniteAbstractCombinatorialClass
     47from sage.combinat.combinatorial_map import combinatorial_map
    4748from backtrack import GenericBacktracker
    4849
    4950from sage.structure.parent import Parent
     
    13081309                rise_comp.append(i)
    13091310        return Composition(rise_comp)
    13101311
     1312    @combinatorial_map(name='to two-row standard tableau')
    13111313    def to_standard_tableau(self):
    13121314        r"""
    13131315        Returns a standard tableau of shape `(a,b)` where
  • sage/combinat/permutation.py

    diff --git a/sage/combinat/permutation.py b/sage/combinat/permutation.py
    a b  
    216216from necklace import Necklaces
    217217from sage.misc.misc import uniq
    218218from backtrack import GenericBacktracker
     219from sage.combinat.combinatorial_map import combinatorial_map
    219220
    220221permutation_options = {'display':'list', 'mult':'l2r'}
    221222
     
    15181519        r"""
    15191520        Returns the Coxeter length of a permutation p. The length is given by
    15201521        the number of inversions of p.
    1521        
     1522
    15221523        EXAMPLES::
    1523        
     1524
    15241525            sage: Permutation([5, 1, 3, 4, 2]).length()
    15251526            6
    15261527        """
    15271528        return self.number_of_inversions()
    15281529
     1530    @combinatorial_map(order=2,name='inverse')
    15291531    def inverse(self):
    15301532        r"""
    15311533        Returns the inverse of a permutation
    1532        
     1534
    15331535        EXAMPLES::
    1534        
     1536
    15351537            sage: Permutation([3,8,5,10,9,4,6,1,7,2]).inverse()
    15361538            [8, 10, 1, 6, 3, 7, 9, 2, 5, 4]
    15371539            sage: Permutation([2, 4, 1, 5, 3]).inverse()
     
    21342136        """
    21352137        return len(self.idescents(final_descent))
    21362138
    2137 
     2139    @combinatorial_map(name='descent composition')
    21382140    def descents_composition(self):
    21392141        """
    21402142        Returns the composition corresponding to the descents of the
    21412143        permutation.
    2142        
     2144
    21432145        EXAMPLES::
    2144        
     2146
    21452147            sage: Permutation([1,3,2,4]).descents_composition()
    21462148            [2, 2]
    21472149        """
     
    27852787
    27862788        return __builtin__.list(itertools.ifilter(lambda pos: to_standard(map(lambda z: p[z], pos)) == patt, iter(subword.Subwords(range(len(p)), len(patt))) ))
    27872789
    2788 
     2790    @combinatorial_map(order=2,name='reverse')
    27892791    def reverse(self):
    27902792        """
    27912793        Returns the permutation obtained by reversing the list.
    2792        
     2794
    27932795        EXAMPLES::
    2794        
     2796
    27952797            sage: Permutation([3,4,1,2]).reverse()
    27962798            [2, 1, 4, 3]
    27972799            sage: Permutation([1,2,3,4,5]).reverse()
     
    27992801        """
    28002802        return Permutation_class( [i for i in reversed(self)] )
    28012803
    2802 
     2804    @combinatorial_map(order=2,name='complement')
    28032805    def complement(self):
    28042806        """
    28052807        Returns the complement of the permutation which is obtained by
    28062808        replacing each value x in the list with n - x + 1.
    2807        
     2809
    28082810        EXAMPLES::
    2809        
     2811
    28102812            sage: Permutation([1,2,3]).complement()
    28112813            [3, 2, 1]
    28122814            sage: Permutation([1, 3, 2]).complement()
     
    29182920
    29192921        return [tableau.Tableau(p),tableau.Tableau(q)]
    29202922
     2923    @combinatorial_map(name='Robinson-Schensted insertion tableau')
    29212924    def left_tableau(self):
    29222925        """
    29232926        Returns the right standard tableau after performing the RSK
    29242927        algorithm on self.
    2925        
     2928
    29262929        EXAMPLES::
    2927        
     2930
    29282931            sage: Permutation([1,4,3,2]).left_tableau()
    29292932            [[1, 2], [3], [4]]
    29302933        """
    29312934        return self.robinson_schensted()[0]
    29322935
     2936    @combinatorial_map(name='Robinson-Schensted recording tableau')
    29332937    def right_tableau(self):
    29342938        """
    29352939        Returns the right standard tableau after performing the RSK
    29362940        algorithm on self.
    2937        
     2941
    29382942        EXAMPLES::
    2939        
     2943
    29402944            sage: Permutation([1,4,3,2]).right_tableau()
    29412945            [[1, 2], [3], [4]]
    29422946        """
    29432947        return self.robinson_schensted()[1]
    29442948
     2949    @combinatorial_map(name='Robinson-Schensted tableau shape')
     2950    def RS_partition(self):
     2951        """
     2952        Returns the partition corresponding to the tableaux of the RSK algorithm.
     2953
     2954        EXAMPLES::
     2955
     2956            sage: Permutation([1,4,3,2]).RS_partition()
     2957            [2, 1, 1]
     2958        """
     2959        return self.robinson_schensted()[1].shape()
     2960
    29452961    def remove_extra_fixed_points(self):
    29462962        """
    29472963        Returns the permutation obtained by removing any fixed points at
  • sage/combinat/tableau.py

    diff --git a/sage/combinat/tableau.py b/sage/combinat/tableau.py
    a b  
    8585from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
    8686from sage.categories.sets_cat import Sets
    8787import __builtin__
     88from sage.combinat.combinatorial_map import combinatorial_map
    8889
    8990class Tableau(CombinatorialObject, Element):
    9091    """
     
    363364        """
    364365        return [self]
    365366
     367    @combinatorial_map(name='shape')
    366368    def shape(self):
    367369        r"""
    368370        Returns the shape of a tableau t.
     
    401403        return self.shape().corners()
    402404
    403405
     406    @combinatorial_map(order=2,name='conjugate')
    404407    def conjugate(self):
    405408        """
    406409        Returns the conjugate of the tableau t.
     
    603606        p = self.shape()
    604607        return len(self.inversions()) - sum([ p.arm_length(*cell) for cell in self.descents() ])
    605608
     609    @combinatorial_map(order=2,name='Schuetzenberger involution')
    606610    def schuetzenberger_involution(self, n = None):
    607611        """
    608612        Returns the Schuetzenberger involution of the tableau self.
     
    647651            t = t.bump(wi[k])
    648652        return t
    649653
     654    @combinatorial_map(name ='reading word permutation')
     655    def reading_word_permutation(self):
     656        """
     657        Returns a permutation with the entries of ``self`` obtained by reading
     658        ``self`` in the given reading order.
     659
     660        EXAMPLES::
     661
     662            sage: StandardTableau([[1,2],[3,4]]).reading_word_permutation()
     663            [3, 4, 1, 2]
     664        """
     665        return permutation.Permutation(self.to_word())
     666
    650667    def entries(self):
    651668        """
    652669        Returns a list of all entries of self, in the order obtained