This document is one of More SageMath Tutorials. You may edit it on github. \(\def\NN{\mathbb{N}}\) \(\def\ZZ{\mathbb{Z}}\) \(\def\QQ{\mathbb{Q}}\) \(\def\RR{\mathbb{R}}\) \(\def\CC{\mathbb{C}}\)
Demo: reflection groups (draft)¶
\(\def\QQ{\mathbb{Q}}\def\CC{\mathbb{C}}\def\Hilb{\operatorname{Hilb}}\)
This demonstration review some of the features of Coxeter and reflection groups (basic manipulations, related posets, calculation of Molien type series). It grew out of a live demo improvised with the participants during interactive sessions at the CRM workshop on reflection groups on May 29th of 2017.
Requirements
This demonstration requires gap3 to be installed.
sage: %display latex # not tested
Constructing Coxeter groups¶
Let’s build the Coxeter group of type \(E_8\), and do some sample calculations with it:
sage: W = CoxeterGroup(["E",8])
sage: W
Finite Coxeter group over Integer Ring with Coxeter matrix:
[1 2 3 2 2 2 2 2]
[2 1 2 3 2 2 2 2]
[3 2 1 3 2 2 2 2]
[2 3 3 1 3 2 2 2]
[2 2 2 3 1 3 2 2]
[2 2 2 2 3 1 3 2]
[2 2 2 2 2 3 1 3]
[2 2 2 2 2 2 3 1]
sage: W.cardinality()
696729600
By default, this Coxeter group is constructed as a matrix group:
sage: W.an_element()
[ 0 1 0 0 0 0 0 -1]
[ 0 0 1 0 0 0 0 -1]
[ 1 1 0 0 0 0 0 -1]
[ 0 1 1 0 0 0 0 -1]
[ 0 0 0 1 0 0 0 -1]
[ 0 0 0 0 1 0 0 -1]
[ 0 0 0 0 0 1 0 -1]
[ 0 0 0 0 0 0 1 -1]
Instead, it’s possible to construct it as a permutation group, namely the group of permutation of its roots:
sage: W = CoxeterGroup(["E",8], implementation="permutation")
sage: w = W.an_element(); w
(1,121)(3,13)(9,22)(18,27)(19,23)(25,30)(29,35)(31,42)(34,40)(36,37)(38,45)(41,47)(43,49)(44,56)(48,51)(50,52)(54,59)(55,62)(57,64)(60,63)(68,73)(74,78)(96,98)(100,102)(101,106)(104,107)(108,110)(109,112)(111,113)(123,133)(129,142)(138,147)(139,143)(145,150)(149,155)(151,162)(154,160)(156,157)(158,165)(161,167)(163,169)(164,176)(168,171)(170,172)(174,179)(175,182)(177,184)(180,183)(188,193)(194,198)(216,218)(220,222)(221,226)(224,227)(228,230)(229,232)(231,233)
Finite and affine Coxeter groups can be specified as above using their classification, by providing their Cartan type. Here is a sample of all available Cartan types:
sage: CartanType.samples()
[['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5],
['D', 2], ['D', 3], ['D', 5],
['E', 6], ['E', 7], ['E', 8],
['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4],
['A', 1, 1], ... ['BC', 5, 2]^*]
It contains all exceptional types, and a couple representatives of each infinite families.
Reduced words¶
Let’s play with elements and reduced words. One can construct an element from the Coxeter generators (also called simple reflections) with:
sage: s = W.simple_reflections()
sage: w = s[1] * s[3] * s[2]; w
(1,133,3)(2,122)(4,18,22,10,9,27)(13,123,121)(15,25,23,21,19,30)(17,36,35,28,29,37)(26,41,42,33,31,47)(32,48,45,39,38,51)(34,46,40)(43,53,49)(44,61,56)(50,58,52)(54,67,59)(55,66,62)(57,69,64)(60,70,63)(65,72)(68,77,73)(71,75)(74,83,78)(76,84)(79,81)(80,87)(82,88)(85,91)(86,90)(89,96,98)(92,94)(93,100,102)(95,99)(97,101,106)(103,104,107)(105,108,110)(109,115,112,111,114,113)(124,138,142,130,129,147)(135,145,143,141,139,150)(137,156,155,148,149,157)(146,161,162,153,151,167)(152,168,165,159,158,171)(154,166,160)(163,173,169)(164,181,176)(170,178,172)(174,187,179)(175,186,182)(177,189,184)(180,190,183)(185,192)(188,197,193)(191,195)(194,203,198)(196,204)(199,201)(200,207)(202,208)(205,211)(206,210)(209,216,218)(212,214)(213,220,222)(215,219)(217,221,226)(223,224,227)(225,228,230)(229,235,232,231,234,233)
Here is a short hand (note: the word need not be reduced):
sage: W.from_reduced_word([1,3,2])
(1,133,3)(2,122)(4,18,22,10,9,27)(13,123,121)(15,25,23,21,19,30)(17,36,35,28,29,37)(26,41,42,33,31,47)(32,48,45,39,38,51)(34,46,40)(43,53,49)(44,61,56)(50,58,52)(54,67,59)(55,66,62)(57,69,64)(60,70,63)(65,72)(68,77,73)(71,75)(74,83,78)(76,84)(79,81)(80,87)(82,88)(85,91)(86,90)(89,96,98)(92,94)(93,100,102)(95,99)(97,101,106)(103,104,107)(105,108,110)(109,115,112,111,114,113)(124,138,142,130,129,147)(135,145,143,141,139,150)(137,156,155,148,149,157)(146,161,162,153,151,167)(152,168,165,159,158,171)(154,166,160)(163,173,169)(164,181,176)(170,178,172)(174,187,179)(175,186,182)(177,189,184)(180,190,183)(185,192)(188,197,193)(191,195)(194,203,198)(196,204)(199,201)(200,207)(202,208)(205,211)(206,210)(209,216,218)(212,214)(213,220,222)(215,219)(217,221,226)(223,224,227)(225,228,230)(229,235,232,231,234,233)
sage: w.reduced_word()
[1, 2, 3]
sage: w.reduced_words()
[[1, 3, 2], [2, 1, 3], [1, 2, 3]]
Computing Molien-type sums for reflection groups¶
Let’s start by exploring the Shephard-Todd reflection group G_4
:
sage: W = ReflectionGroup(4); W
Irreducible complex reflection group of rank 2 and type ST4
sage: W.cardinality()
24
sage: W.is_isomorphic(SymmetricGroup(4))
False
It is constructed as a permutation group:
sage: w = W.an_element(); w
(1,3,9)(2,4,7)(5,10,18)(6,11,16)(8,12,19)(13,15,20)(14,17,21)(22,23,24)
Here is how to recover the matrix action on \(V\) and \(V^*\):
sage: m = w.to_matrix(); m
[ 1 0]
[ 0 E(3)]
sage: w.to_matrix("dual")
[ 1 0]
[ 0 E(3)^2]
The Hilbert series of the invariant ring and degrees of its generators¶
Let’s use Molien’s formula to compute the Hilbert series \(H=\Hilb(\CC[V]^W,q)\) of the invariant ring \(\CC[V]^W=S(V^*)^W\):
sage: QQq = QQ['q'].fraction_field()
sage: q = QQq.gen()
sage: H = 1/W.cardinality() * sum( 1/det(1-q*w.to_matrix()) for w in W );
sage: H
1/(q^10 - q^6 - q^4 + 1)
We know that this should factor as \(\frac{1}{\prod 1-q^{d_i}}\).
Frustrating as it is, Sage can’t factor the above fraction as is:
sage: H.factor()
Traceback (most recent call last):
...
NotImplementedError
That’s because it looks like a fraction in \(\QQ(q)\) but it is in fact a fraction in the Universal Cyclotomic Field (the extension of \(\QQ\) containing all roots of unity):
sage: H.parent()
Fraction Field of Univariate Polynomial Ring in q over Universal Cyclotomic Field
To proceed, we first convert \(H\) into \(\QQ(q)\):
sage: H = QQq(H)
sage: H.parent()
Fraction Field of Univariate Polynomial Ring in q over Rational Field
and then can finally factor it:
sage: factor(H.denominator())
(q - 1)^2 * (q + 1)^2 * (q^2 - q + 1) * (q^2 + 1) * (q^2 + q + 1)
This is a product of cyclotomic polynomials, and by manual inspection, one we can recover the desired form for the denominator of \(H\):
sage: H.denominator() == (1-q^4)*(1-q^6)
True
This is telling us that the invariant ring is generated by two invariants of degree \(4\) and \(6\). Let’s double check this.
Sage can compute generators of an invariant ring of a finite matrix
group, but only over reasonably simple fields, which does not include
the Universal Cyclotomic Field. So we are going to convert our group
into a matrix group WM
over the Cyclotomic Field of degree \(3\):
sage: K = CyclotomicField(3)
sage: WM = MatrixGroup( [ matrix(K, w.to_matrix()) for w in W.gens()])
sage: WM
Matrix group over Cyclotomic Field of order 3 and degree 2 with 2 generators (
[ 1 0] [2/3*zeta3 + 1/3 1/3*zeta3 - 1/3]
[ 0 zeta3], [2/3*zeta3 - 2/3 1/3*zeta3 + 2/3]
)
sage: WM.invariant_generators()
[x1^4 - x1*x2^3, x1^6 + 5/2*x1^3*x2^3 - 1/8*x2^6]
Computation of exponents and coexponents¶
We will use that \(V\) and \(V^*\) are irreducible representations together with the following relations between the Hilbert series of the corresponding isotypic components in the polynomial ring \(\CC[V]^W\) with the exponents \(e_1,\ldots,e_n\) and coexponents \(e_1^*,\ldots,e_n^*\):
sage: 1/W.cardinality() * sum( w.to_matrix().trace()/det(1-q*w.to_matrix()) for w in W ) / H
q^5 + q^3
sage: 1/W.cardinality() * sum( w.to_matrix("dual").trace()/det(1-q*w.to_matrix()) for w in W ) / H
q^3 + q
Let’s do a consistency check with the degrees (which are the \(e_i+1\)) and the codegrees (which are the \(e_i^*-1\)):
sage: W.degrees()
(4, 6)
sage: W.codegrees()
(2, 0)
Solomon’s formula¶
Exercise
Compute the Hilbert series of \((\CC[V]\otimes \bigwedge^\cdot V^*)^W\) via a Molien-type calculation:
and then compare it to the prediction of Solomon’s formula, namely:
Solution
sage: QQqt = QQ['q,t'].fraction_field()
sage: q,t = QQqt.gens()
sage: Solomon = 1/W.cardinality() * sum( det(1+t*w.to_matrix()) / det(1-q*w.to_matrix()) for w in W )
sage: QQqt(Solomon) / H
q^8*t^2 + q^5*t + q^3*t + 1
sage: _.factor()
(q^3*t + 1) * (q^5*t + 1)