Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/combinat/combinatorial_map.py
8815 views
1
"""
2
Combinatorial 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
11
def 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
106
class 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
return "Combinatorial map: %s" %self.name()
156
157
def _sage_src_lines_(self):
158
"""
159
Returns the source code location for the wrapped function.
160
161
EXAMPLES::
162
163
sage: p = Permutation([1,3,2,4])
164
sage: cm = p.left_tableau; cm
165
Combinatorial map: Robinson-Schensted insertion tableau
166
sage: (src, lines) = cm._sage_src_lines_()
167
sage: src[0]
168
" @combinatorial_map(name='Robinson-Schensted insertion tableau')\n"
169
sage: lines # random
170
2653
171
"""
172
from sage.misc.sageinspect import sage_getsourcelines
173
return sage_getsourcelines(self._f)
174
175
def __get__(self, inst, cls=None):
176
"""
177
Bounds the method of self to the given instance.
178
179
EXAMPLES::
180
181
sage: p = Permutation([1,3,2,4])
182
sage: p.left_tableau #indirect doctest
183
Combinatorial map: Robinson-Schensted insertion tableau
184
"""
185
self._inst = inst
186
return self
187
188
def __call__(self, *args, **kwds):
189
"""
190
Calls the combinatorial map.
191
192
EXAMPLES::
193
194
sage: p = Permutation([1,3,2,4])
195
sage: cm = type(p).left_tableau; cm
196
Combinatorial map: Robinson-Schensted insertion tableau
197
sage: cm(p)
198
[[1, 2, 4], [3]]
199
sage: cm(Permutation([4,3,2,1]))
200
[[1], [2], [3], [4]]
201
"""
202
if self._inst is not None:
203
return self._f(self._inst, *args, **kwds)
204
else:
205
return self._f(*args, **kwds)
206
207
def unbounded_map(self):
208
r"""
209
Return the unbounded version of ``self``.
210
211
You can use this method to return a function which takes as input
212
an element in the domain of the combinatorial map.
213
See the example below.
214
215
EXAMPLES::
216
217
sage: from sage.combinat.permutation import Permutation
218
sage: pi = Permutation([1,3,2])
219
sage: f = pi.reverse
220
sage: F = f.unbounded_map()
221
sage: F(pi)
222
[2, 3, 1]
223
"""
224
return self._f
225
226
def order(self):
227
"""
228
Returns the order of ``self``, or ``None`` if the order is not known.
229
230
EXAMPLES::
231
232
sage: from sage.combinat.combinatorial_map import combinatorial_map
233
sage: class CombinatorialClass:
234
... @combinatorial_map(order=2)
235
... def to_self_1(): pass
236
... @combinatorial_map()
237
... def to_self_2(): pass
238
sage: CombinatorialClass.to_self_1.order()
239
2
240
sage: CombinatorialClass.to_self_2.order() is None
241
True
242
"""
243
return self._order
244
245
def name(self):
246
"""
247
Returns the name of a combinatorial map.
248
This is used for the string representation of ``self``.
249
250
EXAMPLES::
251
252
sage: from sage.combinat.combinatorial_map import combinatorial_map
253
sage: class CombinatorialClass:
254
... @combinatorial_map(name='map1')
255
... def to_self_1(): pass
256
... @combinatorial_map()
257
... def to_self_2(): pass
258
sage: CombinatorialClass.to_self_1.name()
259
'map1'
260
sage: CombinatorialClass.to_self_2.name()
261
'to_self_2'
262
"""
263
if self._name is not None:
264
return self._name
265
else:
266
return self._f.__name__
267
268
def combinatorial_maps_in_class(cls):
269
"""
270
Returns the combinatorial maps of the class as a list of combinatorial maps.
271
272
EXAMPLES::
273
274
sage: from sage.combinat.combinatorial_map import combinatorial_maps_in_class
275
sage: p = Permutation([1,3,2,4])
276
sage: cmaps = combinatorial_maps_in_class(p)
277
sage: cmaps # random
278
[Combinatorial map: Robinson-Schensted insertion tableau,
279
Combinatorial map: Robinson-Schensted recording tableau,
280
Combinatorial map: Robinson-Schensted tableau shape,
281
Combinatorial map: complement,
282
Combinatorial map: descent composition,
283
Combinatorial map: inverse, ...]
284
sage: p.left_tableau in cmaps
285
True
286
sage: p.right_tableau in cmaps
287
True
288
sage: p.complement in cmaps
289
True
290
"""
291
result = set()
292
for method in dir(cls):
293
entry = getattr(cls, method)
294
if isinstance(entry, CombinatorialMap):
295
result.add(entry)
296
return list(result)
297
298