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})
24Semisimple.WeylGroup — Type
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})
6Semisimple.WeylGroupElem — Type
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 * s2Semisimple.weyl_group — Function
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 A2Semisimple.weyl_order — Function
weyl_order(::Type{DT}) -> BigIntReturn the order of the Weyl group of type DT.
Examples
julia> using Semisimple
julia> weyl_order(TypeA{3})
24
julia> weyl_order(TypeE{8})
696729600Semisimple.root_system — Function
root_system(W::WeylGroup) -> RootSystemReturn 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 rootsGenerators 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
0x02Longest 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))
6Semisimple.gens — Function
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
s2Semisimple.gen — Function
gen(W::WeylGroup, i) -> WeylGroupElemReturn the i-th simple reflection.
Examples
julia> using Semisimple
julia> gen(weyl_group(TypeA{2}), 1)
s1Semisimple.longest_element — Function
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)
3Semisimple.word — Function
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
0x02Base.length — Method
Base.length(x::WeylGroupElem) -> IntReturn the length (number of simple reflections) of x.
Semisimple.rmul! — Function
rmul!(x::WeylGroupElem, s::UInt8) -> WeylGroupElemMultiply 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.
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)
ω1Action 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 + α2Weyl 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
4For the adjoint representation of $\mathrm{A}_2$:
julia> ω = fundamental_weight(TypeA{2}, 1) + fundamental_weight(TypeA{2}, 2);
julia> length(weyl_orbit(TypeA{2}, ω))
6Semisimple.weyl_orbit — Function
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)))
3Dominant 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)
2Semisimple.dominant_weights — Function
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(λ))
2Weyl 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
64A₂ examples:
julia> ω1_a2 = fundamental_weight(TypeA{2}, 1);
julia> degree(ω1_a2)
3
julia> degree(ω1_a2 + fundamental_weight(TypeA{2}, 2)) # adjoint
8The zero weight gives the trivial representation:
julia> degree(WeightLatticeElem(TypeA{3}, [0, 0, 0]))
1Semisimple.degree — Function
degree(::Type{DT}, hw::WeightLatticeElem{DT,R}) -> BigInt
degree(hw::WeightLatticeElem{DT,R}) -> BigIntDimension 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
8degree(::Type{DT}, v::AbstractVector{<:Integer}) -> BigIntDimension 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
248degree(V::WeylCharacter) -> BigIntReturn 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))
248Semisimple.weyl_dimension — Function
weyl_dimension(λ::WeightLatticeElem) -> BigInt
weyl_dimension(::Type{DT}, λ::WeightLatticeElem) -> BigInt
weyl_dimension(::Type{DT}, v::AbstractVector{<:Integer}) -> BigInt
weyl_dimension(dt::DynkinType, v) -> BigIntSynonym for degree. Computes the dimension of the irreducible representation via the Weyl dimension formula.
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_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_bott — Function
_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 λ.
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
trueThe 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
trueSingular 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(λ)
trueSemisimple.is_singular — Function
is_singular(w::WeightLatticeElem{DT,R}, nodes=1:R) -> BoolCheck 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}))
falseFor 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,))
falseBruhat 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)
falseSemisimple.right_descent_set — Function
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}:
2Semisimple.left_descent_set — Function
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}:
1Semisimple.bruhat_leq — Function
bruhat_leq(x::WeylGroupElem, y::WeylGroupElem) -> BoolReturn 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]))
trueSemisimple.bruhat_descendants — Function
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}}:
s1Parabolic 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)
trueSemisimple.right_coset_reps — Function
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]))
3Semisimple.left_coset_reps — Function
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]))
3Weyl 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