Coxeter groups

Chevie.CoxGroupsModule

A suitable reference for the general theory of Coxeter groups is, for example, Bourbaki "Lie Groups and Lie Algebras" chapter 4.

A Coxeter group is a group which has the presentation $W=⟨S|(st)^{m(s,t)}=1\text{ for }s,t∈ S⟩$ for some symmetric integer matrix m(s,t) called the Coxeter matrix, where m(s,t)>1 for s≠t and m(s,s)=1; m(s,t)=∞ is allowed meaning there is no relation between s and t. It is true (but a non-trivial theorem) that in a Coxeter group the order of st is exactly m(s,t), thus a Coxeter group is the same as a Coxeter system, that is a pair (W,S) of a group W and a set S⊂W of involutions, such that the group is presented by generators S and relations describing the order of the product of two elements of S.

A Coxeter group has a natural representation, its reflection representation, on a real vector space V of dimension length(S) (which is the Coxeter rank of W), where each element of S acts as a reflection; the faithfulness of this representation (a theorem of Tits) is the main argument to prove that the order of st is exactly m(s,t). This representation is defined as follows on a space V with basis {eₛ} for s∈ S. The cartan matrix associated to the Coxeter matrix m(s,t) is the matrix C with entries C(s,t)=-2cos(π/m(s,t)); we set C(s,t)=-2 if m(s,t)=∞. Then the action of s∈ S on V is given by s(eₜ)=eₜ-C(s,t)eₛ.

Thus, Coxeter groups are real reflection groups. The converse need not be true if the set of reflecting hyperplanes has bad topological properties, but it turns out that finite Coxeter groups are the same as finite real reflection groups. The possible Coxeter matrices for finite Coxeter groups have been completely classified, see Weyl; the corresponding finite groups play a deep role in several areas of mathematics.

Coxeter groups have a nice solution to the word problem. The length l(w) of an element w∈ W is the minimum number of elements of S of which it is a product (since the elements of S are involutions, we do not need inverses). An expression of w of minimum length is called a reduced word for w. The main property of reduced words is the exchange lemma which states that if s₁…sₖ is a reduced word for w (thus k=l(w)) and s∈ S is such that l(sw)≤l(w) then one of the sᵢ in the word for w can be deleted to obtain a reduced word for sw. Thus given s∈ S and w∈ W, either l(sw)=l(w)+1 or l(sw)=l(w)-1 and in the latter case we say that s belongs to the left descent set of w. Computing a reduced word for an element, and other word problems, are easy if we know how to multiply elements and know left descent sets. In each of the Coxeter groups that we implement, the left descent set is easy to compute (see for example coxeter_symmetric_group below), so this suggests how to deal with Coxeter groups generically:

The type CoxeterGroup is an abstract type; an actual struct which implements it must define a function

isleftdescent(W,w,i) which tells whether the i-th element of S is in the left descent set of w.

the other functions needed in an instance of a Coxeter group are

  • gens(W) which returns the set S (the list of Coxeter generators)
  • nref(W) which returns the number of reflections of W, if W is finite or nothing if W is infinite.

It should be noted that a Coxeter group can be any kind of group implementing the above functions.

Because of the easy solution of the word problem in Coxeter groups, a convenient way to represent their elements is as words in the Coxeter generators, that is lists of integers in 1:length(S). The functions 'word' and 'W(...)' do the conversion between Coxeter words and elements of the group.

Examples

julia> W=coxsym(4)
𝔖 ₄

julia> p=W(1,3,2,1,3)
(1,4)

julia> word(W,p)
5-element Vector{Int64}:
 1
 2
 3
 2
 1

We notice that the word we started with and the one that we ended up with, are not the same, even though they represent the same element of W. The reason is that there are several reduced words for an element of W. The function 'word' calculates a lexicographically smallest word for w. Below are some other possible computations using the same Coxeter group:

julia> word(W,longest(W))  # the (unique) longest element in W
6-element Vector{Int64}:
 1
 2
 1
 3
 2
 1

julia> w0=longest(W)
(1,4)(2,3)

julia> length(W,w0)
6
julia> map(w->word(W,w),refls(W,1:nref(W)))
6-element Vector{Vector{Int64}}:
 [1]
 [2]
 [3]
 [1, 2, 1]
 [2, 3, 2]
 [1, 2, 3, 2, 1]
julia> [length(elements(W,i)) for i in 0:nref(W)]
7-element Vector{Int64}:
 1
 3
 5
 6
 5
 3
 1

The last list tells us that there is 1 element of length 0, there are 6 of length 3, …

For most basic functions the convention is that the input is an element of the group, rather than a Coxeter word. The reason for this is that for a Coxeter group which is a permutation group, using the low level functions for permutations is usually much faster than manipulating lists representing reduced expressions.

The only Coxeter group constructors implemented in this module are coxsym and coxgroup; the last constructor takes a Cartan matrix and builds the corresponding Coxeter group as a matrix group. The module Weyl defines other methods for coxgroup building a finite Coxeter group as a permutation group, given its type.

source
Chevie.CoxGroups.isleftdescentMethod

isleftdescent(W::CoxeterGroup,w,i::Integer)

returns true iff the i-th generating reflection of the Coxeter group W is in the left descent set of the element w of W, that is iff length(W,W(i)*w)<length(W,w).

julia> W=coxsym(3)
𝔖 ₃

julia> isleftdescent(W,Perm(1,2),1)
true
source
Chevie.CoxGroups.isrightdescentFunction

isrightdescent(W::CoxeterGroup,w,i::Integer)

returns true iff the i-th generating reflection of the Coxeter group W is in the right descent set of the element w of W, that is iff length(W,w*W(i))<length(W,w).

julia> W=coxsym(3)
𝔖 ₃

julia> isrightdescent(W,Perm(1,2),1)
true
source
Chevie.CoxGroups.firstleftdescentFunction

firstleftdescent(W,w)

returns the index in gens(W) of the first element of the left descent set of w –- that is, the first i such that if s=W(i) then l(sw)<l(w). It returnsnothingforone(W)`.

julia> W=coxsym(3)
𝔖 ₃

julia> firstleftdescent(W,Perm(2,3))
2
source
Chevie.CoxGroups.leftdescentsMethod

leftdescents(W,w)

The left descents of the element w of the Coxeter group W, that is the set of i such that length(W,W(i)*w)<length(W,w).

julia> W=coxsym(3)
𝔖 ₃

julia> leftdescents(W,Perm(1,3))
2-element Vector{Int64}:
 1
 2
source
PermGroups.Groups.wordMethod

word(W::CoxeterGroup,w)

returns a reduced word in the standard generators of the Coxeter group W for the element w (represented as the vector of the corresponding generator indices).

julia> W=coxgroup(:A,3)
A₃

julia> w=perm"(1,11)(3,10)(4,9)(5,7)(6,12)"
(1,11)(3,10)(4,9)(5,7)(6,12)

julia> w in W
true

julia> word(W,w)
5-element Vector{Int64}:
 1
 2
 3
 2
 1

The result of  word is the lexicographically smallest reduced word for w (for the ordering of the Coxeter generators given by gens(W)).

source
Base.lengthMethod

length(W::CoxeterGroup ,w)

returns the length of a reduced expression in the Coxeter generators of the element w of W.

julia> W=coxsym(4)
𝔖 ₄

julia> p=W(1,2,3,1,2,3)
(1,3)(2,4)

julia> length(W,p)
4

julia> word(W,p)
4-element Vector{Int64}:
 2
 1
 3
 2
source
Chevie.CoxGroups.longestFunction

longest(W)

If W is finite, returns the unique element of maximal length of the Coxeter group W. May loop infinitely otherwise.

julia> longest(coxsym(4))
(1,4)(2,3)

longest(W,I)

returns the longest element of the parabolic subgroup of W generated by the generating reflections of indices in I.

julia> longest(coxsym(4))
(1,4)(2,3)
source
PermGroups.Groups.elementsMethod

elements(W::CoxeterGroup[,l])

When l is not given this works only if W is finite; it returns the elements of W sorted by increasing Coxeter length. If the second argument is an integer l, the elements of W of Coxeter length l are returned.

julia> W=coxgroup(:G,2)
G₂

julia> e=elements(W,6)
1-element Vector{Perm{Int16}}:
 (1,7)(2,8)(3,9)(4,10)(5,11)(6,12)

julia> e[1]==longest(W)
true
source
PermGroups.Groups.wordsMethod

words(W::CoxeterGroup,w)

returns the list of all reduced expressions of the element w of the Coxeter group W.

julia> W=coxgroup(:A,3)
A₃

julia> words(W,longest(W))
16-element Vector{Vector{Int64}}:
 [1, 2, 1, 3, 2, 1]
 [1, 2, 3, 1, 2, 1]
 [1, 2, 3, 2, 1, 2]
 [1, 3, 2, 1, 3, 2]
 [1, 3, 2, 3, 1, 2]
 [2, 1, 2, 3, 2, 1]
 [2, 1, 3, 2, 1, 3]
 [2, 1, 3, 2, 3, 1]
 [2, 3, 1, 2, 1, 3]
 [2, 3, 1, 2, 3, 1]
 [2, 3, 2, 1, 2, 3]
 [3, 1, 2, 1, 3, 2]
 [3, 1, 2, 3, 1, 2]
 [3, 2, 1, 2, 3, 2]
 [3, 2, 1, 3, 2, 3]
 [3, 2, 3, 1, 2, 3]
source
PermGroups.Groups.wordsMethod

words(W::CoxeterGroup[,l::Integer])

With one argument this works only if W is finite; it returns the reduced Coxeter words of elements of W by increasing length. If the second argument is an integer l, only the elements of length l are returned; this works for infinite Coxeter groups.

julia> W=coxgroup(:G,2)
G₂

julia> e=elements(W,6)
1-element Vector{Perm{Int16}}:
 (1,7)(2,8)(3,9)(4,10)(5,11)(6,12)

julia> e[1]==longest(W)
true
source
Chevie.CoxGroups.bruhatlessFunction

bruhatless(W, x, y)

whether x≤y in the Bruhat order, for x,y∈ W. We have x≤y if a reduced expression for x can be extracted from one for w. See (5.9) and (5.10) Humphreys1990 for properties of the Bruhat order.

julia> W=coxgroup(:H,3)
H₃

julia> w=W(1,2,1,3);

julia> b=filter(x->bruhatless(W,x,w),elements(W));

julia> word.(Ref(W),b)
12-element Vector{Vector{Int64}}:
 []
 [1]
 [2]
 [3]
 [1, 2]
 [2, 1]
 [1, 3]
 [2, 3]
 [1, 2, 1]
 [1, 2, 3]
 [2, 1, 3]
 [1, 2, 1, 3]
source

bruhatless(W, y)

returns a vector whose i-th element is the vector of elements of W smaller for the Bruhat order than w and of Coxeter length i-1. Thus the first element of the returned list contains only one(W) and the length(W,w)-th element contains only w.

julia> W=coxsym(3)
𝔖 ₃

julia> bruhatless(W,Perm(1,3))
4-element Vector{Vector{Perm{Int16}}}:
 [()]
 [(1,2), (2,3)]
 [(1,2,3), (1,3,2)]
 [(1,3)]

see also Poset for Coxeter groups.

source
Chevie.CoxGroups.coxeter_matrixFunction

coxeter_matrix(m::AbstractMatrix) or coxmat

returns the Coxeter matrix of the Coxeter group defined by the cartan matrix m

julia> C=cartan(:H,3)
3×3 Matrix{Cyc{Int64}}:
       2  ζ₅²+ζ₅³   0
 ζ₅²+ζ₅³        2  -1
       0       -1   2

julia> coxmat(C)
3×3 Matrix{Int64}:
 1  5  2
 5  1  3
 2  3  1
source

coxeter_matrix(W) or coxmat

returns the Coxeter matrix of the Coxeter group W, that is the matrix m whose entry m[i,j] contains the order of W(i)*W(j) where W(i) is the i-th Coxeter generator of W. An infinite order is represented by the entry 0.

julia> W=coxsym(4)
𝔖 ₄

julia> coxmat(W)
3×3 Matrix{Int64}:
 1  3  2
 3  1  3
 2  3  1
source

coxeter_matrix(type, rank [,bond]) or coxmat

Like cartan, the function coxmat can be defined from the type and rank of a finite Coxeter group.

source
Chevie.PermRoot.cartanMethod

cartan(M::AbstractMatrix) Cartan matrix from Coxeter matrix

The argument should be the Coxeter matrix M for a Coxeter group W and the result is the Cartan Matrix C for the standard reflection representation of W. We have C[s,t]=-2cos(π/M[s,t]), where M[s,s]==1 and by convention π/M[s,t]==0 if M[s,t]==∞, which we represent by M[s,t]==0. Since M is symmetric, the resulting C is symmetric, meaning that all roots in the constructed reflection representation have same length.

julia> cartan([1 3;3 1])
2×2 Matrix{Cyc{Int64}}:
  2  -1
 -1   2
source
Chevie.CoxGroups.coxeter_symmetric_groupFunction

coxeter_symmetric_group(n::Integer) or coxeter_symmetric_group(m:n) or coxsym

The symmetric group on the letters 1:n (or if a m≤n is given, on the letters m:n) as a Coxeter group. The Coxeter generators are the Perm(i,i+1) for i in m:n-1.

julia> W=coxsym(3)
𝔖 ₃

julia> gens(W)
2-element Vector{Perm{Int16}}:
 (1,2)
 (2,3)

julia> e=elements(W)
6-element Vector{Perm{Int16}}:
 ()
 (1,2)
 (2,3)
 (1,3,2)
 (1,2,3)
 (1,3)

julia> length.(Ref(W),e) # length in the genrators of the elements
6-element Vector{Int64}:
 0
 1
 1
 2
 2
 3
source
Chevie.CoxGroups.coxeter_hyperoctaedral_groupFunction

coxeter_hyperoctaedral_group(n) or coxhyp(n)

The Hyperoctaedral group (the group of all signed permutations of ±1,…,±n) as a Coxeter group of type Bₙ, with generators (1,-1) and (i,i+1)(-i,-i-1).

julia> elements(coxhyp(2))
8-element Vector{SPerm{Int8}}:
 ()
 (1,2)
 (1,-1)
 (1,2,-1,-2)
 (1,-2,-1,2)
 (2,-2)
 (1,-2)
 (1,-1)(2,-2)
source
PermGroups.reducedFunction

reduced(W,w)

The unique element of minimal length in the coset W.w. This makes sense when isleftdescent(W,u) makes sense for u∈ W.w which happens when w is a Coxeter automorphism of W or when w lives in a Coxeter overgroup of W.

julia> W=coxgroup(:G,2)
G₂

julia> H=reflection_subgroup(W,[2,6])
G₂₍₂₆₎=Ã₁×A₁

julia> word.(Ref(W),unique(reduced.(Ref(H),elements(W))))
3-element Vector{Vector{Int64}}:
 []
 [1]
 [1, 2]
source

reduced(H::CoxeterGroup,W::CoxeterGroup,i=nref(W))

The elements w∈ W which are H-reduced, and of length ≤i (by default all of them), grouped by length.

julia> W=coxgroup(:G,2)
G₂

julia> H=reflection_subgroup(W,[2,6])
G₂₍₂₆₎=Ã₁×A₁

julia> [word(W,w) for S in reduced(H,W) for w in S]
3-element Vector{Vector{Int64}}:
 []
 [1]
 [1, 2]
source
Chevie.CoxGroups.standard_parabolic_classFunction

standard_parabolic_class(W,I)

I should be a subset of eachindex(gens(W)). The function returns the list of such subsets W-conjugate to I.

julia> CoxGroups.standard_parabolic_class(coxgroup(:E,8),[7,8])
7-element Vector{Vector{Int64}}:
 [7, 8]
 [6, 7]
 [5, 6]
 [4, 5]
 [2, 4]
 [3, 4]
 [1, 3]
source
Chevie.CoxGroups.coxeter_groupMethod

coxeter_group(m) or coxgroup(m)

m should be a square matrix of real cyclotomic numbers. It returns the Coxeter group whose Cartan matrix is m. This is a matrix group W constructed as follows. Let V be a real vector space of dimension size(m,1), let eᵢ be the canonical basis of V. Then W is the matrix group generated by the reflections sᵢ(eⱼ)=eⱼ-mᵢⱼ eᵢ.

julia> W=coxgroup([2 -2;-2 2])
coxeter_group([2 -2; -2 2])

Above is a way to construct the affine Weyl group Ã₁.

source
FinitePosets.PosetType

Poset(W::CoxeterGroup,w=longest(W))

returns as a poset the Bruhat interval [1,w]of W. If w is not given, the whole Bruhat Poset of W is returned (W must then be finite).

julia> W=coxsym(3)
𝔖 ₃

julia> Poset(W)
.<1,2<21,12<121

The above poset is constructed efficiently by constructing the Hasse diagram, but it could be constructed naively as follows:

julia> p=Poset((x,y)->bruhatless(W,x,y),elements(W))
()<(1,2),(2,3)<(1,3,2),(1,2,3)<(1,3)

The output is not so nice, showing permutations instead of words. This can be fixed by defining:

julia> p.show_element=(io,x,n)->join(io,word(W,x.elements[n]));

julia> p
<1,2<12,21<121

julia> W=coxsym(4)
𝔖 ₄

julia> Poset(W,W(1,3))
.<3,1<13
source