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)
ω1
Semisimple.WeylCharacterType
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
true
source
Semisimple.is_effectiveFunction
is_effective(V::WeylCharacter) -> Bool

True 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)
true
source
Semisimple.is_irreducibleFunction
is_irreducible(V::WeylCharacter) -> Bool

True 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)
false
source
Semisimple.highest_weightFunction
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)
ω1
source

Arithmetic

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
true

Characters also support multiplication (tensor product) and exponentiation (tensor power):

julia> V * V2 == tensor_product(V, V2)
true

julia> V^3 == V * V * V
true
Base.:*Method
*(V::WeylCharacter, W::WeylCharacter) -> WeylCharacter

Tensor product of virtual characters, computed via Brauer–Klimyk. Equivalent to the ring multiplication in the representation ring.

source
Base.:^Method
^(V::WeylCharacter, n::Integer) -> WeylCharacter

Compute 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))
true
source

In-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)
true
source
Semisimple.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)
true
source

Character data terminology

Semisimple.jl uses three related but distinct character representations:

NameJulia representationMeaning
WeylCharacterDict{WeightLatticeElem,Int} in the terms fieldirreducible decomposition in the representation ring
Full weight characterDict{SVector{R,Int},Int} from freudenthal_formulamultiplicity of every weight
Dominant characterDict{SVector{R,Int},Int} from dominant_charactermultiplicity 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
1

Dominant 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
1
Semisimple.dominant_characterFunction
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_formula to expand the dominant character into the full character polynomial (all W-orbit members listed with their multiplicities).
  • Use weight_multiplicity to 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
2
source

Freudenthal'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
true

The 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))
2
Semisimple.freudenthal_formulaFunction
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
8
source
Semisimple.weight_multiplicityFunction
weight_multiplicity(λ::WeightLatticeElem{DT,R}, μ::WeightLatticeElem{DT,R}) -> BigInt

Return 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
2
source

Tensor 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
true
Semisimple.tensor_productFunction
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)
source
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)
source
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.

source
Semisimple.lr_tensor_productFunction
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)
source

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.dualFunction
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
 ω1
source
dual(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)
source

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
3

The 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)
true
Semisimple.adams_operatorFunction
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)
source
Semisimple.character_from_weightsFunction
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)
source

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
0

Dimension 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)
true

Type 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)
true

Non-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)
true
Semisimple.exterior_powerFunction
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)
source
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)
true
source
Semisimple.⋀Function
⋀(k::Integer, λ::WeightLatticeElem) -> WeylCharacter
⋀(k::Integer, V::WeylCharacter) -> WeylCharacter

Compute 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))
true
source

Symmetric 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)
true

Dimension 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)
true

Newton 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)
true

Reducible 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)
true
Semisimple.symmetric_powerFunction
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)
source
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)
true
source
Semisimple.SymFunction
Sym(k::Integer, λ::WeightLatticeElem) -> WeylCharacter
Sym(k::Integer, V::WeylCharacter) -> WeylCharacter

Compute 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)))
10
source

Plethysm (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
20

Plethysm on non-simply-laced types

julia> plethysm([2], ω1_g2) == Sym(2, W_g2)
true

julia> plethysm([1, 1], ω1_g2) == ⋀(2, W_g2)
true
Semisimple.plethysmFunction
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)
source

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
true

Cross-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)
true

G₂: 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)
true

E₈: 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
2

Representation 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&nbsp;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})
true

Casimir 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//4

Congruency 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))
0

Adjoint representation

julia> adj = adjoint_representation(TypeE{8});

julia> degree(adj)
248
Semisimple.dynkin_indexFunction
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//1
source
Semisimple.casimir_eigenvalueFunction
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//4
source
Semisimple.congruency_classFunction
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)
source
Semisimple.is_self_dualFunction
is_self_dual(λ::WeightLatticeElem{DT,R}) -> Bool

Return 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))
true
source
Semisimple.frobenius_schur_indicatorFunction
frobenius_schur_indicator(λ::WeightLatticeElem{DT,R}) -> Int

Compute the Frobenius–Schur indicator of the irreducible representation $\mathrm{V}(λ)$:

  • 1 if $\mathrm{V}(λ)$ is real (orthogonal): admits an invariant symmetric bilinear form
  • -1 if $\mathrm{V}(λ)$ is pseudoreal (quaternionic/symplectic): admits an invariant skew-symmetric bilinear form
  • 0 if $\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))
-1
source
Semisimple.adjoint_representationFunction
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)
source