Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/combinat/descent_algebra.py
8817 views
1
"""
2
Descent Algebras
3
4
AUTHORS:
5
6
- Travis Scrimshaw (2013-07-28): Initial version
7
"""
8
#*****************************************************************************
9
# Copyright (C) 2013 Travis Scrimshaw <tscrim at ucdavis.edu>
10
#
11
# Distributed under the terms of the GNU General Public License (GPL)
12
# http://www.gnu.org/licenses/
13
#*****************************************************************************
14
15
from sage.misc.cachefunc import cached_method
16
from sage.misc.bindable_class import BindableClass
17
from sage.misc.lazy_attribute import lazy_attribute
18
from sage.misc.misc import subsets
19
from sage.structure.parent import Parent
20
from sage.structure.unique_representation import UniqueRepresentation
21
from sage.categories.algebras import Algebras
22
from sage.categories.realizations import Realizations, Category_realization_of_parent
23
from sage.categories.all import FiniteDimensionalAlgebrasWithBasis
24
from sage.rings.all import ZZ, QQ
25
from sage.functions.other import factorial
26
from sage.combinat.free_module import CombinatorialFreeModule
27
from sage.combinat.permutation import Permutations
28
from sage.combinat.composition import Compositions
29
from sage.combinat.integer_matrices import IntegerMatrices
30
from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra
31
from sage.combinat.ncsf_qsym.ncsf import NonCommutativeSymmetricFunctions
32
33
class DescentAlgebra(Parent, UniqueRepresentation):
34
r"""
35
Solomon's descent algebra.
36
37
The descent algebra `\Sigma_n` over a ring `R` is a subalgebra of the
38
symmetric group algebra `R S_n`.
39
40
There are three bases currently implemented for `\Sigma_n`:
41
42
- the standard basis `D_S` of (sums of) descent classes, indexed by
43
subsets `S` of `\{1, 2, \ldots, n-1\}`,
44
- the subset basis `B_p`, indexed by compositions `p` of `n`,
45
- the idempotent basis `I_p`, indexed by compositions `p` of `n`,
46
which is used to construct the mutually orthogonal idempotents
47
of the symmetric group algebra.
48
49
We follow the notations and conventions in [GR1989]_. In order to use
50
the idempotent basis, we require `R` to be a `\QQ`-algebra.
51
52
INPUT:
53
54
- ``R`` -- the base ring
55
56
- ``n`` -- a nonnegative integer
57
58
REFERENCES:
59
60
.. [GR1989] C. Reutenauer, A. M. Garsia. *A decomposition of Solomon's
61
descent algebra.* Adv. Math. **77** (1989).
62
http://www.lacim.uqam.ca/~christo/Publi%C3%A9s/1989/Decomposition%20Solomon.pdf
63
64
.. [Atkinson] M. D. Atkinson. *Solomon's descent algebra revisited.*
65
Bull. London Math. Soc. 24 (1992) 545-551.
66
http://www.cs.otago.ac.nz/staffpriv/mike/Papers/Descent/DescAlgRevisited.pdf
67
68
.. [MR-Desc] C. Malvenuto, C. Reutenauer, *Duality between
69
quasi-symmetric functions and the Solomon descent algebra*,
70
Journal of Algebra 177 (1995), no. 3, 967-982.
71
http://www.lacim.uqam.ca/~christo/Publi%C3%A9s/1995/Duality.pdf
72
73
EXAMPLES::
74
75
sage: DA = DescentAlgebra(QQ, 4)
76
sage: D = DA.D(); D
77
Descent algebra of 4 over Rational Field in the standard basis
78
sage: B = DA.B(); B
79
Descent algebra of 4 over Rational Field in the subset basis
80
sage: I = DA.I(); I
81
Descent algebra of 4 over Rational Field in the idempotent basis
82
sage: basis_B = B.basis()
83
sage: elt = basis_B[Composition([1,2,1])] + 4*basis_B[Composition([1,3])]; elt
84
B[1, 2, 1] + 4*B[1, 3]
85
sage: D(elt)
86
5*D{} + 5*D{1} + D{1, 3} + D{3}
87
sage: I(elt)
88
7/6*I[1, 1, 1, 1] + 2*I[1, 1, 2] + 3*I[1, 2, 1] + 4*I[1, 3]
89
90
There is the following syntatic sugar for calling elements of a basis, note
91
that for the empty set one must use ``D[[]]`` due to python's syntax::
92
93
sage: D[[]] + D[2] + 2*D[1,2]
94
D{} + 2*D{1, 2} + D{2}
95
sage: I[1,2,1] + 3*I[4] + 2*I[3,1]
96
I[1, 2, 1] + 2*I[3, 1] + 3*I[4]
97
98
TESTS:
99
100
We check that we can go back and forth between our bases::
101
102
sage: DA = DescentAlgebra(QQ, 4)
103
sage: D = DA.D()
104
sage: B = DA.B()
105
sage: I = DA.I()
106
sage: all(D(B(b)) == b for b in D.basis())
107
True
108
sage: all(D(I(b)) == b for b in D.basis())
109
True
110
sage: all(B(D(b)) == b for b in B.basis())
111
True
112
sage: all(B(I(b)) == b for b in B.basis())
113
True
114
sage: all(I(D(b)) == b for b in I.basis())
115
True
116
sage: all(I(B(b)) == b for b in I.basis())
117
True
118
"""
119
def __init__(self, R, n):
120
r"""
121
EXAMPLES::
122
123
sage: TestSuite(DescentAlgebra(QQ, 4)).run()
124
"""
125
self._n = n
126
self._category = FiniteDimensionalAlgebrasWithBasis(R)
127
Parent.__init__(self, base=R, category=self._category.WithRealizations())
128
129
def _repr_(self):
130
r"""
131
Return a string representation of ``self``.
132
133
EXAMPLES::
134
135
sage: DescentAlgebra(QQ, 4)
136
Descent algebra of 4 over Rational Field
137
"""
138
return "Descent algebra of {0} over {1}".format(self._n, self.base_ring())
139
140
def a_realization(self):
141
r"""
142
Return a particular realization of ``self`` (the `B`-basis).
143
144
EXAMPLES::
145
146
sage: DA = DescentAlgebra(QQ, 4)
147
sage: DA.a_realization()
148
Descent algebra of 4 over Rational Field in the subset basis
149
"""
150
return self.B()
151
152
class D(CombinatorialFreeModule, BindableClass):
153
r"""
154
The standard basis of a descent algebra.
155
156
This basis is indexed by `S \subseteq \{1, 2, \ldots, n-1\}`,
157
and the basis vector indexed by `S` is the sum of all permutations,
158
taken in the symmetric group algebra `R S_n`, whose descent set is `S`.
159
160
EXAMPLES::
161
162
sage: DA = DescentAlgebra(QQ, 4)
163
sage: D = DA.D()
164
sage: list(D.basis())
165
[D{}, D{1}, D{2}, D{1, 2}, D{3}, D{1, 3}, D{2, 3}, D{1, 2, 3}]
166
167
sage: DA = DescentAlgebra(QQ, 0)
168
sage: D = DA.D()
169
sage: list(D.basis())
170
[D{}]
171
"""
172
def __init__(self, alg, prefix="D"):
173
r"""
174
Initialize ``self``.
175
176
EXAMPLES::
177
178
sage: TestSuite(DescentAlgebra(QQ, 4).D()).run()
179
"""
180
self._prefix = prefix
181
self._basis_name = "standard"
182
p_set = subsets(range(1, alg._n))
183
CombinatorialFreeModule.__init__(self, alg.base_ring(),
184
map(tuple, p_set),
185
category=DescentAlgebraBases(alg),
186
bracket="", prefix=prefix)
187
188
# Change of basis:
189
B = alg.B()
190
self.module_morphism(self.to_B_basis,
191
codomain=B, category=self.category()
192
).register_as_coercion()
193
194
B.module_morphism(B.to_D_basis,
195
codomain=self, category=self.category()
196
).register_as_coercion()
197
198
# Coercion to symmetric group algebra
199
SGA = SymmetricGroupAlgebra(alg.base_ring(), alg._n)
200
self.module_morphism(self.to_symmetric_group_algebra_on_basis,
201
codomain=SGA, category=Algebras(alg.base_ring())
202
).register_as_coercion()
203
204
def _element_constructor_(self, x):
205
"""
206
Construct an element of ``self``.
207
208
EXAMPLES::
209
210
sage: D = DescentAlgebra(QQ, 4).D()
211
sage: D([1, 3])
212
D{1, 3}
213
"""
214
if isinstance(x, (list, set)):
215
x = tuple(x)
216
if isinstance(x, tuple):
217
return self.monomial(x)
218
return CombinatorialFreeModule._element_constructor_(self, x)
219
220
# We need to overwrite this since our basis elements must be indexed by tuples
221
def _repr_term(self, S):
222
r"""
223
EXAMPLES::
224
225
sage: DA = DescentAlgebra(QQ, 4)
226
sage: DA.D()._repr_term((1, 3))
227
'D{1, 3}'
228
"""
229
return self._prefix + '{' + repr(list(S))[1:-1] + '}'
230
231
def product_on_basis(self, S, T):
232
r"""
233
Return `D_S D_T`, where `S` and `T` are subsets of `[n-1]`.
234
235
EXAMPLES::
236
237
sage: DA = DescentAlgebra(QQ, 4)
238
sage: D = DA.D()
239
sage: D.product_on_basis((1, 3), (2,))
240
D{} + D{1} + D{1, 2} + 2*D{1, 2, 3} + D{1, 3} + D{2} + D{2, 3} + D{3}
241
"""
242
return self(self.to_B_basis(S)*self.to_B_basis(T))
243
244
@cached_method
245
def one_basis(self):
246
r"""
247
Return the identity element, as per
248
``AlgebrasWithBasis.ParentMethods.one_basis``.
249
250
EXAMPLES::
251
252
sage: DescentAlgebra(QQ, 4).D().one_basis()
253
()
254
sage: DescentAlgebra(QQ, 0).D().one_basis()
255
()
256
257
sage: all( U * DescentAlgebra(QQ, 3).D().one() == U
258
....: for U in DescentAlgebra(QQ, 3).D().basis() )
259
True
260
"""
261
return tuple([])
262
263
@cached_method
264
def to_B_basis(self, S):
265
r"""
266
Return `D_S` as a linear combination of `B_p`-basis elements.
267
268
EXAMPLES::
269
270
sage: DA = DescentAlgebra(QQ, 4)
271
sage: D = DA.D()
272
sage: B = DA.B()
273
sage: for b in D.basis(): B(b) # indirect doctest
274
B[4]
275
B[1, 3] - B[4]
276
B[2, 2] - B[4]
277
B[1, 1, 2] - B[1, 3] - B[2, 2] + B[4]
278
B[3, 1] - B[4]
279
B[1, 2, 1] - B[1, 3] - B[3, 1] + B[4]
280
B[2, 1, 1] - B[2, 2] - B[3, 1] + B[4]
281
B[1, 1, 1, 1] - B[1, 1, 2] - B[1, 2, 1] + B[1, 3] - B[2, 1, 1] + B[2, 2] + B[3, 1] - B[4]
282
"""
283
B = self.realization_of().B()
284
285
if len(S) == 0:
286
return B.one()
287
288
n = self.realization_of()._n
289
C = Compositions(n)
290
return B.sum_of_terms([(C.from_subset(T, n), (-1)**(len(S)-len(T))) for T in subsets(S)])
291
292
def to_symmetric_group_algebra_on_basis(self, S):
293
"""
294
Return `D_S` as a linear combination of basis elements in the
295
symmetric group algebra.
296
297
EXAMPLES::
298
299
sage: D = DescentAlgebra(QQ, 4).D()
300
sage: for b in Subsets(3): D.to_symmetric_group_algebra_on_basis(tuple(b))
301
[1, 2, 3, 4]
302
[2, 1, 3, 4] + [3, 1, 2, 4] + [4, 1, 2, 3]
303
[1, 3, 2, 4] + [1, 4, 2, 3] + [2, 3, 1, 4] + [2, 4, 1, 3] + [3, 4, 1, 2]
304
[1, 2, 4, 3] + [1, 3, 4, 2] + [2, 3, 4, 1]
305
[3, 2, 1, 4] + [4, 2, 1, 3] + [4, 3, 1, 2]
306
[2, 1, 4, 3] + [3, 1, 4, 2] + [3, 2, 4, 1] + [4, 1, 3, 2] + [4, 2, 3, 1]
307
[1, 4, 3, 2] + [2, 4, 3, 1] + [3, 4, 2, 1]
308
[4, 3, 2, 1]
309
"""
310
n = self.realization_of()._n
311
SGA = SymmetricGroupAlgebra(self.base_ring(), n)
312
# Need to convert S to a list of positions by -1 for indexing
313
P = Permutations(descents=([x-1 for x in S], n))
314
return SGA.sum_of_terms([(p, 1) for p in P])
315
316
def __getitem__(self, S):
317
"""
318
Return the basis element indexed by ``S``.
319
320
INPUT:
321
322
- ``S`` -- a subset of `[n-1]`
323
324
EXAMPLES::
325
326
sage: D = DescentAlgebra(QQ, 4).D()
327
sage: D[3]
328
D{3}
329
sage: D[1, 3]
330
D{1, 3}
331
sage: D[[]]
332
D{}
333
334
TESTS::
335
336
sage: D = DescentAlgebra(QQ, 0).D()
337
sage: D[[]]
338
D{}
339
"""
340
n = self.realization_of()._n
341
if S in ZZ:
342
if S >= n or S <= 0:
343
raise ValueError("({0},) is not a subset of {{1, ..., {1}}}".format(S, n-1))
344
return self.monomial((S,))
345
if len(S) == 0:
346
return self.one()
347
S = tuple(sorted(S))
348
if S[-1] >= n or S[0] <= 0:
349
raise ValueError("{0} is not a subset of {{1, ..., {1}}}".format(S, n-1))
350
return self.monomial(S)
351
352
standard = D
353
354
class B(CombinatorialFreeModule, BindableClass):
355
r"""
356
The subset basis of a descent algebra (indexed by compositions).
357
358
The subset basis `(B_S)_{S \subseteq \{1, 2, \ldots, n-1\}}` of
359
`\Sigma_n` is formed by
360
361
.. MATH::
362
363
B_S = \sum_{T \subseteq S} D_T,
364
365
where `(D_S)_{S \subseteq \{1, 2, \ldots, n-1\}}` is the
366
:class:`standard basis <DescentAlgebra.D>`. However it is more
367
natural to index the subset basis by compositions
368
of `n` under the bijection `\{i_1, i_2, \ldots, i_k\} \mapsto
369
(i_1, i_2 - i_1, i_3 - i_2, \ldots, i_k - i_{k-1}, n - i_k)`,
370
which is what Sage uses to index the basis.
371
372
By using compositions of `n`, the product `B_p B_q` becomes a
373
sum over the non-negative-integer matrices `M` with column sum `p`
374
and row sum `q`. The summand corresponding to `M` is `B_c`, where `c`
375
is the composition obtained by reading `M` row-by-row from
376
left-to-right and top-to-bottom and removing all zeroes. This
377
multiplication rule is commonly called "Solomon's Mackey formula".
378
379
EXAMPLES::
380
381
sage: DA = DescentAlgebra(QQ, 4)
382
sage: B = DA.B()
383
sage: list(B.basis())
384
[B[1, 1, 1, 1], B[1, 1, 2], B[1, 2, 1], B[1, 3], B[2, 1, 1], B[2, 2], B[3, 1], B[4]]
385
"""
386
def __init__(self, alg, prefix="B"):
387
r"""
388
Initialize ``self``.
389
390
EXAMPLES::
391
392
sage: TestSuite(DescentAlgebra(QQ, 4).B()).run()
393
"""
394
self._prefix = prefix
395
self._basis_name = "subset"
396
CombinatorialFreeModule.__init__(self, alg.base_ring(),
397
Compositions(alg._n),
398
category=DescentAlgebraBases(alg),
399
bracket="", prefix=prefix)
400
401
S = NonCommutativeSymmetricFunctions(alg.base_ring()).Complete()
402
self.module_morphism(self.to_nsym,
403
codomain=S, category=Algebras(alg.base_ring())
404
).register_as_coercion()
405
406
def product_on_basis(self, p, q):
407
r"""
408
Return `B_p B_q`, where `p` and `q` are compositions of `n`.
409
410
EXAMPLES::
411
412
sage: DA = DescentAlgebra(QQ, 4)
413
sage: B = DA.B()
414
sage: p = Composition([1,2,1])
415
sage: q = Composition([3,1])
416
sage: B.product_on_basis(p, q)
417
B[1, 1, 1, 1] + 2*B[1, 2, 1]
418
"""
419
IM = IntegerMatrices(list(p), list(q))
420
P = Compositions(self.realization_of()._n)
421
to_composition = lambda m: P( filter(lambda x: x != 0, m.list()) )
422
return self.sum_of_monomials(map(to_composition, IM))
423
424
@cached_method
425
def one_basis(self):
426
r"""
427
Return the identity element which is the composition `[n]`, as per
428
``AlgebrasWithBasis.ParentMethods.one_basis``.
429
430
EXAMPLES::
431
432
sage: DescentAlgebra(QQ, 4).B().one_basis()
433
[4]
434
sage: DescentAlgebra(QQ, 0).B().one_basis()
435
[]
436
437
sage: all( U * DescentAlgebra(QQ, 3).B().one() == U
438
....: for U in DescentAlgebra(QQ, 3).B().basis() )
439
True
440
"""
441
n = self.realization_of()._n
442
P = Compositions(n)
443
if n == 0:
444
return P([])
445
return P([n])
446
447
@cached_method
448
def to_I_basis(self, p):
449
r"""
450
Return `B_p` as a linear combination of `I`-basis elements.
451
452
This is done using the formula
453
454
.. MATH::
455
456
B_p = \sum_{q \leq p} \frac{1}{\mathbf{k}!(q,p)} I_q,
457
458
where `\leq` is the refinement order and `\mathbf{k}!(q,p)` is
459
defined as follows: When `q \leq p`, we can write `q` as a
460
concatenation `q_{(1)} q_{(2)} \cdots q_{(k)}` with each `q_{(i)}`
461
being a composition of the `i`-th entry of `p`, and then
462
we set `\mathbf{k}!(q,p)` to be
463
`l(q_{(1)})! l(q_{(2)})! \cdots l(q_{(k)})!`, where `l(r)`
464
denotes the number of parts of any composition `r`.
465
466
EXAMPLES::
467
468
sage: DA = DescentAlgebra(QQ, 4)
469
sage: B = DA.B()
470
sage: I = DA.I()
471
sage: for b in B.basis(): I(b) # indirect doctest
472
I[1, 1, 1, 1]
473
1/2*I[1, 1, 1, 1] + I[1, 1, 2]
474
1/2*I[1, 1, 1, 1] + I[1, 2, 1]
475
1/6*I[1, 1, 1, 1] + 1/2*I[1, 1, 2] + 1/2*I[1, 2, 1] + I[1, 3]
476
1/2*I[1, 1, 1, 1] + I[2, 1, 1]
477
1/4*I[1, 1, 1, 1] + 1/2*I[1, 1, 2] + 1/2*I[2, 1, 1] + I[2, 2]
478
1/6*I[1, 1, 1, 1] + 1/2*I[1, 2, 1] + 1/2*I[2, 1, 1] + I[3, 1]
479
1/24*I[1, 1, 1, 1] + 1/6*I[1, 1, 2] + 1/6*I[1, 2, 1] + 1/2*I[1, 3] + 1/6*I[2, 1, 1] + 1/2*I[2, 2] + 1/2*I[3, 1] + I[4]
480
"""
481
I = self.realization_of().I()
482
483
def coeff(p, q):
484
ret = QQ.one()
485
last = 0
486
for val in p:
487
count = 0
488
s = 0
489
while s != val:
490
s += q[last+count]
491
count += 1
492
ret /= factorial(count)
493
last += count
494
return ret
495
496
return I.sum_of_terms([(q, coeff(p, q)) for q in p.finer()])
497
498
@cached_method
499
def to_D_basis(self, p):
500
r"""
501
Return `B_p` as a linear combination of `D`-basis elements.
502
503
EXAMPLES::
504
505
sage: DA = DescentAlgebra(QQ, 4)
506
sage: B = DA.B()
507
sage: D = DA.D()
508
sage: for b in B.basis(): D(b) # indirect doctest
509
D{} + D{1} + D{1, 2} + D{1, 2, 3} + D{1, 3} + D{2} + D{2, 3} + D{3}
510
D{} + D{1} + D{1, 2} + D{2}
511
D{} + D{1} + D{1, 3} + D{3}
512
D{} + D{1}
513
D{} + D{2} + D{2, 3} + D{3}
514
D{} + D{2}
515
D{} + D{3}
516
D{}
517
518
TESTS:
519
520
Check to make sure the empty case is handled correctly::
521
522
sage: DA = DescentAlgebra(QQ, 0)
523
sage: B = DA.B()
524
sage: D = DA.D()
525
sage: for b in B.basis(): D(b)
526
D{}
527
"""
528
D = self.realization_of().D()
529
530
if p == []:
531
return D.one()
532
533
return D.sum_of_terms([(tuple(sorted(s)), 1) for s in p.to_subset().subsets()])
534
535
def to_nsym(self, p):
536
"""
537
Return `B_p` as an element in `NSym`, the non-commutative
538
symmetric functions.
539
540
This maps `B_p` to `S_p` where `S` denotes the Complete basis of
541
`NSym`.
542
543
EXAMPLES::
544
545
sage: B = DescentAlgebra(QQ, 4).B()
546
sage: S = NonCommutativeSymmetricFunctions(QQ).Complete()
547
sage: for b in B.basis(): S(b) # indirect doctest
548
S[1, 1, 1, 1]
549
S[1, 1, 2]
550
S[1, 2, 1]
551
S[1, 3]
552
S[2, 1, 1]
553
S[2, 2]
554
S[3, 1]
555
S[4]
556
"""
557
S = NonCommutativeSymmetricFunctions(self.base_ring()).Complete()
558
return S.monomial(p)
559
560
subset = B
561
562
class I(CombinatorialFreeModule, BindableClass):
563
r"""
564
The idempotent basis of a descent algebra.
565
566
The idempotent basis `(I_p)_{p \models n}` is a basis for `\Sigma_n`.
567
Let `\lambda(p)` denote the partition obtained from a composition
568
`p` by sorting. This basis is called the idempotent basis since for
569
any `q` such that `\lambda(p) = \lambda(q)`, we have:
570
571
.. MATH::
572
573
I_p I_q = s(\lambda) I_q
574
575
where `\lambda` denotes `\lambda(p) = \lambda(q)`, and where
576
`s(\lambda)` is the stabilizer of `\lambda` in `S_n`.
577
578
It is also straightforward to compute the idempotents `E_{\lambda}`
579
for the symmetric group algebra by the formula
580
(Theorem 3.2 in [GR1989]_):
581
582
.. MATH::
583
584
E_{\lambda} = \frac{1}{k!} \sum_{\lambda(p) = \lambda} I_p.
585
586
.. NOTE::
587
588
The basis elements are not orthogonal idempotents.
589
590
EXAMPLES::
591
592
sage: DA = DescentAlgebra(QQ, 4)
593
sage: I = DA.I()
594
sage: list(I.basis())
595
[I[1, 1, 1, 1], I[1, 1, 2], I[1, 2, 1], I[1, 3], I[2, 1, 1], I[2, 2], I[3, 1], I[4]]
596
"""
597
def __init__(self, alg, prefix="I"):
598
r"""
599
Initialize ``self``.
600
601
EXAMPLES::
602
603
sage: TestSuite(DescentAlgebra(QQ, 4).B()).run()
604
"""
605
self._prefix = prefix
606
self._basis_name = "idempotent"
607
CombinatorialFreeModule.__init__(self, alg.base_ring(),
608
Compositions(alg._n),
609
category=DescentAlgebraBases(alg),
610
bracket="", prefix=prefix)
611
612
## Change of basis:
613
B = alg.B()
614
self.module_morphism(self.to_B_basis,
615
codomain=B, category=self.category()
616
).register_as_coercion()
617
618
B.module_morphism(B.to_I_basis,
619
codomain=self, category=self.category()
620
).register_as_coercion()
621
622
def product_on_basis(self, p, q):
623
r"""
624
Return `I_p I_q`, where `p` and `q` are compositions of `n`.
625
626
EXAMPLES::
627
628
sage: DA = DescentAlgebra(QQ, 4)
629
sage: I = DA.I()
630
sage: p = Composition([1,2,1])
631
sage: q = Composition([3,1])
632
sage: I.product_on_basis(p, q)
633
0
634
sage: I.product_on_basis(p, p)
635
2*I[1, 2, 1]
636
"""
637
# These do not act as orthogonal idempotents, so we have to lift
638
# to the B basis to do the multiplication
639
# TODO: if the partitions of p and q match, return s*I_q where
640
# s is the size of the stabilizer of the partition of p
641
return self(self.to_B_basis(p)*self.to_B_basis(q))
642
643
@cached_method
644
def one(self):
645
r"""
646
Return the identity element, which is `B_{[n]}`, in the `I` basis.
647
648
EXAMPLES::
649
650
sage: DescentAlgebra(QQ, 4).I().one()
651
1/24*I[1, 1, 1, 1] + 1/6*I[1, 1, 2] + 1/6*I[1, 2, 1] + 1/2*I[1, 3] + 1/6*I[2, 1, 1] + 1/2*I[2, 2] + 1/2*I[3, 1] + I[4]
652
sage: DescentAlgebra(QQ, 0).I().one()
653
I[]
654
655
TESTS::
656
657
sage: all( U * DescentAlgebra(QQ, 3).I().one() == U
658
....: for U in DescentAlgebra(QQ, 3).I().basis() )
659
True
660
"""
661
B = self.realization_of().B()
662
return B.to_I_basis(B.one_basis())
663
664
def one_basis(self):
665
"""
666
The element `1` is not (generally) a basis vector in the `I`
667
basis, thus this returns a ``TypeError``.
668
669
EXAMPLES::
670
671
sage: DescentAlgebra(QQ, 4).I().one_basis()
672
Traceback (most recent call last):
673
...
674
TypeError: 1 is not a basis element in the I basis.
675
"""
676
raise TypeError("1 is not a basis element in the I basis.")
677
678
@cached_method
679
def to_B_basis(self, p):
680
r"""
681
Return `I_p` as a linear combination of `B`-basis elements.
682
683
This is computed using the formula (Theorem 3.4 in [GR1989]_)
684
685
.. MATH::
686
687
I_p = \sum_{q \leq p}
688
\frac{(-1)^{l(q)-l(p)}}{\mathbf{k}(q,p)} B_q,
689
690
where `\leq` is the refinement order and `l(r)` denotes the number
691
of parts of any composition `r`, and where `\mathbf{k}(q,p)` is
692
defined as follows: When `q \leq p`, we can write `q` as a
693
concatenation `q_{(1)} q_{(2)} \cdots q_{(k)}` with each `q_{(i)}`
694
being a composition of the `i`-th entry of `p`, and then
695
we set `\mathbf{k}(q,p)` to be
696
`l(q_{(1)}) l(q_{(2)}) \cdots l(q_{(k)})`.
697
698
EXAMPLES::
699
700
sage: DA = DescentAlgebra(QQ, 4)
701
sage: B = DA.B()
702
sage: I = DA.I()
703
sage: for b in I.basis(): B(b) # indirect doctest
704
B[1, 1, 1, 1]
705
-1/2*B[1, 1, 1, 1] + B[1, 1, 2]
706
-1/2*B[1, 1, 1, 1] + B[1, 2, 1]
707
1/3*B[1, 1, 1, 1] - 1/2*B[1, 1, 2] - 1/2*B[1, 2, 1] + B[1, 3]
708
-1/2*B[1, 1, 1, 1] + B[2, 1, 1]
709
1/4*B[1, 1, 1, 1] - 1/2*B[1, 1, 2] - 1/2*B[2, 1, 1] + B[2, 2]
710
1/3*B[1, 1, 1, 1] - 1/2*B[1, 2, 1] - 1/2*B[2, 1, 1] + B[3, 1]
711
-1/4*B[1, 1, 1, 1] + 1/3*B[1, 1, 2] + 1/3*B[1, 2, 1] - 1/2*B[1, 3] + 1/3*B[2, 1, 1] - 1/2*B[2, 2] - 1/2*B[3, 1] + B[4]
712
"""
713
B = self.realization_of().B()
714
715
def coeff(p, q):
716
ret = QQ.one()
717
last = 0
718
for val in p:
719
count = 0
720
s = 0
721
while s != val:
722
s += q[last+count]
723
count += 1
724
ret /= count
725
last += count
726
if (len(q) - len(p)) % 2 == 1:
727
ret = -ret
728
return ret
729
730
return B.sum_of_terms([(q, coeff(p, q)) for q in p.finer()])
731
732
def idempotent(self, la):
733
"""
734
Return the idemponent corresponding to the partition ``la``.
735
736
EXAMPLES::
737
738
sage: I = DescentAlgebra(QQ, 4).I()
739
sage: E = I.idempotent([3,1]); E
740
1/2*I[1, 3] + 1/2*I[3, 1]
741
sage: E*E == E
742
True
743
sage: E2 = I.idempotent([2,1,1]); E2
744
1/6*I[1, 1, 2] + 1/6*I[1, 2, 1] + 1/6*I[2, 1, 1]
745
sage: E2*E2 == E2
746
True
747
sage: E*E2 == I.zero()
748
True
749
"""
750
from sage.combinat.permutation import Permutations
751
k = len(la)
752
C = Compositions(self.realization_of()._n)
753
return self.sum_of_terms([(C(x), ~QQ(factorial(k))) for x in Permutations(la)])
754
755
idempotent = I
756
757
class DescentAlgebraBases(Category_realization_of_parent):
758
r"""
759
The category of bases of a descent algebra.
760
"""
761
def __init__(self, base):
762
r"""
763
Initialize the bases of a descent algebra.
764
765
INPUT:
766
767
- ``base`` -- a descent algebra
768
769
TESTS::
770
771
sage: from sage.combinat.descent_algebra import DescentAlgebraBases
772
sage: DA = DescentAlgebra(QQ, 4)
773
sage: bases = DescentAlgebraBases(DA)
774
sage: DA.B() in bases
775
True
776
"""
777
Category_realization_of_parent.__init__(self, base)
778
779
def _repr_(self):
780
r"""
781
Return the representation of ``self``.
782
783
EXAMPLES::
784
785
sage: from sage.combinat.descent_algebra import DescentAlgebraBases
786
sage: DA = DescentAlgebra(QQ, 4)
787
sage: DescentAlgebraBases(DA)
788
Category of bases of Descent algebra of 4 over Rational Field
789
"""
790
return "Category of bases of %s" % self.base()
791
792
def super_categories(self):
793
r"""
794
The super categories of ``self``.
795
796
EXAMPLES::
797
798
sage: from sage.combinat.descent_algebra import DescentAlgebraBases
799
sage: DA = DescentAlgebra(QQ, 4)
800
sage: bases = DescentAlgebraBases(DA)
801
sage: bases.super_categories()
802
[Category of finite dimensional algebras with basis over Rational Field,
803
Category of realizations of Descent algebra of 4 over Rational Field]
804
"""
805
return [self.base()._category, Realizations(self.base())]
806
807
class ParentMethods:
808
def _repr_(self):
809
"""
810
Text representation of this basis of a descent algebra.
811
812
EXAMPLES::
813
814
sage: DA = DescentAlgebra(QQ, 4)
815
sage: DA.B()
816
Descent algebra of 4 over Rational Field in the subset basis
817
sage: DA.D()
818
Descent algebra of 4 over Rational Field in the standard basis
819
sage: DA.I()
820
Descent algebra of 4 over Rational Field in the idempotent basis
821
"""
822
return "%s in the %s basis"%(self.realization_of(), self._basis_name)
823
824
def __getitem__(self, p):
825
"""
826
Return the basis element indexed by ``p``.
827
828
INPUT:
829
830
- ``p`` -- a composition
831
832
EXAMPLES::
833
834
sage: B = DescentAlgebra(QQ, 4).B()
835
sage: B[Composition([4])]
836
B[4]
837
sage: B[1,2,1]
838
B[1, 2, 1]
839
sage: B[4]
840
B[4]
841
sage: B[[3,1]]
842
B[3, 1]
843
"""
844
C = Compositions(self.realization_of()._n)
845
if p in C:
846
return self.monomial(C(p)) # Make sure it's a composition
847
if p == []:
848
return self.one()
849
850
if not isinstance(p, tuple):
851
p = [p]
852
return self.monomial(C(p))
853
854
def is_field(self, proof = True):
855
"""
856
Return whether this descent algebra is a field.
857
858
EXAMPLES::
859
860
sage: B = DescentAlgebra(QQ, 4).B()
861
sage: B.is_field()
862
False
863
sage: B = DescentAlgebra(QQ, 1).B()
864
sage: B.is_field()
865
True
866
"""
867
if self.realization_of()._n <= 1:
868
return self.base_ring().is_field()
869
return False
870
871
def is_commutative(self):
872
"""
873
Return whether this descent algebra is commutative.
874
875
EXAMPLES::
876
877
sage: B = DescentAlgebra(QQ, 4).B()
878
sage: B.is_commutative()
879
False
880
sage: B = DescentAlgebra(QQ, 1).B()
881
sage: B.is_commutative()
882
True
883
"""
884
return self.base_ring().is_commutative() \
885
and self.realization_of()._n <= 2
886
887
@lazy_attribute
888
def to_symmetric_group_algebra(self):
889
"""
890
Morphism from ``self`` to the symmetric group algebra.
891
892
EXAMPLES::
893
894
sage: D = DescentAlgebra(QQ, 4).D()
895
sage: D.to_symmetric_group_algebra(D[1,3])
896
[2, 1, 4, 3] + [3, 1, 4, 2] + [3, 2, 4, 1] + [4, 1, 3, 2] + [4, 2, 3, 1]
897
sage: B = DescentAlgebra(QQ, 4).B()
898
sage: B.to_symmetric_group_algebra(B[1,2,1])
899
[1, 2, 3, 4] + [1, 2, 4, 3] + [1, 3, 4, 2] + [2, 1, 3, 4]
900
+ [2, 1, 4, 3] + [2, 3, 4, 1] + [3, 1, 2, 4] + [3, 1, 4, 2]
901
+ [3, 2, 4, 1] + [4, 1, 2, 3] + [4, 1, 3, 2] + [4, 2, 3, 1]
902
"""
903
SGA = SymmetricGroupAlgebra(self.base_ring(), self.realization_of()._n)
904
return self.module_morphism(self.to_symmetric_group_algebra_on_basis, codomain=SGA)
905
906
def to_symmetric_group_algebra_on_basis(self, S):
907
"""
908
Return the basis element index by ``S`` as a linear combination
909
of basis elements in the symmetric group algebra.
910
911
EXAMPLES::
912
913
sage: B = DescentAlgebra(QQ, 3).B()
914
sage: for c in Compositions(3): B.to_symmetric_group_algebra_on_basis(c)
915
[1, 2, 3] + [1, 3, 2] + [2, 1, 3] + [2, 3, 1] + [3, 1, 2] + [3, 2, 1]
916
[1, 2, 3] + [2, 1, 3] + [3, 1, 2]
917
[1, 2, 3] + [1, 3, 2] + [2, 3, 1]
918
[1, 2, 3]
919
sage: I = DescentAlgebra(QQ, 3).I()
920
sage: for c in Compositions(3): I.to_symmetric_group_algebra_on_basis(c)
921
[1, 2, 3] + [1, 3, 2] + [2, 1, 3] + [2, 3, 1] + [3, 1, 2] + [3, 2, 1]
922
1/2*[1, 2, 3] - 1/2*[1, 3, 2] + 1/2*[2, 1, 3] - 1/2*[2, 3, 1] + 1/2*[3, 1, 2] - 1/2*[3, 2, 1]
923
1/2*[1, 2, 3] + 1/2*[1, 3, 2] - 1/2*[2, 1, 3] + 1/2*[2, 3, 1] - 1/2*[3, 1, 2] - 1/2*[3, 2, 1]
924
1/3*[1, 2, 3] - 1/6*[1, 3, 2] - 1/6*[2, 1, 3] - 1/6*[2, 3, 1] - 1/6*[3, 1, 2] + 1/3*[3, 2, 1]
925
"""
926
D = self.realization_of().D()
927
return D.to_symmetric_group_algebra(D(self[S]))
928
929
class ElementMethods:
930
def to_symmetric_group_algebra(self):
931
"""
932
Return ``self`` in the symmetric group algebra.
933
934
EXAMPLES::
935
936
sage: B = DescentAlgebra(QQ, 4).B()
937
sage: B[1,3].to_symmetric_group_algebra()
938
[1, 2, 3, 4] + [2, 1, 3, 4] + [3, 1, 2, 4] + [4, 1, 2, 3]
939
sage: I = DescentAlgebra(QQ, 4).I()
940
sage: elt = I(B[1,3])
941
sage: elt.to_symmetric_group_algebra()
942
[1, 2, 3, 4] + [2, 1, 3, 4] + [3, 1, 2, 4] + [4, 1, 2, 3]
943
"""
944
return self.parent().to_symmetric_group_algebra(self)
945
946
947