Characters and representations
A WeylCharacter is an element of the representation ring (Grothendieck ring) of a semisimple Lie algebra. It stores a formal $\mathbb{Z}$-linear combination of irreducible representations, indexed by their dominant highest weights.
Constructing characters
julia> using Semisimple, StaticArrays
julia> ω1 = fundamental_weight(TypeA{3}, 1);
julia> ω2 = fundamental_weight(TypeA{3}, 2);
julia> V = WeylCharacter(ω1) # irreducible V(ω1)
A3(1, 0, 0)
julia> WeylCharacter(TypeA{3}) # zero character (additive identity)
0
julia> is_effective(V)
true
julia> is_irreducible(V)
true
julia> highest_weight(V)
ω1Semisimple.WeylCharacter — Type
WeylCharacter{DT,R}An element of the representation ring (Grothendieck ring) of a semisimple Lie algebra of Dynkin type DT with rank R.
Computationally, this is stored as a Dict{WeightLatticeElem{DT,R}, Int} mapping dominant highest weights to irreducible multiplicities. Positive multiplicities correspond to actual representations; negative multiplicities arise in virtual differences.
This is distinct from the full weight-multiplicity character returned by freudenthal_formula and the dominant-representative weight multiplicity dictionary returned by dominant_character.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1);
julia> V = WeylCharacter(ω1)
A2(1, 0)
julia> V + V == 2 * V
trueSemisimple.is_effective — Function
is_effective(V::WeylCharacter) -> BoolTrue when all multiplicities are non-negative, i.e. V corresponds to an actual (not merely virtual) representation.
Examples
julia> using Semisimple
julia> V = WeylCharacter(fundamental_weight(TypeA{2}, 1));
julia> is_effective(V - 2V)
false
julia> is_effective(V - V)
trueSemisimple.is_irreducible — Function
is_irreducible(V::WeylCharacter) -> BoolTrue when V is a single irreducible with multiplicity 1.
Examples
julia> using Semisimple
julia> V = WeylCharacter(fundamental_weight(TypeA{2}, 1));
julia> is_irreducible(V)
true
julia> is_irreducible(2V)
falseSemisimple.highest_weight — Function
highest_weight(V::WeylCharacter{DT,R}) -> WeightLatticeElem{DT,R}Return the highest weight of an irreducible virtual character. Throws if V is not irreducible.
Examples
julia> using Semisimple
julia> V = WeylCharacter(fundamental_weight(TypeA{2}, 1));
julia> highest_weight(V)
ω1Arithmetic
Characters support addition, subtraction, and scalar multiplication:
julia> V2 = WeylCharacter(ω2);
julia> V + V2
A3(1, 0, 0) + A3(0, 1, 0)
julia> 2 * V
2*A3(1, 0, 0)
julia> V + V == 2 * V
trueCharacters also support multiplication (tensor product) and exponentiation (tensor power):
julia> V * V2 == tensor_product(V, V2)
true
julia> V^3 == V * V * V
trueBase.:^ — Method
^(V::WeylCharacter, n::Integer) -> WeylCharacterCompute the n-th tensor power of V.
Algorithm choice: uses right-to-left sequential multiplication V ⊗ (V ⊗ (V ⊗ ⋯)) rather than repeated squaring.
With Brauer–Klimyk, the cost of A ⊗ B is proportional to |A| × Weyl-orbit-size(B) (or vice versa). Sequential multiplication keeps one factor always equal to the original small V, so every step is O(|V| × orbit_size(V^{r−1})). Repeated squaring would let both factors grow: the intermediate result V^{n/2} can be much larger than V itself, making each squaring step significantly more expensive.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1);
julia> V = WeylCharacter(ω1);
julia> V^2 == tensor_product(ω1, ω1)
true
julia> V^0 == WeylCharacter(zero(ω1))
trueIn-place mutation
For performance-critical loops, use add! and addmul!:
julia> result = WeylCharacter(TypeA{3});
julia> add!(result, V);
julia> result
A3(1, 0, 0)
julia> addmul!(result, V2, 3);
julia> result
A3(1, 0, 0) + 3*A3(0, 1, 0)Semisimple.add! — Function
add!(V::WeylCharacter{DT,R}, W::WeylCharacter{DT,R}) -> WeylCharacter{DT,R}Add W into V in-place, modifying V. Returns V.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1);
julia> V = WeylCharacter(ω1); W = WeylCharacter(ω1);
julia> add!(V, W) == 2 * WeylCharacter(ω1)
trueSemisimple.addmul! — Function
addmul!(V::WeylCharacter{DT,R}, W::WeylCharacter{DT,R}, c::Integer) -> WeylCharacter{DT,R}Add c * W into V in-place, modifying V. Returns V.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1);
julia> V = WeylCharacter(TypeA{2}); W = WeylCharacter(ω1);
julia> addmul!(V, W, 3) == 3 * WeylCharacter(ω1)
trueCharacter data terminology
Semisimple.jl uses three related but distinct character representations:
| Name | Julia representation | Meaning |
|---|---|---|
WeylCharacter | Dict{WeightLatticeElem,Int} in the terms field | irreducible decomposition in the representation ring |
| Full weight character | Dict{SVector{R,Int},Int} from freudenthal_formula | multiplicity of every weight |
| Dominant character | Dict{SVector{R,Int},Int} from dominant_character | multiplicity on dominant representatives of Weyl orbits |
Character polynomials
A character polynomial of a finite-dimensional representation is a formal sum
\[\chi(\lambda) = \sum_{\mu \in P} m_\lambda(\mu) e^\mu\]
where $P$ is the weight lattice, $m_\lambda(\mu)$ is the multiplicity of weight $\mu$ in the representation with highest weight $\lambda$, and $e^\mu$ is a formal exponential. This encodes the weight multiplicities in a single object that respects the representation ring structure (tensor product → multiplication of characters).
Since character polynomials are Weyl group invariant (i.e., $\chi_\lambda(w \cdot \mu) = \chi_\lambda(\mu)$ for all $w \in W$), the full character is determined by its values on dominant weights. More precisely: each weight orbit under the Weyl group contains exactly one dominant weight, and all weights in an orbit have equal multiplicity.
julia> ω1_a2 = fundamental_weight(TypeA{2}, 1);
julia> full_mults = freudenthal_formula(ω1_a2);
julia> length(full_mults) # includes all W-orbit members
3
julia> dom_mults = dominant_character(ω1_a2);
julia> length(dom_mults) # only dominant weights
1Dominant character polynomials
The dominant character polynomial (or sometimes just "dominant character") is a more compact representation:
\[\chi_{\lambda, \text{dom}} = \sum_{\mu \in P^+ : m_\lambda(\mu) > 0} m_\lambda(\mu) e^\mu\]
where $P^+$ is the set of dominant weights. By W-invariance, this omits all non-dominant weights while retaining all information about the full character.
Explicitly: since each W-orbit contains a unique dominant representative, reconstructing the full character from the dominant character is straightforward — just apply the Weyl group orbit operator. This is what freudenthal_formula does internally.
dominant_character computes this using Freudenthal's recursion formula and returns a Dict{SVector{R,Int}, Int} mapping dominant weight coordinates to multiplicities. This is the cached building block behind freudenthal_formula, weight_multiplicity, tensor products, Adams operators, and plethysms.
This dominant character corresponds to the domchar output in LiE.
julia> ω1_a2 = fundamental_weight(TypeA{2}, 1);
julia> dc = dominant_character(ω1_a2);
julia> length(dc) # only 1 dominant weight for V(ω1) of A2
1
julia> dc[SVector(1, 0)] # the highest weight itself
1Semisimple.dominant_character — Function
dominant_character(λ::WeightLatticeElem{DT,R}) -> Dict{SVector{R,Int}, BigInt}Compute the dominant character of the irreducible representation $\mathrm{V}(λ)$ using Freudenthal's recursion.
The result records the weight multiplicity on the unique dominant representative of each Weyl orbit of weights in $\mathrm{V}(λ)$. It is a compact form of the full weight character, not an irreducible decomposition.
This function computes the dominant character using Freudenthal's recursion formula and returns a Dict{SVector{R,Int}, BigInt} with dominant weight coordinates as keys and multiplicities as values. Multiplicities are stored as BigInt because the Freudenthal recursion accumulates intermediates that exceed typemax(Int64) for large representations such as $\mathrm{V}(ρ)$ of E₈.
Results are cached per highest weight; clear with clear_all_caches!.
Expanding the dominant character:
- Use
freudenthal_formulato expand the dominant character into the full character polynomial (all W-orbit members listed with their multiplicities). - Use
weight_multiplicityto query the multiplicity of a single weight without computing the entire W-orbit.
Examples
julia> using Semisimple; using StaticArrays
julia> ω1 = fundamental_weight(TypeA{2}, 1);
julia> dc = dominant_character(ω1);
julia> length(dc) # V(ω1) of A2 has 1 dominant weight
1
julia> dc[SVector(1, 0)] # multiplicity of ω1 itself
1
julia> adj = ω1 + fundamental_weight(TypeA{2}, 2);
julia> dc_adj = dominant_character(adj);
julia> dc_adj[SVector(0, 0)] # zero weight multiplicity in adjoint
2Freudenthal's formula
Compute the full weight multiplicity dictionary of an irreducible representation $\mathrm{V}(\lambda)$. Returns a Dict{SVector{R,Int}, Int} mapping weight coordinates (in the fundamental weight basis) to their multiplicities:
julia> m = freudenthal_formula(ω1);
julia> length(m) # V(ω1) of A3 has 4 weights
4
julia> sum(values(m)) == degree(ω1) # total = dimension
trueThe convenience function weight_multiplicity returns the multiplicity of a single weight. For example, the $\mathrm{A}_2$ adjoint representation $\mathrm{V}(\omega_1 + \omega_2)$ has dimension 8, and the zero weight has multiplicity 2:
julia> adj = fundamental_weight(TypeA{2}, 1) + fundamental_weight(TypeA{2}, 2);
julia> weight_multiplicity(adj, zero(adj))
2Semisimple.freudenthal_formula — Function
freudenthal_formula(λ::WeightLatticeElem{DT,R}) -> Dict{SVector{R,Int}, BigInt}Compute the full weight multiplicity dictionary of the irreducible representation $\mathrm{V}(λ)$.
Returns a dictionary mapping every weight (in fundamental weight coordinates) to its multiplicity. Only weights with non-zero multiplicity are included.
Multiplicities are returned as BigInt because they can exceed typemax(Int64) for large representations (e.g. $\mathrm{V}(ρ)$ of E₈).
Internally, this calls dominant_character to compute multiplicities of dominant weights via Freudenthal's recursion, then expands each dominant weight to its full Weyl orbit.
Examples
julia> using Semisimple; using StaticArrays
julia> ω1 = fundamental_weight(TypeA{2}, 1);
julia> mults = freudenthal_formula(ω1);
julia> mults[SVector(1, 0)]
1
julia> sum(values(mults)) # = dim V(ω1) = 3
3
julia> ω2 = fundamental_weight(TypeA{2}, 2);
julia> mults = freudenthal_formula(ω1 + ω2); # adjoint of A2
julia> length(mults) # 7 distinct weights
7
julia> sum(values(mults)) # dim = 8
8Semisimple.weight_multiplicity — Function
weight_multiplicity(λ::WeightLatticeElem{DT,R}, μ::WeightLatticeElem{DT,R}) -> BigIntReturn the multiplicity of weight μ in the irreducible representation $\mathrm{V}(λ)$. This is a convenience wrapper around freudenthal_formula. The return type is BigInt because multiplicities in large representations (e.g. $\mathrm{V}(ρ)$ of E₈) can exceed typemax(Int64).
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1); ω2 = fundamental_weight(TypeA{2}, 2);
julia> weight_multiplicity(ω1 + ω2, zero(ω1)) # zero weight of adjoint
2Tensor products
Brauer–Klimyk (general)
The default tensor product algorithm works for all types:
julia> tensor_product(ω1, ω1) # V ⊗ V = Sym²V ⊕ ⋀²V
A3(2, 0, 0) + A3(0, 1, 0)
julia> tensor_product(ω1, ω2)
A3(1, 1, 0) + A3(0, 0, 1)Tensor product of a weight with the trivial representation:
julia> ω3 = fundamental_weight(TypeA{3}, 3);
julia> tensor_product(ω1, ω3) # V(ω1) ⊗ V(ω3) contains trivial
A3(1, 0, 1) + A3(0, 0, 0)Littlewood–Richardson (type A)
For type A, the Littlewood–Richardson rule provides a faster tensor product algorithm. It is used automatically by tensor_product for type A inputs:
julia> ω1_a4 = fundamental_weight(TypeA{4}, 1);
julia> ω2_a4 = fundamental_weight(TypeA{4}, 2);
julia> lr_tensor_product(ω1_a4, ω2_a4)
A4(1, 1, 0, 0) + A4(0, 0, 1, 0)julia> λ = WeightLatticeElem(TypeA{4}, [2, 1, 0, 0]);
julia> r = tensor_product(λ, λ);
julia> length(r.terms) # number of irreducible components
11
julia> sum(m * degree(μ) for (μ, m) in r.terms) == degree(λ)^2
trueSemisimple.tensor_product — Function
tensor_product(V::WeylCharacter{DT,R}, W::WeylCharacter{DT,R}) -> WeylCharacter{DT,R}Tensor product decomposition of two virtual characters. Iterates over all pairs (λ, m) in V and (μ, n) in W, computes tensor_product(λ, μ) via Brauer–Klimyk, and accumulates m * n * result.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1);
julia> V = WeylCharacter(ω1);
julia> V * V == Sym(2, V) + ⋀(2, V)
true
julia> V^3 # right-to-left tensor power
A2(3, 0) + 2*A2(1, 1) + A2(0, 0)tensor_product(λ::WeightLatticeElem{DT,R}, μ::WeightLatticeElem{DT,R}) -> WeylCharacter{DT,R}Decompose the tensor product $\mathrm{V}(λ) \otimes \mathrm{V}(μ)$ into irreducibles using the Brauer–Klimyk algorithm. The Freudenthal formula is applied to whichever factor has smaller dimension, for efficiency.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1); ω2 = fundamental_weight(TypeA{2}, 2);
julia> tensor_product(ω1, ω1)
A2(2, 0) + A2(0, 1)
julia> ω1 = fundamental_weight(TypeA{3}, 1); tensor_product(ω1, ω1)
A3(2, 0, 0) + A3(0, 1, 0)tensor_product(λ::WeightLatticeElem{TypeA{N},N}, μ::WeightLatticeElem{TypeA{N},N}) -> WeylCharacter{TypeA{N},N}Specialization for type $\mathrm{A}$: uses the Littlewood–Richardson rule instead of Brauer–Klimyk, which is typically much faster.
Semisimple.lr_tensor_product — Function
lr_tensor_product(λ::WeightLatticeElem{TypeA{N},N}, μ::WeightLatticeElem{TypeA{N},N}) -> WeylCharacter{TypeA{N},N}Decompose $\mathrm{V}(λ) \otimes \mathrm{V}(μ)$ into irreducibles using the Littlewood–Richardson rule. This is specific to type $\mathrm{A}$ and is typically much faster than the general Brauer–Klimyk algorithm.
The algorithm converts highest weights to partitions, enumerates LR skew tableaux of shape $ν / α$ with content $β$ (where $α$ and $β$ are the partitions for $λ$ and $μ$), and reads off the multiplicities $c^ν_{αβ}$.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1); ω2 = fundamental_weight(TypeA{2}, 2);
julia> lr_tensor_product(ω1, ω1)
A2(2, 0) + A2(0, 1)
julia> lr_tensor_product(ω1, ω2)
A2(1, 1) + A2(0, 0)
julia> lr_tensor_product(ω1 + ω2, ω1) # 8 ⊗ 3 in A2
A2(2, 1) + A2(1, 0) + A2(0, 2)Duality
The dual (contragredient) representation:
julia> dual(WeylCharacter(ω1))
A3(0, 0, 1)
julia> dual(WeylCharacter(ω3))
A3(1, 0, 0)
julia> dual(WeylCharacter(ω2)) # self-dual for A3
A3(0, 1, 0)Semisimple.dual — Function
dual(λ::WeightLatticeElem{DT,R}) -> WeightLatticeElem{DT,R}Highest weight of the contragredient (dual) representation: λ* = -w₀(λ).
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1); ω2 = fundamental_weight(TypeA{2}, 2);
julia> dual(ω1) == ω2
true
julia> [dual(fundamental_weight(TypeA{3}, i)) for i in 1:3]
3-element Vector{WeightLatticeElem{TypeA{3}, 3}}:
ω3
ω2
ω1dual(V::WeylCharacter{DT,R}) -> WeylCharacter{DT,R}Dual of a virtual character: each summand $\mathrm{V}(λ)$ maps to $\mathrm{V}(λ^*)$.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1);
julia> dual(WeylCharacter(ω1))
A2(0, 1)Adams operators
The Adams operator $\psi^k$ scales every weight of $\mathrm{V}(\lambda)$ by $k$. The result is returned as a Dict{SVector{R,Int}, Int} mapping weight coordinates to multiplicities (not decomposed into irreducibles). Use character_from_weights to convert it to a WeylCharacter:
julia> ω1_a2 = fundamental_weight(TypeA{2}, 1);
julia> ψ2 = adams_operator(ω1_a2, 2);
julia> length(ψ2) # number of distinct weights
3The Newton identity connects Adams operators to symmetric/exterior powers: $\psi^2(\mathrm{V}) = \mathrm{Sym}^2(\mathrm{V}) - \bigwedge^2(\mathrm{V})$:
julia> ψ2_char = character_from_weights(TypeA{2}, ψ2);
julia> ψ2_char == Sym(2, ω1_a2) - ⋀(2, ω1_a2)
trueSemisimple.adams_operator — Function
adams_operator(λ::WeightLatticeElem{DT,R}, k::Integer) -> Dict{SVector{R,Int}, BigInt}Compute the k-th Adams operator $ψ^k(\mathrm{V}(λ))$, returned as a dictionary of weight multiplicities (not decomposed into irreducibles).
The Adams operator scales every weight by k: if $\mathrm{V}(λ)$ has weight multiplicity $m(μ)$, then $ψ^k(\mathrm{V}(λ))$ has $m(μ)$ at weight $kμ$. Multiplicities are stored as BigInt (propagated from freudenthal_formula).
Examples
julia> using Semisimple, StaticArrays
julia> m = adams_operator(fundamental_weight(TypeA{2}, 1), 2);
julia> length(m), m[SVector(2, 0)]
(3, 1)Semisimple.character_from_weights — Function
character_from_weights(::Type{DT}, multiplicities::Dict{SVector{R,Int}, <:Integer}) -> WeylCharacter{DT,R}Given a dictionary of weight multiplicities (as from Freudenthal), decompose the representation into a formal sum of irreducibles (a virtual character if some multiplicities are negative).
Uses the "peeling" algorithm: at each step find the dominant weight with the largest root-basis height ht_root(λ) = (col-sums of C⁻¹)·λ (with ties broken in favour of dominant weights — necessary for minuscule representations of simply-laced types), subtract the Freudenthal multiplicities of that irreducible, and repeat until mults is empty.
The root-basis height is the unique correct linear height for the peeling order: it is strictly positive on positive roots, strictly larger on the dominant weight of each Weyl orbit than on any non-dominant orbit member, and handles all Lie types (including G₂ where the Cartan symmetrizer gives the wrong order).
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1);
julia> character_from_weights(TypeA{2}, freudenthal_formula(ω1))
A2(1, 0)Exterior powers
The $k$-th exterior power $\bigwedge^k \mathrm{V}$ is computed via the Newton–Girard recurrence, which relates exterior powers to Adams operators (power-sum symmetric functions):
\[k \cdot \bigwedge\nolimits^k(\mathrm{V}) = \sum_{r=1}^{k} (-1)^{r-1}\, \psi^r(\mathrm{V}) \cdot \bigwedge\nolimits^{k-r}(\mathrm{V})\]
This is the representation-ring analogue of the classical identity $k \, e_k = \sum_{r=1}^{k} (-1)^{r-1} p_r \, e_{k-r}$ relating elementary symmetric polynomials $e_k$ to power-sum polynomials $p_r$.
Both WeightLatticeElem and WeylCharacter are accepted:
julia> ⋀(2, V) # ⋀²V(ω1) of A3 = V(ω2)
A3(0, 1, 0)
julia> ⋀(3, V) # ⋀³V(ω1) of A3 = V(ω3)
A3(0, 0, 1)
julia> ⋀(4, V) # top exterior power = trivial (det)
A3(0, 0, 0)
julia> ⋀(5, V) # exceeds dim = 0
0Dimension identity
$\dim \bigwedge^k \mathrm{V} = \binom{\dim \mathrm{V}}{k}$:
julia> r = ⋀(2, V);
julia> sum(m * degree(μ) for (μ, m) in r.terms) == binomial(4, 2)
trueType A fundamental representations
For $\mathrm{A}_n$, $\bigwedge^k \mathrm{V}(\omega_1) = \mathrm{V}(\omega_k)$:
julia> ω = [fundamental_weight(TypeA{5}, i) for i in 1:5];
julia> all(⋀(k, WeylCharacter(ω[1])) == WeylCharacter(ω[k]) for k in 1:5)
trueNon-minuscule exterior powers
julia> adj = ω1 + ω3; # adjoint of A3 (15-dim)
julia> r = ⋀(2, adj);
julia> is_effective(r)
true
julia> sum(m * degree(μ) for (μ, m) in r.terms) == binomial(15, 2)
trueSemisimple.exterior_power — Function
exterior_power(λ::WeightLatticeElem{DT,R}, k::Integer) -> WeylCharacter{DT,R}Compute the k-th exterior power $\bigwedge^k \mathrm{V}(λ)$ of the irreducible representation with highest weight λ, using the Newton–Girard recurrence:
$k \cdot \bigwedge\nolimits^k(\mathrm{V}) = \sum_{r=1}^{k} (-1)^{r-1} ψ^r(\mathrm{V}) \cdot \bigwedge\nolimits^{k-r}(\mathrm{V})$
This is the representation-ring analogue of the classical identity $k \, e_k = \sum_{r=1}^{k} (-1)^{r-1} p_r \, e_{k-r}$ relating the elementary symmetric polynomials $e_k$ to the power-sum polynomials $p_r$. Here the Adams operator $ψ^r$ plays the role of $p_r$.
Results are memoized for efficiency in recursive calls.
Examples
julia> using Semisimple
julia> spin = fundamental_weight(TypeB{3}, 3); # B3 spin rep, dim 8
julia> ⋀(6, spin)
B3(1, 0, 0) + B3(0, 1, 0)exterior_power(V::WeylCharacter{DT,R}, k::Integer) -> WeylCharacter{DT,R}Compute the k-th exterior power $\bigwedge^k(V)$ of a virtual character V.
For an irreducible character $V = \mathrm{V}(λ)$ this delegates to the weight-level exterior_power(λ, k). For a general virtual character $V = \sum_i m_i \mathrm{V}(λ_i)$ the Newton–Girard recurrence is applied at the level of characters, with the Adams operator applied component-wise:
$k \cdot \bigwedge\nolimits^k(V) = \sum_{r=1}^{k} (-1)^{r-1} ψ^r(V) \cdot \bigwedge\nolimits^{k-r}(V)$
Results are memoized.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{3}, 1);
julia> V = WeylCharacter(ω1);
julia> exterior_power(V, 2)
A3(0, 1, 0)
julia> exterior_power(V, 4) # top exterior power = trivial (det)
A3(0, 0, 0)
julia> exterior_power(V, 5) # exceeds dimension = 0
0
julia> exterior_power(V, 2) == exterior_power(ω1, 2)
trueSemisimple.⋀ — Function
⋀(k::Integer, λ::WeightLatticeElem) -> WeylCharacter
⋀(k::Integer, V::WeylCharacter) -> WeylCharacterCompute the k-th exterior power. Shorthand for exterior_power.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{3}, 1);
julia> ⋀(2, ω1) == WeylCharacter(fundamental_weight(TypeA{3}, 2))
true
julia> V = WeylCharacter(ω1);
julia> ⋀(2, V) == WeylCharacter(fundamental_weight(TypeA{3}, 2))
trueSymmetric powers
The $k$-th symmetric power $\mathrm{Sym}^k \mathrm{V}$ is likewise computed via the Newton–Girard recurrence:
\[k \cdot \mathrm{Sym}^k(\mathrm{V}) = \sum_{r=1}^{k} \psi^r(\mathrm{V}) \cdot \mathrm{Sym}^{k-r}(\mathrm{V})\]
This is the representation-ring analogue of the identity $k \, h_k = \sum_{r=1}^{k} p_r \, h_{k-r}$ for complete homogeneous symmetric polynomials $h_k$.
Both WeightLatticeElem and WeylCharacter are accepted:
julia> Sym(2, V) # Sym² of std rep of A3
A3(2, 0, 0)
julia> Sym(0, V) # Sym⁰ = trivial
A3(0, 0, 0)
julia> Sym(1, V) # Sym¹ = identity
A3(1, 0, 0)Type A: always irreducible for ω₁
For $\mathrm{A}_n$, $\mathrm{Sym}^k \mathrm{V}(\omega_1) = \mathrm{V}(k\omega_1)$:
julia> all(Sym(k, V) == WeylCharacter(k * ω1) for k in 1:5)
trueDimension identity
$\dim \mathrm{Sym}^k \mathrm{V} = \binom{\dim \mathrm{V} + k - 1}{k}$:
julia> r = Sym(3, V);
julia> sum(m * degree(μ) for (μ, m) in r.terms) == binomial(4 + 2, 3)
trueNewton identity: V ⊗ V = Sym²V ⊕ ⋀²V
julia> V * V == Sym(2, V) + ⋀(2, V)
true
julia> ω1_g2 = fundamental_weight(TypeG2, 1);
julia> W_g2 = WeylCharacter(ω1_g2);
julia> W_g2 * W_g2 == Sym(2, W_g2) + ⋀(2, W_g2)
trueReducible character example
Sym and ⋀ also accept general WeylCharacter values (not just irreducibles). Scaling $V \mapsto 2V$ adds a copy, so: $\mathrm{Sym}^2(2V) = 3\,\mathrm{Sym}^2(V) \oplus \bigwedge^2(V)$:
julia> symmetric_power(2 * V, 2) == 3 * Sym(2, V) + ⋀(2, V)
trueSemisimple.symmetric_power — Function
symmetric_power(λ::WeightLatticeElem{DT,R}, k::Integer) -> WeylCharacter{DT,R}Compute the k-th symmetric power $\mathrm{Sym}^k \mathrm{V}(λ)$ of the irreducible representation with highest weight λ, using the Newton–Girard recurrence:
$k \cdot \mathrm{Sym}^k(\mathrm{V}) = \sum_{r=1}^{k} ψ^r(\mathrm{V}) \cdot \mathrm{Sym}^{k-r}(\mathrm{V})$
This is the representation-ring analogue of the classical identity $k \, h_k = \sum_{r=1}^{k} p_r \, h_{k-r}$ relating the complete homogeneous symmetric polynomials $h_k$ to the power-sum polynomials $p_r$. Here the Adams operator $ψ^r$ plays the role of $p_r$.
Results are memoized for efficiency in recursive calls.
Examples
julia> using Semisimple
julia> spin = fundamental_weight(TypeB{3}, 3); # B3 spin rep, dim 8
julia> Sym(6, spin)
B3(0, 0, 6) + B3(0, 0, 4) + B3(0, 0, 2) + B3(0, 0, 0)symmetric_power(V::WeylCharacter{DT,R}, k::Integer) -> WeylCharacter{DT,R}Compute the k-th symmetric power $\mathrm{Sym}^k(V)$ of a virtual character V.
For an irreducible character $V = \mathrm{V}(λ)$ this delegates to the weight-level symmetric_power(λ, k). For a general virtual character $V = \sum_i m_i \mathrm{V}(λ_i)$ the Newton–Girard recurrence is applied at the level of characters, with the Adams operator applied component-wise:
$k \cdot \mathrm{Sym}^k(V) = \sum_{r=1}^{k} ψ^r(V) \cdot \mathrm{Sym}^{k-r}(V)$
Results are memoized.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1);
julia> V = WeylCharacter(ω1);
julia> symmetric_power(V, 2)
A2(2, 0)
julia> symmetric_power(V, 3)
A2(3, 0)
julia> symmetric_power(V, 0) == WeylCharacter(zero(ω1))
true
julia> # Sym²(V ⊕ V) = 3·Sym²V ⊕ ⋀²V (dimension identity: C(6+1,2) = 21)
symmetric_power(2 * V, 2) == 3 * symmetric_power(V, 2) + exterior_power(V, 2)
trueSemisimple.Sym — Function
Sym(k::Integer, λ::WeightLatticeElem) -> WeylCharacter
Sym(k::Integer, V::WeylCharacter) -> WeylCharacterCompute the k-th symmetric power. Shorthand for symmetric_power.
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{2}, 1);
julia> Sym(2, ω1)
A2(2, 0)
julia> V = WeylCharacter(ω1);
julia> Sym(2, V)
A2(2, 0)
julia> Sym(2, V) == Sym(2, ω1)
true
julia> degree(highest_weight(Sym(3, V)))
10Plethysm (Schur functors)
The plethysm $s_\lambda(\mathrm{V}(\mu))$ applies the Schur functor associated to a partition $\lambda \vdash n$ to an irreducible representation $\mathrm{V}(\mu)$. Symmetric and exterior powers are special cases:
- $s_{(n)} = \mathrm{Sym}^n$
- $s_{(1^n)} = \bigwedge^n$
The general formula uses the Murnaghan–Nakayama rule for $S_n$ characters and Adams operators (power-sum symmetric functions):
\[s_\lambda(\mathrm{V}) = \frac{1}{n!} \sum_{\kappa \vdash n} \chi^\lambda(\kappa) \cdot |\mathrm{Cl}(\kappa)| \cdot \psi^{\kappa_1}(\mathrm{V}) \otimes \cdots \otimes \psi^{\kappa_m}(\mathrm{V})\]
julia> plethysm([2], ω1) == Sym(2, V) # one-row partition = Sym
true
julia> plethysm([1, 1], ω1) == ⋀(2, V) # one-column partition = ⋀
true
julia> plethysm([2, 1], ω1) # mixed symmetry S_{(2,1)}
A3(1, 1, 0)
julia> degree(plethysm([2, 1], ω1)) # mixed-symmetry representation of A3
20Plethysm on non-simply-laced types
julia> plethysm([2], ω1_g2) == Sym(2, W_g2)
true
julia> plethysm([1, 1], ω1_g2) == ⋀(2, W_g2)
trueSemisimple.plethysm — Function
plethysm(λ::Vector{<:Integer}, μ::WeightLatticeElem{DT,R}) -> WeylCharacter{DT,R}Compute the plethysm $s_λ(\mathrm{V}(μ))$, where $λ$ is a partition of $n$ (parts in weakly decreasing order) and $\mathrm{V}(μ)$ is the irreducible representation with highest weight $μ$.
The Schur functor $s_λ$ generalises symmetric and exterior powers:
- $s_{(n)} = \mathrm{Sym}^n$
- $s_{(1,1,…,1)} = \bigwedge^n$
Uses the Murnaghan–Nakayama rule for $S_n$ characters and the formula:
\[s_λ(\mathrm{V}) = \frac{1}{n!} \sum_{κ \vdash n} χ^λ(κ) \cdot |\mathrm{Cl}(κ)| \cdot ψ^{κ_1}(\mathrm{V}) \otimes \cdots \otimes ψ^{κ_m}(\mathrm{V})\]
Examples
julia> using Semisimple
julia> ω1 = fundamental_weight(TypeA{3}, 1);
julia> plethysm([2], ω1) == Sym(2, ω1)
true
julia> plethysm([1, 1], ω1) == ⋀(2, ω1)
true
julia> plethysm([2, 1], ω1) # Mixed symmetry: S_{(2,1)} functor
A3(1, 1, 0)Reconstructing characters from weights
Given a weight multiplicity dictionary (e.g. from an Adams operator), recover the Weyl character decomposition:
julia> m = Dict(SVector(1, 0, 0) => 1, SVector(-1, 1, 0) => 1,
SVector(0, -1, 1) => 1, SVector(0, 0, -1) => 1);
julia> V_rec = character_from_weights(TypeA{3}, m);
julia> is_irreducible(V_rec)
true
julia> highest_weight(V_rec) == ω1
trueCross-type examples
B₃: spin representation
julia> ω3_b3 = fundamental_weight(TypeB{3}, 3);
julia> degree(ω3_b3) # 8-dim spin rep
8
julia> spin = WeylCharacter(ω3_b3);
julia> r = ⋀(2, spin);
julia> sum(m * degree(μ) for (μ, m) in r.terms) == binomial(8, 2)
trueG₂: 7-dimensional representation
julia> degree(ω1_g2)
7
julia> r = Sym(2, W_g2);
julia> is_effective(r)
true
julia> sum(m * degree(μ) for (μ, m) in r.terms) == binomial(7 + 1, 2)
trueE₈: adjoint representation
julia> ω8_e8 = fundamental_weight(TypeE{8}, 8);
julia> degree(ω8_e8) # 248-dim adjoint
248
julia> r = ⋀(2, WeylCharacter(ω8_e8));
julia> length(r.terms) # 2 irreducible components
2Representation invariants
Semisimple.jl provides several classical invariants attached to irreducible representations.
Dynkin index
The Dynkin index of $\mathrm{V}(λ)$ is the proportionality constant between the trace form on $\mathrm{V}(λ)$ and the Killing form:
\[I(λ) = \frac{\dim \mathrm{V}(λ) \cdot (λ,\, λ + 2ρ)}{2\,\dim \mathfrak{g}}\]
where the inner product is normalized so that long roots have squared length 2. Equivalently, Semisimple.jl divides its internal bilinear form by $(\theta,\theta)/2$. For the adjoint representation, $I(θ) = h^∨$ (the dual Coxeter number).
julia> dynkin_index(fundamental_weight(TypeA{3}, 1))
1//2
julia> adj = adjoint_representation(TypeA{3});
julia> dynkin_index(highest_weight(adj)) == dual_coxeter_number(TypeA{3})
trueCasimir eigenvalue
The eigenvalue of the quadratic Casimir element on $\mathrm{V}(λ)$ is $c(λ) = 2(λ, λ + 2ρ)/(\theta,\theta)$, where $\theta$ is the highest root. This normalizes long roots to have squared length 2:
julia> casimir_eigenvalue(fundamental_weight(TypeA{3}, 1))
15//4
julia> casimir_eigenvalue(fundamental_weight(TypeB{3}, 3))
21//4Congruency class
julia> congruency_class(fundamental_weight(TypeA{3}, 1))
1
julia> congruency_class(fundamental_weight(TypeD{4}, 3))
(1, 0)Self-duality and Frobenius–Schur indicator
julia> is_self_dual(fundamental_weight(TypeB{3}, 1))
true
julia> frobenius_schur_indicator(fundamental_weight(TypeB{3}, 1))
1
julia> frobenius_schur_indicator(fundamental_weight(TypeC{2}, 1))
-1
julia> frobenius_schur_indicator(fundamental_weight(TypeA{2}, 1))
0Adjoint representation
julia> adj = adjoint_representation(TypeE{8});
julia> degree(adj)
248Semisimple.dynkin_index — Function
dynkin_index(λ::WeightLatticeElem{DT,R}) -> Rational{BigInt}Compute the Dynkin index of the irreducible representation $\mathrm{V}(λ)$:
\[\ell(λ) = \frac{\dim \mathrm{V}(λ)}{2 \dim \mathfrak{g}} \cdot (λ,\, λ + 2ρ)\]
where ρ is the Weyl vector, \dim \mathfrak{g} is the dimension of the Lie algebra, and the bilinear form is normalized so long roots have squared length
For the adjoint representation, the Dynkin index equals the dual Coxeter number. The result is always a non-negative half-integer.
Examples
julia> using Semisimple
julia> dynkin_index(fundamental_weight(TypeA{2}, 1))
1//2
julia> dynkin_index(fundamental_weight(TypeE{8}, 8))
30//1Semisimple.casimir_eigenvalue — Function
casimir_eigenvalue(λ::WeightLatticeElem{DT,R}) -> Rational{Int}Compute the eigenvalue of the quadratic Casimir operator on the irreducible representation $\mathrm{V}(λ)$:
\[c(λ) = \frac{2\,(λ,\, λ + 2ρ)}{(θ, θ)}\]
where $(\cdot,\cdot)$ is the Cartan bilinear form and $θ$ is the highest root. The normalization ensures long roots have squared length 2.
Examples
julia> using Semisimple
julia> casimir_eigenvalue(fundamental_weight(TypeA{2}, 1))
8//3
julia> casimir_eigenvalue(fundamental_weight(TypeB{3}, 3))
21//4Semisimple.congruency_class — Function
congruency_class(λ::WeightLatticeElem{DT,R}) -> Union{Int, Tuple{Int,Int}}Compute the congruency class of the irreducible representation $\mathrm{V}(λ)$. Two representations belong to the same congruency class if and only if their difference of highest weights lies in the root lattice.
The return value depends on the Lie algebra type:
- $\mathrm{A}_N$: an integer in $0, 1, \ldots, N$ (mod $N+1$)
- $\mathrm{B}_N$: an integer in $\{0, 1\}$ (mod 2)
- $\mathrm{C}_N$: an integer in $\{0, 1\}$ (mod 2)
- $\mathrm{D}_N$ ($N$ even): a tuple $(a, b)$ with $a, b \in \{0,1\}$ (center $\mathbb{Z}/2 \times \mathbb{Z}/2$)
- $\mathrm{D}_N$ ($N$ odd): an integer in $\{0, 1, 2, 3\}$ (center $\mathbb{Z}/4$)
- $\mathrm{E}_6$: an integer in $\{0, 1, 2\}$ (mod 3)
- $\mathrm{E}_7$: an integer in $\{0, 1\}$ (mod 2)
- $\mathrm{E}_8, \mathrm{F}_4, \mathrm{G}_2$: always $0$ (trivial center)
Examples
julia> using Semisimple
julia> congruency_class(fundamental_weight(TypeA{2}, 1))
1
julia> congruency_class(fundamental_weight(TypeD{4}, 1))
(1, 1)Semisimple.is_self_dual — Function
is_self_dual(λ::WeightLatticeElem{DT,R}) -> BoolReturn true if the irreducible representation $\mathrm{V}(λ)$ is isomorphic to its dual $\mathrm{V}(λ)^*$, i.e. if $λ = -w_0(λ)$.
Examples
julia> using Semisimple
julia> is_self_dual(fundamental_weight(TypeA{2}, 1))
false
julia> is_self_dual(WeightLatticeElem(TypeA{2}, [1, 1]))
true
julia> is_self_dual(fundamental_weight(TypeB{3}, 1))
trueSemisimple.frobenius_schur_indicator — Function
frobenius_schur_indicator(λ::WeightLatticeElem{DT,R}) -> IntCompute the Frobenius–Schur indicator of the irreducible representation $\mathrm{V}(λ)$:
1if $\mathrm{V}(λ)$ is real (orthogonal): admits an invariant symmetric bilinear form-1if $\mathrm{V}(λ)$ is pseudoreal (quaternionic/symplectic): admits an invariant skew-symmetric bilinear form0if $\mathrm{V}(λ)$ is complex: not self-dual
For a self-dual representation, the indicator is $(-1)^{⟨δ, λ⟩}$ where $δ = ∑_{α > 0} α^∨$ is twice the dual Weyl vector and $⟨α_i^∨, λ⟩ = λ_i$ is the natural pairing.
Examples
julia> using Semisimple
julia> frobenius_schur_indicator(fundamental_weight(TypeA{2}, 1))
0
julia> frobenius_schur_indicator(WeightLatticeElem(TypeA{2}, [1, 1]))
1
julia> frobenius_schur_indicator(fundamental_weight(TypeC{2}, 1))
-1Semisimple.adjoint_representation — Function
adjoint_representation(::Type{DT}) -> WeylCharacter{DT}Return the character of the adjoint representation of the Lie algebra of type DT. The highest weight is the highest root θ.
For a simple type, the adjoint is a single irreducible. For a product type DT = T₁ × T₂ × ⋯, the adjoint is the direct sum of the factor adjoints, each embedded in the product weight space with zeros in the other factor slots.
Examples
julia> using Semisimple
julia> degree(adjoint_representation(TypeA{3}))
15
julia> degree(adjoint_representation(TypeE{8}))
248
julia> PDT = ProductDynkinType{Tuple{TypeA{2},TypeB{2}}};
julia> degree(adjoint_representation(PDT))
18
julia> adjoint_representation(PDT)
A2 × B2(1, 1, 0, 0) + A2 × B2(0, 0, 0, 2)