Weyl groups

The Weyl group is generated by simple reflections $s_1, \ldots, s_r$. Elements are stored as reduced words (sequences of generator indices).

Semisimple.jl writes Weyl group actions on the right: λ * x denotes the usual geometric action of x on the weight or root λ. Products are applied in the same order as written in λ * (s1 * s2), matching OSCAR's right-action convention for roots and weights.

Creating the Weyl group

julia> using Semisimple

julia> W = weyl_group(TypeA{3})
Weyl group of type A3

julia> weyl_order(TypeA{3})
24
Semisimple.WeylGroupType
WeylGroup{DT,R}

The Weyl group of a root system of Dynkin type DT with rank R.

Semisimple.jl writes Weyl group actions on the right: λ * x denotes the usual action of the Weyl group element x on the weight or root λ.

Examples

julia> using Semisimple

julia> weyl_order(TypeA{2})
6
source
Semisimple.WeylGroupElemType
WeylGroupElem{DT,R}

An element of the Weyl group, stored as a reduced word (vector of simple reflection indices).

Examples

julia> using Semisimple

julia> W = weyl_group(TypeA{2});

julia> W([1, 2])
s1 * s2
source
Semisimple.weyl_groupFunction
weyl_group(::Type{DT}) -> WeylGroup{DT}

Construct the Weyl group for the given Dynkin type.

Examples

julia> using Semisimple

julia> W = weyl_group(TypeA{2})
Weyl group of type A2
source
Semisimple.weyl_orderFunction
weyl_order(::Type{DT}) -> BigInt

Return the order of the Weyl group of type DT.

Examples

julia> using Semisimple

julia> weyl_order(TypeA{3})
24

julia> weyl_order(TypeE{8})
696729600
source
Semisimple.root_systemFunction
root_system(W::WeylGroup) -> RootSystem

Return the root system underlying the Weyl group W.

Examples

julia> using Semisimple

julia> root_system(weyl_group(TypeA{2}))
Root system of type A2, rank 2 with 3 positive roots
source

Generators and multiplication

julia> s1 = gen(W, 1)
s1

julia> s2 = gen(W, 2)
s2

julia> s1 * s2
s1 * s2

julia> word(s1)
1-element Vector{UInt8}:
 0x01

julia> word(s1 * s2)
2-element Vector{UInt8}:
 0x01
 0x02

Longest element

The longest element $w_0$ has maximal length in the Weyl group:

julia> w0 = longest_element(W)
s1 * s2 * s1 * s3 * s2 * s1

julia> length(word(w0))
6
Semisimple.gensFunction
gens(W::WeylGroup) -> Vector{WeylGroupElem}

Return all simple reflections.

Examples

julia> using Semisimple

julia> gens(weyl_group(TypeA{2}))
2-element Vector{WeylGroupElem{TypeA{2}, 2}}:
 s1
 s2
source
Semisimple.genFunction
gen(W::WeylGroup, i) -> WeylGroupElem

Return the i-th simple reflection.

Examples

julia> using Semisimple

julia> gen(weyl_group(TypeA{2}), 1)
s1
source
Semisimple.longest_elementFunction
longest_element(W::WeylGroup{DT,R}) -> WeylGroupElem{DT,R}

Compute the longest element w0 of the Weyl group. Uses the iterative algorithm: repeatedly find a simple reflection that increases length. The result is cached per Dynkin type.

Examples

julia> using Semisimple

julia> W = weyl_group(TypeA{2});

julia> w0 = longest_element(W);

julia> length(w0)
3
source
Semisimple.wordFunction
word(x::WeylGroupElem) -> Vector{UInt8}

Return the reduced word of x.

Examples

julia> using Semisimple

julia> W = weyl_group(TypeA{2});

julia> word(W([1, 2]))
2-element Vector{UInt8}:
 0x01
 0x02
source
Base.oneMethod
one(W::WeylGroup) -> WeylGroupElem

Return the identity element.

Examples

julia> using Semisimple

julia> one(weyl_group(TypeA{2}))
id
source
Base.lengthMethod
Base.length(x::WeylGroupElem) -> Int

Return the length (number of simple reflections) of x.

source
Semisimple.rmul!Function
rmul!(x::WeylGroupElem, s::UInt8) -> WeylGroupElem

Multiply x from the right by the simple reflection s, maintaining the reduced word in short-lex normal form.

Uses the reflection table from the root system.

source

Action on weights

The Weyl group acts on the weight lattice. Right multiplication corresponds to the geometric reflection:

julia> ω1 = fundamental_weight(TypeA{3}, 1);

julia> ω1 * s1   # s1(ω1) = -ω1 + ω2
-ω1 + ω2

julia> ω1 * s2   # s2(ω1) = ω1 (orthogonal)
ω1
Base.:*Method
*(w::WeightLatticeElem{DT,R}, x::WeylGroupElem{DT,R}) -> WeightLatticeElem{DT,R}

Right action of a Weyl group element on a weight.

source

Action on roots

julia> RS = RootSystem(TypeA{3});

julia> α1 = simple_root(RS, 1);

julia> α1 * s1   # s1(α1) = -α1
-α1

julia> α1 * s2   # s2(α1) = α1 + α2
α1 + α2
Base.:*Method
*(r::RootSpaceElem{DT,R}, x::WeylGroupElem{DT,R}) -> RootSpaceElem{DT,R}

Right action of a Weyl group element on a root space element.

source

Weyl orbits

The orbit of a weight under the full Weyl group:

julia> orbit = weyl_orbit(TypeA{3}, ω1);

julia> length(orbit)   # |W/Stab(ω1)| = 4 for std rep of A3
4

For the adjoint representation of $\mathrm{A}_2$:

julia> ω = fundamental_weight(TypeA{2}, 1) + fundamental_weight(TypeA{2}, 2);

julia> length(weyl_orbit(TypeA{2}, ω))
6
Semisimple.weyl_orbitFunction
weyl_orbit(::Type{DT}, w::WeightLatticeElem{DT,R}) -> Vector{WeightLatticeElem{DT,R}}

Compute the full Weyl orbit of the weight w.

Examples

julia> using Semisimple

julia> length(weyl_orbit(TypeA{2}, fundamental_weight(TypeA{2}, 1)))
3
source

Dominant weights

All dominant weights $\mu \leq \lambda$ (in the dominance order):

julia> ω2 = fundamental_weight(TypeA{3}, 2);

julia> dw = dominant_weights(TypeA{3}, ω1 + ω2);

julia> length(dw)
2
Semisimple.dominant_weightsFunction
dominant_weights(::Type{DT}, hw::WeightLatticeElem{DT,R}) -> Vector{WeightLatticeElem{DT,R}}

Compute the dominant weights occurring in the irreducible representation with highest weight hw, sorted by decreasing level below hw.

The level of μ below hw is the root-lattice height of hw - μ, i.e. the sum of coefficients when hw - μ is written in the simple root basis.

Examples

julia> using Semisimple

julia> λ = fundamental_weight(TypeA{2}, 1) + fundamental_weight(TypeA{2}, 2);

julia> length(dominant_weights(λ))
2
source

Weyl dimension formula

The dimension of the irreducible representation $\mathrm{V}(\lambda)$:

julia> degree(ω1)   # standard rep of A3 (SL4)
4

julia> degree(ω2)   # ⋀² of standard = 6-dim
6

julia> degree(ω1 + ω2)   # 20-dim rep
20

julia> degree(weyl_vector(TypeA{3}))   # ρ = ω1+ω2+ω3
64

A₂ examples:

julia> ω1_a2 = fundamental_weight(TypeA{2}, 1);

julia> degree(ω1_a2)
3

julia> degree(ω1_a2 + fundamental_weight(TypeA{2}, 2))   # adjoint
8

The zero weight gives the trivial representation:

julia> degree(WeightLatticeElem(TypeA{3}, [0, 0, 0]))
1
Semisimple.degreeFunction
degree(::Type{DT}, hw::WeightLatticeElem{DT,R}) -> BigInt
degree(hw::WeightLatticeElem{DT,R}) -> BigInt

Dimension of the irreducible representation with highest weight hw, computed via the Weyl dimension formula:

$\dim \mathrm{V}(λ) = \prod_{α > 0} \frac{⟨λ + ρ, α^\vee⟩}{⟨ρ, α^\vee⟩}$

Equivalently, using the invariant bilinear form, $\prod_{α>0} (λ+ρ,α)/(ρ,α)$.

The denominator and the symmetrizer-scaled root vectors are precomputed once per Dynkin type. The numerator is computed as a BigInt product of Int-valued inner products via in-place GMP arithmetic.

Examples

julia> using Semisimple

julia> degree(fundamental_weight(TypeA{3}, 1))
4

julia> degree(fundamental_weight(TypeB{3}, 3))
8

julia> degree(fundamental_weight(TypeE{8}, 8))
248

julia> [degree(fundamental_weight(TypeB{3}, i)) for i in 1:3]
3-element Vector{BigInt}:
  7
 21
  8
source
degree(::Type{DT}, v::AbstractVector{<:Integer}) -> BigInt

Dimension of the irreducible representation with highest weight given by the integer vector v (in the fundamental weight basis).

This is a convenience wrapper: degree(DT, v) == degree(WeightLatticeElem(DT, v)).

Examples

julia> using Semisimple

julia> degree(TypeA{2}, [1, 0])  # standard representation of A2
3

julia> degree(TypeE{8}, [0, 0, 0, 0, 0, 0, 0, 1])  # adjoint of E8
248
source
degree(V::WeylCharacter) -> BigInt

Return the (signed) dimension of a character in the representation ring.

For a virtual character V = ∑ mᵢ V(λᵢ) (with mᵢ possibly negative), returns:

deg(V) = ∑ mᵢ dim(V(λᵢ))

For effective characters (all mᵢ ≥ 0) this equals the total dimension of the corresponding representation. For virtual characters (some mᵢ < 0) the result can be negative or zero; this is the Euler characteristic in the representation ring.

Returns a BigInt.

Examples

julia> using Semisimple

julia> ω1 = fundamental_weight(TypeA{2}, 1);

julia> V = WeylCharacter(ω1);

julia> degree(V)  # dim of standard representation
3

julia> degree(V^2)  # dim of V ⊗ V = Sym²V ⊕ ⋀²V
9

julia> degree(Sym(2, V))  # dim of Sym²V
6

julia> # Virtual character: V(ω1) - V(ω2) has degree 0 (both dim 3)
       degree(V - WeylCharacter(fundamental_weight(TypeA{2}, 2)))
0

julia> ω8 = fundamental_weight(TypeE{8}, 8);

julia> degree(WeylCharacter(ω8))
248
source
Semisimple.weyl_dimensionFunction
weyl_dimension(λ::WeightLatticeElem) -> BigInt
weyl_dimension(::Type{DT}, λ::WeightLatticeElem) -> BigInt
weyl_dimension(::Type{DT}, v::AbstractVector{<:Integer}) -> BigInt
weyl_dimension(dt::DynkinType, v) -> BigInt

Synonym for degree. Computes the dimension of the irreducible representation via the Weyl dimension formula.

source

Borel–Weil–Bott theorem

Compute the cohomological degree and resulting representation for a weight on a flag variety:

julia> import Semisimple: _borel_weil_bott

julia> _borel_weil_bott(ω1)   # dominant weight → degree 0
(0, ω1)

julia> _borel_weil_bott(WeightLatticeElem(TypeA{3}, [-3, 2, 1]))
(1, ω1 + ω3)

Singular weights give zero cohomology, and _borel_weil_bott returns nothing:

julia> _borel_weil_bott(-weyl_vector(TypeA{3})) === nothing
true
Note

_borel_weil_bott is internal: the leading underscore marks it as neither exported nor covered by semantic versioning. It is rather a feature for PartialFlagVarieties.jl, which builds it out of the exported conjugate_dominant_weight_with_length.

Semisimple._borel_weil_bottFunction
_borel_weil_bott(λ::WeightLatticeElem{DT,R}, nodes=1:R) -> Union{Nothing, Tuple{Int, WeightLatticeElem{DT,R}}}

Apply the Borel–Weil–Bott theorem to the weight λ.

Internal

The leading underscore marks this as internal: it is not exported, not part of the public API of Semisimple.jl, and not covered by semantic versioning. The theorem properly belongs to PartialFlagVarieties.jl, which builds it out of the exported conjugate_dominant_weight_with_length; this implementation is kept here only to exercise the restricted fold from the tests.

Compute μ = λ + ρ and find the unique Weyl group element w such that w(μ) is dominant. If μ is singular (lies on a Weyl chamber wall), all cohomology vanishes and we return nothing. Otherwise, return (d, w(μ) - ρ) where d = ℓ(w) is the cohomological degree, meaning

$\mathrm{H}^d(G/B, \mathcal{L}_λ) \cong \mathrm{V}_{w(μ)-ρ}^*$

and all other cohomology groups vanish.

Passing nodes restricts both the reflections and the singularity test to the root subsystem spanned by $S$ = nodes, so w is sought in $\mathrm{W}_S$. This is the relative statement along a projection of flag varieties, the higher direct images of $\mathcal{L}_λ$ along $\mathrm{G}/\mathrm{B} \to \mathrm{G}/\mathrm{P}_I$ with nodes the nodes unmarked in $I$: taking nodes to be all of them recovers the absolute statement. Note that $ρ = ρ_{\mathrm{G}}$ remains the right shift, because $ρ_{\mathrm{G}} - ρ_S$ pairs to zero with every coroot in $S$ and is therefore $\mathrm{W}_S$-invariant.

Examples

julia> using Semisimple; import Semisimple: _borel_weil_bott

julia> _borel_weil_bott(fundamental_weight(TypeA{2}, 1))
(0, ω1)

julia> _borel_weil_bott(WeightLatticeElem(TypeA{2}, [-2, 1]))
(1, 0)

julia> _borel_weil_bott(-weyl_vector(TypeA{2})) === nothing
true

The same weight, but reflecting only in the second node: it is already dominant there, so it stays put in degree zero.

julia> using Semisimple; import Semisimple: _borel_weil_bott

julia> _borel_weil_bott(WeightLatticeElem(TypeA{2}, [-2, 1]), (2,))
(0, -2ω1 + ω2)

julia> _borel_weil_bott(-weyl_vector(TypeA{2}), (2,)) === nothing   # singular for s2 too
true
source

Singular weights

A weight $\lambda$ is singular when $\langle \lambda + \rho, \alpha^\vee \rangle = 0$ for some positive root $\alpha$. Singular weights give zero cohomology:

julia> λ = WeightLatticeElem(TypeA{2}, [-1, 0]);

julia> is_singular(λ)
true
Semisimple.is_singularFunction
is_singular(w::WeightLatticeElem{DT,R}, nodes=1:R) -> Bool

Check whether the weight w is singular, i.e. lies on some wall of a Weyl chamber. Equivalently, w is singular iff ⟨α∨, w⟩ = 0 for some positive root α.

For a dominant weight this simplifies to checking whether any fundamental weight coordinate is zero. For a general weight, we first conjugate to the dominant chamber.

Passing nodes restricts the question to the root subsystem spanned by $S$ = nodes, as in conjugate_dominant_weight: the result is then whether $⟨α^\vee, w⟩ = 0$ for some positive root $α$ of that subsystem. This is the vanishing criterion of the relative _borel_weil_bott.

Examples

julia> using Semisimple

julia> is_singular(fundamental_weight(TypeA{2}, 1))
true

julia> is_singular(weyl_vector(TypeA{2}))
false

For the subsystem spanned by the second node the only positive root is $α_2$, so singularity is decided by the pairing with $α_2^\vee$ alone:

julia> using Semisimple

julia> is_singular(fundamental_weight(TypeA{2}, 1), (2,))
true

julia> is_singular(fundamental_weight(TypeA{2}, 2), (2,))
false
source

Bruhat order and descent sets

The Bruhat order on the Weyl group is a partial order defined by subword inclusion in reduced expressions. Descent sets record which simple reflections reduce the word length.

julia> s3 = gen(W, 3)
s3

julia> x = s1 * s2;

julia> right_descent_set(x)
1-element Vector{Int64}:
 2

julia> bruhat_leq(s1, x)
true

julia> bruhat_leq(x, s1)
false
Semisimple.right_descent_setFunction
right_descent_set(w::WeylGroupElem) -> Vector{Int}

Return the right descent set of w, i.e. the indices i such that \ell(ws_i) < \ell(w).

Examples

julia> using Semisimple

julia> W = weyl_group(TypeA{2});

julia> right_descent_set(W([1, 2]))
1-element Vector{Int64}:
 2
source
Semisimple.left_descent_setFunction
left_descent_set(w::WeylGroupElem) -> Vector{Int}

Return the left descent set of w, i.e. the indices i such that \ell(s_iw) < \ell(w).

Examples

julia> using Semisimple

julia> W = weyl_group(TypeA{2});

julia> left_descent_set(W([1, 2]))
1-element Vector{Int64}:
 1
source
Semisimple.bruhat_leqFunction
bruhat_leq(x::WeylGroupElem, y::WeylGroupElem) -> Bool

Return whether x \le y in the (strong) Bruhat order.

Examples

julia> using Semisimple

julia> W = weyl_group(TypeA{2});

julia> bruhat_leq(gen(W, 1), W([1, 2]))
true
source
Semisimple.bruhat_descendantsFunction
bruhat_descendants(w::WeylGroupElem) -> Vector{WeylGroupElem}

Return the immediate Bruhat descendants obtained by right-multiplying by simple reflections in the right descent set.

Examples

julia> using Semisimple

julia> W = weyl_group(TypeA{2});

julia> bruhat_descendants(W([1, 2]))
1-element Vector{WeylGroupElem{TypeA{2}, 2}}:
 s1
source

Parabolic subgroups and coset representatives

For a subset $I \subseteq \{1,\ldots,r\}$ of simple root indices, the parabolic subgroup $W_I$ is generated by $\{s_i : i \in I\}$. The minimal-length coset representatives for $W/W_I$ are the elements whose right descent sets are disjoint from $I$.

julia> reps = right_coset_reps(W, [1]);  # W/⟨s1⟩ for A3

julia> length(reps)   # |A3|/|A1×A1 ... actually just |W|/|W_{1}| = 24/2 = 12
12

julia> all(w -> !(1 in right_descent_set(w)), reps)
true
Semisimple.right_coset_repsFunction
right_coset_reps(W::WeylGroup, I::AbstractVector{<:Integer}) -> Vector{WeylGroupElem}

Enumerate minimal right coset representatives for W/W_I, where W_I is the parabolic subgroup generated by simple reflections in I.

Uses a weight-orbit BFS: the weight $λ_I = \sum_{j \notin I} ω_j$ has stabilizer exactly $W_I$, so its $W$-orbit has size $|W/W_I|$. Enumerates that orbit using $O(|W/W_I| \cdot R)$ weight reflections, independent of $|W|$.

Examples

julia> using Semisimple

julia> length(right_coset_reps(weyl_group(TypeA{2}), [1]))
3
source
Semisimple.left_coset_repsFunction
left_coset_reps(W::WeylGroup, I::AbstractVector{<:Integer}) -> Vector{WeylGroupElem}

Enumerate minimal left coset representatives for W_I\W.

Examples

julia> using Semisimple

julia> length(left_coset_reps(weyl_group(TypeA{2}), [1]))
3
source

Weyl group orders

julia> weyl_order(TypeA{3})
24

julia> weyl_order(TypeB{3})
48

julia> weyl_order(TypeG2)
12

julia> weyl_order(TypeE{8})
696729600