This repository has been archived by the owner on Jan 30, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
qsym.py
3411 lines (2772 loc) · 142 KB
/
qsym.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
r"""
Quasisymmetric functions
REFERENCES:
.. [Ges] I. Gessel, *Multipartite P-partitions and inner products of skew Schur
functions*, Contemp. Math. **34** (1984), 289-301.
http://people.brandeis.edu/~gessel/homepage/papers/multipartite.pdf
.. [MR] C. Malvenuto and C. Reutenauer, *Duality between quasi-symmetric
functions and the Solomon descent algebra*, J. Algebra **177** (1995),
no. 3, 967-982. http://www.mat.uniroma1.it/people/malvenuto/Duality.pdf
.. [GriRei2014] Darij Grinberg, Victor Reiner,
*Hopf algebras in combinatorics*,
30 September 2014. :arxiv:`1409.8356v1`.
.. [Mal1993] Claudia Malvenuto, *Produits et coproduits des fonctions
quasi-symetriques et de l'algebre des descentes*,
thesis, November 1993.
http://www1.mat.uniroma1.it/people/malvenuto/Thesis.pdf
.. [Haz2004] Michiel Hazewinkel, *Explicit polynomial generators for the
ring of quasisymmetric functions over the integers*.
:arxiv:`math/0410366v1`
.. [Rad1979] David E. Radford, *A natural ring basis for the shuffle algebra
and an application to group schemes*, J. Algebra **58** (1979), 432-454.
.. [NCSF1] Israel Gelfand, D. Krob, Alain Lascoux, B. Leclerc,
V. S. Retakh, J.-Y. Thibon,
*Noncommutative symmetric functions*.
:arxiv:`hep-th/9407124v1`
.. [NCSF2] D. Krob, B. Leclerc, J.-Y. Thibon,
*Noncommutative symmetric functions II: Transformations of alphabets*.
http://www-igm.univ-mlv.fr/~jyt/ARTICLES/NCSF2.ps
.. [LMvW13] Kurt Luoto, Stefan Mykytiuk and Stephanie van Willigenburg,
*An introduction to quasisymmetric Schur functions -- Hopf algebras,
quasisymmetric functions, and Young composition tableaux*,
May 23, 2013, Springer.
http://www.math.ubc.ca/%7Esteph/papers/QuasiSchurBook.pdf
.. [BBSSZ2012] Chris Berg, Nantel Bergeron, Franco Saliola,
Luis Serrano, Mike Zabrocki,
*A lift of the Schur and Hall-Littlewood bases to
non-commutative symmetric functions*,
:arxiv:`1208.5191v3`.
AUTHOR:
- Jason Bandlow
- Franco Saliola
- Chris Berg
- Darij Grinberg
"""
#*****************************************************************************
# Copyright (C) 2010 Jason Bandlow <jbandlow@gmail.com>,
# 2012 Franco Saliola <saliola@gmail.com>,
# 2012 Chris Berg <chrisjamesberg@gmail.com>
# Distributed under the terms of the GNU General Public License (GPL)
# http://www.gnu.org/licenses/
#*****************************************************************************
from sage.misc.bindable_class import BindableClass
from sage.categories.graded_hopf_algebras import GradedHopfAlgebras
from sage.categories.rings import Rings
from sage.categories.fields import Fields
from sage.categories.realizations import Category_realization_of_parent
from sage.structure.parent import Parent
from sage.structure.unique_representation import UniqueRepresentation
from sage.matrix.constructor import matrix
from sage.matrix.matrix_space import MatrixSpace
from sage.combinat.permutation import Permutations
from sage.combinat.composition import Composition, Compositions
from sage.combinat.composition_tableau import CompositionTableaux
from sage.combinat.partition import Partitions, _Partitions
from sage.combinat.free_module import CombinatorialFreeModule
from sage.combinat.sf.sf import SymmetricFunctions
from sage.combinat.ncsf_qsym.generic_basis_code import BasesOfQSymOrNCSF
from sage.combinat.ncsf_qsym.combinatorics import number_of_fCT, number_of_SSRCT, compositions_order
from sage.combinat.ncsf_qsym.ncsf import NonCommutativeSymmetricFunctions
from sage.combinat.words.word import Word
from sage.misc.cachefunc import cached_method
from sage.categories.morphism import SetMorphism
from sage.categories.homset import Hom
class QuasiSymmetricFunctions(UniqueRepresentation, Parent):
r"""
.. rubric:: The Hopf algebra of quasisymmetric functions.
Let `R` be a commutative ring with unity.
The `R`-algebra of quasi-symmetric functions may be realized as an
`R`-subalgebra of the ring of power series in countably many
variables `R[[x_1, x_2, x_3, \ldots]]`. It consists of those
formal power series `p` which are degree-bounded (i. e., the degrees
of all monomials occuring with nonzero coefficient in `p` are bounded
from above, although the bound can depend on `p`) and satisfy the
following condition: For every tuple `(a_1, a_2, \ldots, a_m)` of
positive integers, the coefficient of the monomial
`x_{i_1}^{a_1} x_{i_2}^{a_2} \cdots x_{i_m}^{a_m}` in `p` is the same
for all strictly increasing sequences `(i_1 < i_2 < \cdots < i_m)` of
positive integers. (In other words, the coefficient of a monomial in `p`
depends only on the sequence of nonzero exponents in the monomial. If
"sequence" were to be replaced by "multiset" here, we would obtain
the definition of a symmetric function.)
The `R`-algebra of quasi-symmetric functions is commonly called
`\mathrm{QSym}_R` or occasionally just `\mathrm{QSym}` (when
`R` is clear from the context or `\ZZ` or `\QQ`). It is graded by
the total degree of the power series. Its homogeneous elements of degree
`k` form a free `R`-submodule of rank equal to the number of
compositions of `k` (that is, `2^{k-1}` if `k \geq 1`, else `1`).
The two classical bases of `\mathrm{QSym}`, the monomial basis
`(M_I)_I` and the fundamental basis `(F_I)_I`, are indexed by
compositions `I = (I_1, I_2, \cdots, I_\ell )` and defined by the
formulas:
.. MATH::
M_I = \sum_{1 \leq i_1 < i_2 < \cdots < i_\ell} x_{i_1}^{I_1}
x_{i_2}^{I_2} \cdots x_{i_\ell}^{I_\ell}
and
.. MATH::
F_I = \sum_{(j_1, j_2, \ldots, j_n)} x_{j_1} x_{j_2} \cdots
x_{j_n}
where in the second equation the sum runs over all weakly increasing
`n`-tuples `(j_1, j_2, \ldots, j_n)` of positive integers
(where `n` is the size of `I`) which increase strictly from `j_r`
to `j_{r+1}` if `r` is a descent of the composition `I`.
These bases are related by the formula
`F_I = \sum_{J \leq I} M_J`
where the inequality `J \leq I` indicates that `J` is finer than `I`.
The `R`-algebra of quasi-symmetric functions is a Hopf algebra,
with the coproduct satisfying
.. MATH::
\Delta M_I = \sum_{k=0}^{\ell} M_{(I_1, I_2, \cdots, I_k)} \otimes
M_{(I_{k+1}, I_{k+2}, \cdots , I_{\ell})}
for every composition `I = (I_1, I_2, \cdots , I_\ell )`.
It is possible to define an `R`-algebra of quasi-symmetric
functions in a finite number of variables as well (but it is not
a bialgebra). These quasi-symmetric functions are actual polynomials
then, not just power series.
Chapter 5 of [GriRei2014]_ and Section 11 of [HazWitt1]_ are devoted
to quasi-symmetric functions, as are Malvenuto's thesis [Mal1993]_
and part of Chapter 7 of [Sta-EC2]_.
.. rubric:: The implementation of the quasi-symmetric function Hopf algebra
We realize the `R`-algebra of quasi-symmetric functions in Sage as
a graded Hopf algebra with basis elements indexed by compositions::
sage: QSym = QuasiSymmetricFunctions(QQ)
sage: QSym.category()
Join of Category of hopf algebras over Rational Field
and Category of graded algebras over Rational Field
and Category of monoids with realizations
and Category of coalgebras over Rational Field with realizations
The most standard two bases for this `R`-algebra are the monomial and
fundamental bases, and are accessible by the ``M()`` and ``F()`` methods::
sage: M = QSym.M()
sage: F = QSym.F()
sage: M(F[2,1,2])
M[1, 1, 1, 1, 1] + M[1, 1, 1, 2] + M[2, 1, 1, 1] + M[2, 1, 2]
sage: F(M[2,1,2])
F[1, 1, 1, 1, 1] - F[1, 1, 1, 2] - F[2, 1, 1, 1] + F[2, 1, 2]
The product on this space is commutative and is inherited from the product
on the realization within the ring of power series::
sage: M[3]*M[1,1] == M[1,1]*M[3]
True
sage: M[3]*M[1,1]
M[1, 1, 3] + M[1, 3, 1] + M[1, 4] + M[3, 1, 1] + M[4, 1]
sage: F[3]*F[1,1]
F[1, 1, 3] + F[1, 2, 2] + F[1, 3, 1] + F[1, 4] + F[2, 1, 2]
+ F[2, 2, 1] + F[2, 3] + F[3, 1, 1] + F[3, 2] + F[4, 1]
sage: M[3]*F[2]
M[1, 1, 3] + M[1, 3, 1] + M[1, 4] + M[2, 3] + M[3, 1, 1] + M[3, 2]
+ M[4, 1] + M[5]
sage: F[2]*M[3]
F[1, 1, 1, 2] - F[1, 2, 2] + F[2, 1, 1, 1] - F[2, 1, 2] - F[2, 2, 1]
+ F[5]
There is a coproduct on `\mathrm{QSym}` as well, which in the Monomial
basis acts by cutting the composition into a left half and a right
half. The coproduct is not co-commutative::
sage: M[1,3,1].coproduct()
M[] # M[1, 3, 1] + M[1] # M[3, 1] + M[1, 3] # M[1] + M[1, 3, 1] # M[]
sage: F[1,3,1].coproduct()
F[] # F[1, 3, 1] + F[1] # F[3, 1] + F[1, 1] # F[2, 1]
+ F[1, 2] # F[1, 1] + F[1, 3] # F[1] + F[1, 3, 1] # F[]
.. rubric:: The duality pairing with non-commutative symmetric functions
These two operations endow the quasi-symmetric functions
`\mathrm{QSym}` with the structure of a Hopf algebra. It is the graded
dual Hopf algebra of the non-commutative symmetric functions `NCSF`.
Under this duality, the Monomial basis of `\mathrm{QSym}` is dual to
the Complete basis of `NCSF`, and the Fundamental basis of
`\mathrm{QSym}` is dual to the Ribbon basis of `NCSF` (see [MR]_).
::
sage: S = M.dual(); S
Non-Commutative Symmetric Functions over the Rational Field in the Complete basis
sage: M[1,3,1].duality_pairing( S[1,3,1] )
1
sage: M.duality_pairing_matrix( S, degree=4 )
[1 0 0 0 0 0 0 0]
[0 1 0 0 0 0 0 0]
[0 0 1 0 0 0 0 0]
[0 0 0 1 0 0 0 0]
[0 0 0 0 1 0 0 0]
[0 0 0 0 0 1 0 0]
[0 0 0 0 0 0 1 0]
[0 0 0 0 0 0 0 1]
sage: F.duality_pairing_matrix( S, degree=4 )
[1 0 0 0 0 0 0 0]
[1 1 0 0 0 0 0 0]
[1 0 1 0 0 0 0 0]
[1 1 1 1 0 0 0 0]
[1 0 0 0 1 0 0 0]
[1 1 0 0 1 1 0 0]
[1 0 1 0 1 0 1 0]
[1 1 1 1 1 1 1 1]
sage: NCSF = M.realization_of().dual()
sage: R = NCSF.Ribbon()
sage: F.duality_pairing_matrix( R, degree=4 )
[1 0 0 0 0 0 0 0]
[0 1 0 0 0 0 0 0]
[0 0 1 0 0 0 0 0]
[0 0 0 1 0 0 0 0]
[0 0 0 0 1 0 0 0]
[0 0 0 0 0 1 0 0]
[0 0 0 0 0 0 1 0]
[0 0 0 0 0 0 0 1]
sage: M.duality_pairing_matrix( R, degree=4 )
[ 1 0 0 0 0 0 0 0]
[-1 1 0 0 0 0 0 0]
[-1 0 1 0 0 0 0 0]
[ 1 -1 -1 1 0 0 0 0]
[-1 0 0 0 1 0 0 0]
[ 1 -1 0 0 -1 1 0 0]
[ 1 0 -1 0 -1 0 1 0]
[-1 1 1 -1 1 -1 -1 1]
Let `H` and `G` be elements of `\mathrm{QSym}`, and `h` an element of
`NCSF`. Then, if we represent the duality pairing with the
mathematical notation `[ \cdot, \cdot ]`,
`[H G, h] = [H \otimes G, \Delta(h)]~.`
For example, the coefficient of ``M[2,1,4,1]`` in ``M[1,3]*M[2,1,1]`` may be
computed with the duality pairing::
sage: I, J = Composition([1,3]), Composition([2,1,1])
sage: (M[I]*M[J]).duality_pairing(S[2,1,4,1])
1
And the coefficient of ``S[1,3] # S[2,1,1]`` in ``S[2,1,4,1].coproduct()`` is
equal to this result::
sage: S[2,1,4,1].coproduct()
S[] # S[2, 1, 4, 1] + ... + S[1, 3] # S[2, 1, 1] + ... + S[4, 1] # S[2, 1]
The duality pairing on the tensor space is another way of getting this
coefficient, but currently the method ``duality_pairing`` is not defined on
the tensor squared space. However, we can extend this functionality by
applying a linear morphism to the terms in the coproduct, as follows::
sage: X = S[2,1,4,1].coproduct()
sage: def linear_morphism(x, y):
....: return x.duality_pairing(M[1,3]) * y.duality_pairing(M[2,1,1])
sage: X.apply_multilinear_morphism(linear_morphism, codomain=ZZ)
1
Similarly, if `H` is an element of `\mathrm{QSym}` and `g` and `h` are
elements of `NCSF`, then
.. MATH::
[ H, g h ] = [ \Delta(H), g \otimes h ].
For example, the coefficient of ``R[2,3,1]`` in ``R[2,1]*R[2,1]`` is
computed with the duality pairing by the following command::
sage: (R[2,1]*R[2,1]).duality_pairing(F[2,3,1])
1
sage: R[2,1]*R[2,1]
R[2, 1, 2, 1] + R[2, 3, 1]
This coefficient should then be equal to the coefficient of
``F[2,1] # F[2,1]`` in ``F[2,3,1].coproduct()``::
sage: F[2,3,1].coproduct()
F[] # F[2, 3, 1] + ... + F[2, 1] # F[2, 1] + ... + F[2, 3, 1] # F[]
This can also be computed by the duality pairing on the tensor space,
as above::
sage: X = F[2,3,1].coproduct()
sage: def linear_morphism(x, y):
....: return x.duality_pairing(R[2,1]) * y.duality_pairing(R[2,1])
sage: X.apply_multilinear_morphism(linear_morphism, codomain=ZZ)
1
.. rubric:: The operation dual to multiplication by a non-commutative symmetric function
Let `g \in NCSF` and consider the linear endomorphism of `NCSF` defined by
left (respectively, right) multiplication by `g`. Since there is a duality
between `\mathrm{QSym}` and `NCSF`, this linear transformation induces an
operator `g^{\perp}` on `\mathrm{QSym}` satisfying
.. MATH::
[ g^{\perp}(H), h ] = [ H, gh ].
for any non-commutative symmetric function `h`.
This is implemented by the method
:meth:`~sage.combinat.ncsf_qsym.generic_basis_code.BasesOfQSymOrNCSF.ElementMethods.skew_by`.
Explicitly, if ``H`` is a quasi-symmetric function and ``g``
a non-commutative symmetric function, then ``H.skew_by(g)`` and
``H.skew_by(g, side='right')`` are expressions that satisfy,
for any non-commutative symmetric function ``h``, the following
equalities::
H.skew_by(g).duality_pairing(h) == H.duality_pairing(g*h)
H.skew_by(g, side='right').duality_pairing(h) == H.duality_pairing(h*g)
For example, ``M[J].skew_by(S[I])`` is `0` unless the composition ``J``
begins with ``I`` and ``M(J).skew_by(S(I), side='right')`` is `0` unless
the composition ``J`` ends with ``I``. For example::
sage: M[3,2,2].skew_by(S[3])
M[2, 2]
sage: M[3,2,2].skew_by(S[2])
0
sage: M[3,2,2].coproduct().apply_multilinear_morphism( lambda x,y: x.duality_pairing(S[3])*y )
M[2, 2]
sage: M[3,2,2].skew_by(S[3], side='right')
0
sage: M[3,2,2].skew_by(S[2], side='right')
M[3, 2]
.. rubric:: The counit
The counit is defined by sending all elements of positive degree to zero::
sage: M[3].degree(), M[3,1,2].degree(), M.one().degree()
(3, 6, 0)
sage: M[3].counit()
0
sage: M[3,1,2].counit()
0
sage: M.one().counit()
1
sage: (M[3] - 2*M[3,1,2] + 7).counit()
7
sage: (F[3] - 2*F[3,1,2] + 7).counit()
7
.. rubric:: The antipode
The antipode sends the Fundamental basis element indexed by the
composition `I` to `(-1)^{|I|}` times the Fundamental
basis element indexed by the conjugate composition to `I`
(where `|I|` stands for the size of `I`, that is, the sum of all
entries of `I`).
::
sage: F[3,2,2].antipode()
-F[1, 2, 2, 1, 1]
sage: Composition([3,2,2]).conjugate()
[1, 2, 2, 1, 1]
The antipodes of the Monomial quasisymmetric functions can also be
computed easily: Every composition `I` satisfies
.. MATH::
\omega(M_I) = (-1)^{\ell(I)} \sum M_J,
where the sum ranges over all compositions `J` of `|I|`
which are coarser than the reversed composition `I^r` of
`I`. Here, `\ell(I)` denotes the length of the composition `I`
(that is, the number of its parts). ::
sage: M[3,2,1].antipode()
-M[1, 2, 3] - M[1, 5] - M[3, 3] - M[6]
sage: M[3,2,2].antipode()
-M[2, 2, 3] - M[2, 5] - M[4, 3] - M[7]
We demonstrate here the defining relation of the antipode::
sage: X = F[3,2,2].coproduct()
sage: X.apply_multilinear_morphism(lambda x,y: x*y.antipode())
0
sage: X.apply_multilinear_morphism(lambda x,y: x.antipode()*y)
0
.. rubric:: The relation with symmetric functions
The quasi-symmetric functions are a ring which contain the
symmetric functions as a subring. The Monomial quasi-symmetric
functions are related to the monomial symmetric functions by
.. MATH::
m_\lambda = \sum_{\operatorname{sort}(I) = \lambda} M_I
(where `\operatorname{sort}(I)` denotes the result of sorting
the entries of `I` in decreasing order).
There are methods to test if an expression in the quasi-symmetric
functions is a symmetric function and, if it is, send it to an
expression in the symmetric functions::
sage: f = M[1,1,2] + M[1,2,1]
sage: f.is_symmetric()
False
sage: g = M[3,1] + M[1,3]
sage: g.is_symmetric()
True
sage: g.to_symmetric_function()
m[3, 1]
The expansion of the Schur function in terms of the Fundamental quasi-symmetric
functions is due to [Ges]_. There is one term in the expansion for each standard
tableau of shape equal to the partition indexing the Schur function.
::
sage: f = F[3,2] + F[2,2,1] + F[2,3] + F[1,3,1] + F[1,2,2]
sage: f.is_symmetric()
True
sage: f.to_symmetric_function()
5*m[1, 1, 1, 1, 1] + 3*m[2, 1, 1, 1] + 2*m[2, 2, 1] + m[3, 1, 1] + m[3, 2]
sage: s = SymmetricFunctions(QQ).s()
sage: s(f.to_symmetric_function())
s[3, 2]
It is also possible to convert a symmetric function to a
quasi-symmetric function::
sage: m = SymmetricFunctions(QQ).m()
sage: M( m[3,1,1] )
M[1, 1, 3] + M[1, 3, 1] + M[3, 1, 1]
sage: F( s[2,2,1] )
F[1, 1, 2, 1] + F[1, 2, 1, 1] + F[1, 2, 2] + F[2, 1, 2] + F[2, 2, 1]
It is possible to experiment with the quasi-symmetric function expansion of other
bases, but it is important that the base ring be the same for both algebras.
::
sage: R = QQ['t']
sage: Qp = SymmetricFunctions(R).hall_littlewood().Qp()
sage: QSymt = QuasiSymmetricFunctions(R)
sage: Ft = QSymt.F()
sage: Ft( Qp[2,2] )
F[1, 2, 1] + t*F[1, 3] + (t+1)*F[2, 2] + t*F[3, 1] + t^2*F[4]
::
sage: K = QQ['q','t'].fraction_field()
sage: Ht = SymmetricFunctions(K).macdonald().Ht()
sage: Fqt = QuasiSymmetricFunctions(Ht.base_ring()).F()
sage: Fqt(Ht[2,1])
q*t*F[1, 1, 1] + (q+t)*F[1, 2] + (q+t)*F[2, 1] + F[3]
The following will raise an error because the base ring of ``F`` is not
equal to the base ring of ``Ht``::
sage: F(Ht[2,1])
Traceback (most recent call last):
...
TypeError: do not know how to make x (= McdHt[2, 1]) an element of self (=Quasisymmetric functions over the Rational Field in the Fundamental basis)
.. rubric:: The map to the ring of polynomials
The quasi-symmetric functions can be seen as an inverse limit
of a subring of a polynomial ring as the number of variables
increases. Indeed, there exists a projection from the
quasi-symmetric functions onto the polynomial ring
`R[x_1, x_2, \ldots, x_n]`. This projection is defined by
sending the variables `x_{n+1}, x_{n+2}, \cdots` to `0`, while
the remaining `n` variables remain fixed. Note that this
projection sends `M_I` to `0` if the length of the composition
`I` is higher than `n`. ::
sage: M[1,3,1].expand(4)
x0*x1^3*x2 + x0*x1^3*x3 + x0*x2^3*x3 + x1*x2^3*x3
sage: F[1,3,1].expand(4)
x0*x1^3*x2 + x0*x1^3*x3 + x0*x1^2*x2*x3 + x0*x1*x2^2*x3 + x0*x2^3*x3 + x1*x2^3*x3
sage: M[1,3,1].expand(2)
0
TESTS::
sage: QSym = QuasiSymmetricFunctions(QQ); QSym
Quasisymmetric functions over the Rational Field
sage: QSym.base_ring()
Rational Field
"""
def __init__(self, R):
"""
The Hopf algebra of quasi-symmetric functions.
See ``QuasiSymmetricFunctions`` for full documentation.
EXAMPLES::
sage: QuasiSymmetricFunctions(QQ)
Quasisymmetric functions over the Rational Field
sage: QSym1 = QuasiSymmetricFunctions(FiniteField(23))
sage: QSym2 = QuasiSymmetricFunctions(Integers(23))
sage: TestSuite(QuasiSymmetricFunctions(QQ)).run()
"""
# change the line below to assert(R in Rings()) once MRO issues from #15536, #15475 are resolved
assert(R in Fields() or R in Rings()) # side effect of this statement assures MRO exists for R
self._base = R # Won't be needed once CategoryObject won't override base_ring
category = GradedHopfAlgebras(R) # TODO: .Commutative()
self._category = category
Parent.__init__(self, category = category.WithRealizations())
# Bases
Monomial = self.Monomial()
Fundamental = self.Fundamental()
dualImmaculate = self.dualImmaculate()
QS = self.Quasisymmetric_Schur()
# Change of bases
Fundamental.module_morphism(Monomial.sum_of_finer_compositions,
codomain=Monomial, category=category
).register_as_coercion()
Monomial .module_morphism(Fundamental.alternating_sum_of_finer_compositions,
codomain=Fundamental, category=category
).register_as_coercion()
#This changes dualImmaculate into Monomial
dualImmaculate.module_morphism(dualImmaculate._to_Monomial_on_basis,
codomain = Monomial, category = category
).register_as_coercion()
#This changes Monomial into dualImmaculate
Monomial.module_morphism(dualImmaculate._from_Monomial_on_basis,
codomain = dualImmaculate, category = category
).register_as_coercion()
#This changes Quasisymmetric Schur into Monomial
QS .module_morphism(QS._to_monomial_on_basis,
codomain=Monomial, category=category
).register_as_coercion()
#This changes Monomial into Quasisymmetric Schur
Monomial.module_morphism(QS._from_monomial_on_basis,
codomain=QS, category=category
).register_as_coercion()
# Embedding of Sym into QSym in the monomial bases
Sym = SymmetricFunctions(self.base_ring())
Sym_m_to_M = Sym.m().module_morphism(Monomial.sum_of_partition_rearrangements,
triangular='upper', inverse_on_support=Monomial._comp_to_par,
codomain=Monomial, category=category)
Sym_m_to_M.register_as_coercion()
self.to_symmetric_function = Sym_m_to_M.section()
def _repr_(self):
r"""
EXAMPLES::
sage: M = QuasiSymmetricFunctions(ZZ).M()
sage: M._repr_()
'Quasisymmetric functions over the Integer Ring in the Monomial basis'
"""
return "Quasisymmetric functions over the %s"%self.base_ring()
def a_realization(self):
r"""
Return the realization of the Monomial basis of the ring of quasi-symmetric functions.
OUTPUT:
- The Monomial basis of quasi-symmetric functions.
EXAMPLES::
sage: QuasiSymmetricFunctions(QQ).a_realization()
Quasisymmetric functions over the Rational Field in the Monomial basis
"""
return self.Monomial()
_shorthands = tuple(['M', 'F', 'dI', 'QS'])
def dual(self):
r"""
Return the dual Hopf algebra of the quasi-symmetric functions, which is the
non-commutative symmetric functions.
OUTPUT:
- The non-commutative symmetric functions.
EXAMPLES::
sage: QSym = QuasiSymmetricFunctions(QQ)
sage: QSym.dual()
Non-Commutative Symmetric Functions over the Rational Field
"""
return NonCommutativeSymmetricFunctions(self.base_ring())
def from_polynomial(self, f, check=True):
"""
Return the quasi-symmetric function in the Monomial basis
corresponding to the quasi-symmetric polynomial ``f``.
INPUT:
- ``f`` -- a polynomial in finitely many variables over the same base
ring as ``self``. It is assumed that this polynomial is
quasi-symmetric.
- ``check`` -- boolean (default: ``True``), checks whether the
polynomial is indeed quasi-symmetric.
OUTPUT:
- quasi-symmetric function in the Monomial basis
EXAMPLES::
sage: P = PolynomialRing(QQ, 'x', 3)
sage: x = P.gens()
sage: f = x[0] + x[1] + x[2]
sage: QSym = QuasiSymmetricFunctions(QQ)
sage: QSym.from_polynomial(f)
M[1]
Beware of setting ``check=False``::
sage: f = x[0] + 2*x[1] + x[2]
sage: QSym.from_polynomial(f, check=True)
Traceback (most recent call last):
...
ValueError: x0 + 2*x1 + x2 is not a quasi-symmetric polynomial
sage: QSym.from_polynomial(f, check=False)
M[1]
To expand the quasi-symmetric function in a basis other than the
Monomial basis, the following shorthands are provided::
sage: M = QSym.Monomial()
sage: f = x[0]**2+x[1]**2+x[2]**2
sage: g = M.from_polynomial(f); g
M[2]
sage: F = QSym.Fundamental()
sage: F(g)
-F[1, 1] + F[2]
sage: F.from_polynomial(f)
-F[1, 1] + F[2]
"""
assert self.base_ring() == f.base_ring()
exponent_coefficient = f.dict()
z = {}
for (e, c) in exponent_coefficient.iteritems():
I = Compositions()([ei for ei in e if ei > 0])
if I not in z:
z[I] = c
out = self.Monomial()._from_dict(z)
if check and out.expand(f.parent().ngens(), f.parent().gens()) != f:
raise ValueError("%s is not a quasi-symmetric polynomial" % f)
return out
class Bases(Category_realization_of_parent):
r"""
Category of bases of quasi-symmetric functions.
EXAMPLES::
sage: QSym = QuasiSymmetricFunctions(QQ)
sage: QSym.Bases()
Category of bases of Quasisymmetric functions over the Rational Field
"""
def super_categories(self):
r"""
Return the super categories of bases of the Quasi-symmetric functions.
OUTPUT:
- a list of categories
TESTS::
sage: QSym = QuasiSymmetricFunctions(QQ)
sage: QSym.Bases().super_categories()
[Category of commutative bases of Non-Commutative Symmetric Functions or Quasisymmetric functions over the Rational Field]
"""
return [BasesOfQSymOrNCSF(self.base()).Commutative()]
class ParentMethods:
r"""
Methods common to all bases of ``QuasiSymmetricFunctions``.
"""
def from_polynomial(self, f, check=True):
"""
The quasi-symmetric function expanded in this basis
corresponding to the quasi-symmetric polynomial ``f``.
This is a default implementation that computes
the expansion in the Monomial basis and converts
to this basis.
INPUT:
- ``f`` -- a polynomial in finitely many variables over the same base
ring as ``self``. It is assumed that this polynomial is
quasi-symmetric.
- ``check`` -- boolean (default: ``True``), checks whether the
polynomial is indeed quasi-symmetric.
OUTPUT:
- quasi-symmetric function
EXAMPLES::
sage: M = QuasiSymmetricFunctions(QQ).Monomial()
sage: F = QuasiSymmetricFunctions(QQ).Fundamental()
sage: P = PolynomialRing(QQ, 'x', 3)
sage: x = P.gens()
sage: f = x[0] + x[1] + x[2]
sage: M.from_polynomial(f)
M[1]
sage: F.from_polynomial(f)
F[1]
sage: f = x[0]**2+x[1]**2+x[2]**2
sage: M.from_polynomial(f)
M[2]
sage: F.from_polynomial(f)
-F[1, 1] + F[2]
If the polynomial is not quasi-symmetric, an error
is raised::
sage: f = x[0]^2+x[1]
sage: M.from_polynomial(f)
Traceback (most recent call last):
...
ValueError: x0^2 + x1 is not a quasi-symmetric polynomial
sage: F.from_polynomial(f)
Traceback (most recent call last):
...
ValueError: x0^2 + x1 is not a quasi-symmetric polynomial
TESTS:
We convert some quasi-symmetric functions to quasi-symmetric
polynomials and back::
sage: f = (M[1,2] + M[1,1]).expand(3); f
x0*x1^2 + x0*x2^2 + x1*x2^2 + x0*x1 + x0*x2 + x1*x2
sage: M.from_polynomial(f)
M[1, 1] + M[1, 2]
sage: f = (2*M[2,1]+M[1,1]+3*M[3]).expand(3)
sage: M.from_polynomial(f)
M[1, 1] + 2*M[2, 1] + 3*M[3]
sage: f = (F[1,2] + F[1,1]).expand(3); f
x0*x1^2 + x0*x1*x2 + x0*x2^2 + x1*x2^2 + x0*x1 + x0*x2 + x1*x2
sage: F.from_polynomial(f)
F[1, 1] + F[1, 2]
sage: f = (2*F[2,1]+F[1,1]+3*F[3]).expand(3)
sage: F.from_polynomial(f)
F[1, 1] + 2*F[2, 1] + 3*F[3]
"""
g = self.realization_of().from_polynomial(f, check=check)
return self(g)
def Eulerian(self, n, j, k=None):
"""
Return the Eulerian (quasi)symmetric function `Q_{n,j}` in
terms of ``self``.
INPUT:
- ``n`` -- the value `n` or a partition
- ``j`` -- the number of excedances
- ``k`` -- (optional) if specified, determines the number of
fixed points of the permtutation
EXAMPLES::
sage: QSym = QuasiSymmetricFunctions(QQ)
sage: M = QSym.M()
sage: M.Eulerian(3, 1)
4*M[1, 1, 1] + 3*M[1, 2] + 3*M[2, 1] + 2*M[3]
sage: M.Eulerian(4, 1, 2)
6*M[1, 1, 1, 1] + 4*M[1, 1, 2] + 4*M[1, 2, 1]
+ 2*M[1, 3] + 4*M[2, 1, 1] + 3*M[2, 2] + 2*M[3, 1] + M[4]
sage: QS = QSym.QS()
sage: QS.Eulerian(4, 2)
2*QS[1, 3] + QS[2, 2] + 2*QS[3, 1] + 3*QS[4]
sage: QS.Eulerian([2, 2, 1], 2)
QS[1, 2, 2] + QS[1, 4] + QS[2, 1, 2] + QS[2, 2, 1]
+ QS[2, 3] + QS[3, 2] + QS[4, 1] + QS[5]
sage: dI = QSym.dI()
sage: dI.Eulerian(5, 2)
-dI[1, 3, 1] - 5*dI[1, 4] + dI[2, 2, 1] + dI[3, 1, 1]
+ 5*dI[3, 2] + 6*dI[4, 1] + 6*dI[5]
"""
F = self.realization_of().F()
if n in _Partitions:
n = _Partitions(n)
return self(F.Eulerian(n, j, k))
class ElementMethods:
r"""
Methods common to all elements of ``QuasiSymmetricFunctions``.
"""
def internal_coproduct(self):
r"""
Return the inner coproduct of ``self`` in the basis of ``self``.
The inner coproduct (also known as the Kronecker coproduct,
or as the second comultiplication on the `R`-algebra of
quasi-symmetric functions) is an `R`-algebra homomorphism
`\Delta^{\times}` from the `R`-algebra of quasi-symmetric
functions to the tensor square (over `R`) of quasi-symmetric
functions. It can be defined in the following two ways:
#. If `I` is a composition, then a `(0, I)`-matrix will mean a
matrix whose entries are nonnegative integers such that no
row and no column of this matrix is zero, and such that if
all the non-zero entries of the matrix are read (row by row,
starting at the topmost row, reading every row from left to
right), then the reading word obtained is `I`. If `A` is
a `(0, I)`-matrix, then `\mathrm{row}(A)` will denote the
vector of row sums of `A` (regarded as a composition), and
`\mathrm{column}(A)` will denote the vector of column sums
of `A` (regarded as a composition).
For every composition `I`, the internal coproduct
`\Delta^{\times}(M_I)` of the `I`-th monomial quasisymmetric
function `M_I` is the sum
.. MATH::
\sum_{A \hbox{ is a } (0, I) \text{-matrix}}
M_{\mathrm{row}(A)} \otimes M_{\mathrm{column}(A)}.
See Section 11.39 of [HazWitt1]_.
#. For every permutation `w`, let `C(w)` denote the descent
composition of `w`. Then, for any composition `I` of size
`n`, the internal coproduct `\Delta^{\times}(F_I)` of the
`I`-th fundamental quasisymmetric function `F_I` is the sum
.. MATH::
\sum_{\substack{\sigma \in S_n,\\ \tau \in S_n,\\
\tau \sigma = \pi}} F_{C(\sigma)} \otimes F_{C(\tau)},
where `\pi` is any permutation in `S_n` having descent
composition `I` and where permutations act from the left and
multiply accordingly, so `\tau \sigma` means first applying
`\sigma` and then `\tau`. See Theorem 4.23 in [Mal1993]_,
but beware of the notations which are apparently different
from those in [HazWitt1]_.
The restriction of the internal coproduct to the
`R`-algebra of symmetric functions is the well-known
internal coproduct on the symmetric functions.
The method :meth:`kronecker_coproduct` is a synonym of this one.
EXAMPLES:
Let us compute the internal coproduct of `M_{21}` (which is
short for `M_{[2, 1]}`). The `(0, [2,1])`-matrices are
.. MATH::
\begin{bmatrix} 2 & 1 \end{bmatrix},
\begin{bmatrix} 2 \\ 1 \end{bmatrix},
\begin{bmatrix} 2 & 0 \\ 0 & 1 \end{bmatrix}, \hbox{ and }
\begin{bmatrix} 0 & 2 \\ 1 & 0 \end{bmatrix}
so
.. MATH::
\Delta^\times(M_{21}) = M_{3} \otimes M_{21} +
M_{21} \otimes M_3 + M_{21} \otimes M_{21} +
M_{21} \otimes M_{12}.
This is confirmed by the following Sage computation
(incidentally demonstrating the non-cocommutativity of
the internal coproduct)::
sage: M = QuasiSymmetricFunctions(ZZ).M()
sage: a = M([2,1])
sage: a.internal_coproduct()
M[2, 1] # M[1, 2] + M[2, 1] # M[2, 1] + M[2, 1] # M[3] + M[3] # M[2, 1]
Further examples::
sage: all( M([i]).internal_coproduct() == tensor([M([i]), M([i])])
....: for i in range(1, 4) )
True
sage: M([1, 2]).internal_coproduct()
M[1, 2] # M[1, 2] + M[1, 2] # M[2, 1] + M[1, 2] # M[3] + M[3] # M[1, 2]
The definition of `\Delta^{\times}(M_I)` in terms of
`(0, I)`-matrices is not suitable for computation in
cases where the length of `I` is large, but we can use
it as a doctest. Here is a naive implementation::
sage: def naive_internal_coproduct_on_M(I):
....: # INPUT: composition I
....: # (not quasi-symmetric function)
....: # OUTPUT: interior coproduct of M_I
....: M = QuasiSymmetricFunctions(ZZ).M()
....: M2 = M.tensor(M)
....: res = M2.zero()
....: l = len(I)
....: n = I.size()
....: for S in Subsets(range(l**2), l):
....: M_list = sorted(S)
....: row_M = [sum([I[M_list.index(l * i + j)]
....: for j in range(l) if
....: l * i + j in S])
....: for i in range(l)]
....: col_M = [sum([I[M_list.index(l * i + j)]
....: for i in range(l) if
....: l * i + j in S])
....: for j in range(l)]
....: if 0 in row_M:
....: first_zero = row_M.index(0)
....: row_M = row_M[:first_zero]
....: if sum(row_M) != n:
....: continue
....: if 0 in col_M:
....: first_zero = col_M.index(0)
....: col_M = col_M[:first_zero]
....: if sum(col_M) != n:
....: continue
....: res += tensor([M(Compositions(n)(row_M)),
....: M(Compositions(n)(col_M))])
....: return res
sage: all( naive_internal_coproduct_on_M(I)
....: == M(I).internal_coproduct()
....: for I in Compositions(3) )
True
TESTS:
Border cases::
sage: M = QuasiSymmetricFunctions(ZZ).M()
sage: F = QuasiSymmetricFunctions(ZZ).F()
sage: M([]).internal_coproduct()
M[] # M[]
sage: F([]).internal_coproduct()
F[] # F[]
The implementations on the ``F`` and ``M`` bases agree
with each other::
sage: M = QuasiSymmetricFunctions(ZZ).M()
sage: F = QuasiSymmetricFunctions(ZZ).F()
sage: def int_copr_on_F_via_M(I):
....: result = tensor([F.zero(), F.zero()])
....: w = M(F(I)).internal_coproduct()
....: for lam, a in w:
....: (U, V) = lam
....: result += a * tensor([F(M(U)), F(M(V))])
....: return result
sage: all( int_copr_on_F_via_M(I) == F(I).internal_coproduct()
....: for I in Compositions(3) )
True
sage: all( int_copr_on_F_via_M(I) == F(I).internal_coproduct()
....: for I in Compositions(4) )
True
Restricting to the subring of symmetric functions gives the
standard internal coproduct on the latter::