Antonio
Candiello

Projects · WBase and the representations of Lie algebras

WBase: how it works and why

  • wbase
  • irrep
  • irreducible representations
  • Dynkin
  • Lie algebras
  • Cartan-Weyl basis

WBase is a C package of fewer than 1000 lines that computes the irreducible representations (irreps) of the simple Lie algebras and decomposes their tensor products. Given the highest weight of an irrep, it computes its dimension, index, weight system with multiplicities and Young tableau; given two highest weights, it finds the irreps contained in their product.

The article follows the order needed to understand WBase: theory first, then the algorithms, then the code. The numerical examples are rerun with V3.0, and where the original 1995 material contained errors the values are corrected (list).

What WBase is

The program uses Dynkin's approach, which works for all simple algebras, exceptional ones included: An, Bn, Cn, Dn, E6, E7, E8, F4 and G2. It was born for particle physics and supergravity, which need products of irreps larger than those in the classic tables, such as Slansky's.

VersionDateWhat's new
V3.0November 2026Fixes for Cn, B2, E7 and E8, 64-bit dimensions, robust input
V2.0April 1995All simple algebras, table generation (wsequence), extended Young tableaux
V1December 1993First version, An, Bn and Dn only; published in Comput. Phys. Comm. 81 (1994)
Back to top

Dynkin's approach

In Dynkin's approach a simple Lie algebra is described entirely by its Cartan matrix, an \(l \times l\) matrix where \(l\) is the rank. WBase contains no tables of algebras: it builds everything on the fly from this matrix.

In the Cartan–Weyl basis the generators split into \(l\) mutually commuting generators \(H_i\) and the remaining generators \(E_\alpha\):

\[ [H_i, H_j] = 0, \qquad [H_i, E_\alpha] = \alpha_i \, E_\alpha, \qquad i = 1, \ldots, l \]
TermMeaningIn WBase
Rank \(l\)Number of commuting generators \(H_i\)wsize
Roots \(\alpha\)The eigenvalues (\(l\)-vectors) of the generators \(E_\alpha\)—
Simple roots \(\alpha_1 \ldots \alpha_l\)\(l\) roots from which all the others are integer linear combinations, with coefficients all \(\ge 0\) or all \(\le 0\)rows of cart
Positive rootsThe roots with all coefficients \(\ge 0\); there are \((\dim G - l)/2\) of thempos, generated by wptree
Cartan matrix \(A\)\(A_{ij} = 2(\alpha_i, \alpha_j)/(\alpha_j, \alpha_j)\); row \(i\) holds the Dynkin labels of \(\alpha_i\)cart, written by Afill…Gfill
Metric \(G\)\(G_{ij} = (\omega_i, \omega_j)\), scalar product of the fundamental weights; it is the inverse of the Cartan matrix, symmetrizedmetr
Weight\(l\)-tuple of integers identifying a state within an irrepwvect
Highest weight \(\Lambda\)\(l\)-tuple of non-negative integers (Dynkin labels) that uniquely identifies an irrepthe numbers typed as input
Weight systemAll the weights of an irrep, each with its multiplicitylist of wblock

The scalar product of two weights \(x\) and \(y\), written in the Dynkin basis, is \((x, y) = \sum_{ij} x_i G_{ij} y_j\). The special vector \(\delta = (1, 1, \ldots, 1)\), i.e. half the sum of the positive roots, appears in all the formulas.

Back to top

An example: the irrep 15 of SU(3)

The irrep 15 of SU(3) (algebra A2) has highest weight \(\Lambda = (1\ 2)\) and a system of 12 distinct weights on 7 levels. Three weights have multiplicity 2, hence 12 + 3 = 15 states.

The level of a weight is the number of simple roots subtracted from \(\Lambda\) to reach it; the height of the irrep is the lowest level, here 6. This is the table produced by WBase with the command T:

LevelWeightMultiplicity
0(1 2)1
1(−1 3)1
1(2 0)1
2(0 1)2
2(3 −2)1
3(−2 2)1
3(1 −1)2
4(2 −3)1
4(−1 0)2
5(0 −2)1
5(−3 1)1
6(−2 −1)1

The system is symmetric: the lowest weight (−2 −1) is the opposite of the highest weight of the conjugate \(\overline{15} = (2\ 1)\). The original 1995 material gave (−2 1) as the last weight, a typo.

Back to top

How the weight system is built

The weight system is obtained from the highest weight by repeatedly subtracting the simple roots, i.e. the rows of the Cartan matrix. In A2 the simple roots are \(\alpha_1 = (2\ {-1})\) and \(\alpha_2 = ({-1}\ 2)\). The recursive function wtree applies this rule:

  1. Start from \(u = \Lambda\).
  2. For each component \(i\) with \(u_i > 0\), subtract \(\alpha_i\) once, twice, …, \(u_i\) times, giving the weights \(u - k\alpha_i\).
  3. Each new weight is saved at the parent's level plus \(k\) and the procedure restarts from there; a weight already present is not processed again.

The rule stops by itself: negative components generate no subtractions, so the recursion ends at the lowest weight. The weights are kept sorted by level, because the Freudenthal formula needs the higher levels to be computed first.

Each step down subtracts a simple root

Irrep 15 of SU(3), highest weight (1 2): 12 weights on 7 levels, 3 with multiplicity 2

level 0 level 1 level 2 level 3 level 4 level 5 level 6 (1 2) (−1 3) (2 0) (0 1) ×2 (3 −2) (−2 2) (1 −1) ×2 (2 −3) (−1 0) ×2 (0 −2) (−3 1) (−2 −1) subtracts α₁ = (2 −1) subtracts α₂ = (−1 2) multiplicity 2
Weight tree generated with WBase V3.0 (command T).

In the diagram each arrow to the left (solid) subtracts \(\alpha_1\) and each arrow to the right (dashed) subtracts \(\alpha_2\). The tree tells which weights exist, not how many times they occur: (0 −2) has two incoming arrows like (−1 0), but multiplicity 1 instead of 2. Multiplicities need the Freudenthal formula.

Back to top

The formulas

WBase uses three classic formulas, all written with the scalar product of the metric \(G\), plus the height formula. Each formula corresponds to a function in the code.

Dimension: Weyl formula

Function weyl. The product runs over the positive roots \(\alpha\):

\[ \dim(\Lambda) = \prod_{\alpha > 0} \frac{(\Lambda + \delta, \alpha)}{(\delta, \alpha)} \]

The weight system is not needed: the highest weight and the positive roots are enough. That is why the dimension of a huge E8 irrep is computed instantly.

Multiplicity of a weight: Freudenthal recursion formula

Functions freud and bfreud. Start from \(\deg(\Lambda) = 1\) and go down level by level:

\[ \deg(w) = \frac{2 \sum_{\alpha > 0} \sum_{k > 0} \deg(w + k\alpha)\,(w + k\alpha, \alpha)}{\lVert \Lambda + \delta \rVert^2 - \lVert w + \delta \rVert^2} \]

The weights \(w + k\alpha\) lie higher than \(w\), so their multiplicities are already known when \(w\) is reached. This is the slowest part of the program: each \(\deg(w + k\alpha)\) needs a search in the weight list.

Second-order Dynkin index

Function casimir, printed as C=:

\[ C(\Lambda) = \frac{\dim(\Lambda)}{\dim(G)} \, (\Lambda, \Lambda + 2\delta) \]

With this normalization the fundamental of SU(N) has C = 1 and the adjoint of SU(3) has C = 6. The original 1995 material writes only \(\dim(\Lambda)/\dim(G)\), leaving out the factor \((\Lambda, \Lambda + 2\delta)\): the code, however, has always used it.

Height

Function wheight, printed as H=: \(H = \sum_i \mathrm{whigh}_i \Lambda_i\), where the coefficients whigh are fixed for each algebra. H is the level of the lowest weight, i.e. the number of levels of the weight system minus 1.

Back to top

Tensor products

To decompose \(R_1 \otimes R_2\), WBase adds every weight of \(R_1\) to every weight of \(R_2\) and then extracts the irreps one at a time, starting from the highest. This is the function wpdisp, in these steps:

  1. wsyst builds the weight systems of \(R_1\) and \(R_2\), with multiplicities.
  2. bprod forms the set of all the sums \(w_1 + w_2\), counting multiplicities (\(\dim R_1 \times \dim R_2\) elements).
  3. While the set is not empty:
    1. whigher picks the weight of greatest height: it is the highest weight of a component;
    2. wsyst builds the weight system of that component;
    3. bremove subtracts it from the set, multiplicities included.

The fast mode (commands F and L) skips step 3. It lists only the distinct dominant weights of the product, so it gives no multiplicities and can include weights that are not the highest weight of any component.

A physical example: the baryon decuplet

Three quarks form a baryon according to the product \(3 \otimes 3 \otimes 3 = 10 \oplus 8 \oplus 8 \oplus 1\) of flavour SU(3). WBase computes it in two steps: \(3 \otimes 3 = 6 \oplus \overline{3}\), then \(6 \otimes 3 = 10 \oplus 8\) and \(\overline{3} \otimes 3 = 8 \oplus 1\).

The decuplet of the spin-3/2 baryons is the irrep 10 = (0 3), in which the three quarks are symmetrized. With the convention used by WBase, u = (0 1), d = (−1 0) and s = (1 −1), the weight of each state is the sum of the weights of its quarks:

LevelStateQuarksWeight
0Δuuu(0 3)
1Σ*uus(1 1)
2Δduu(−1 2)
2Ξ*uss(2 −1)
3Σ*dus(0 0)
3Ωsss(3 −3)
4Δddu(−2 1)
4Ξ*dss(1 −2)
5Σ*dds(−1 −1)
6Δddd(−3 0)

The baryon decuplet is a triangle of 10 simple weights

Weights of the irrep 10 = (0 3) in the (I₃, Y) plane: four rows of hypercharge, from Δ at the top to Ω at the bottom

Δ, Y = 1 Σ*, Y = 0 Ξ*, Y = −1 Ω, Y = −2 I₃ (isospin) Y (hypercharge) Δ++ (0 3) Δ+ (−1 2) Δ0 (−2 1) Δ− (−3 0) Σ*+ (1 1) Σ*0 (0 0) Σ*− (−1 −1) Ξ*0 (2 −1) Ξ*− (1 −2) Ω− (3 −3) All 10 weights have multiplicity 1: unlike the octet, the decuplet has no double points.
Weight system computed with WBase V3.0 (command T, A2, highest weight 0 3).

All 10 weights have multiplicity 1. The original material gave dds the weight (1 −2), already assigned to dss: the correct value is (−1 −1).

A second example: the meson octet

A meson is made of a quark and an antiquark, according to the product \(3 \otimes \overline{3} = 8 \oplus 1\). With the command P WBase computes it as (0 1) ⊗ (1 0) = (1 1) ⊕ (0 0): the octet plus a singlet.

The octet of the pseudoscalar mesons (spin 0) is the irrep 8 = (1 1), the same one that serves as the adjoint representation of SU(3). The antiquarks have the opposite weights of the quarks, \(\bar{u} = (0\ {-1})\), \(\bar{d} = (1\ 0)\) and \(\bar{s} = ({-1}\ 1)\), and the weight of each meson is the sum of the weights of its quark and antiquark:

LevelMesonQuarksWeightMultiplicity
0\(\pi^+\)\(u\bar{d}\)(1 1)1
1\(K^+\)\(u\bar{s}\)(−1 2)1
1\(\bar{K}^0\)\(s\bar{d}\)(2 −1)1
2\(\pi^0\), \(\eta_8\)\(u\bar{u}\), \(d\bar{d}\), \(s\bar{s}\)(0 0)2
3\(K^0\)\(d\bar{s}\)(−2 1)1
3\(K^-\)\(s\bar{u}\)(1 −2)1
4\(\pi^-\)\(d\bar{u}\)(−1 −1)1

The meson octet is a hexagon with a double centre

Weights of the irrep 8 = (1 1) in the (I₃, Y) plane; under each meson its weight in Dynkin labels

I₃ (isospin) Y (hypercharge) π+ (1 1) K+ (−1 2) K0 (−2 1) π− (−1 −1) K− (1 −2) K0 (2 −1) π0, η8 (0 0) ×2 The double circle marks multiplicity 2; the singlet η₁, also of weight (0 0), is not part of the octet.
Weight system computed with WBase V3.0 (command T, A2, highest weight 1 1).

Unlike the decuplet, here the zero weight has multiplicity 2. The three pairs \(u\bar{u}\), \(d\bar{d}\) and \(s\bar{s}\) all have weight (0 0): two of their combinations belong to the octet (\(\pi^0\) and \(\eta_8\)), the third, symmetric one is the singlet \(\eta_1\). This accounts for the 9 = 8 + 1 states of the product. The observed mesons \(\eta\) and \(\eta'\) are mixtures of \(\eta_8\) and \(\eta_1\).

Back to top

Data structures

WBase allocates all its memory at run time, because the size of a weight system is not known in advance: it can range from a few bytes to hundreds of megabytes. There are three data types, defined in wbase.h:

TypeDefinitionUse
wvecttypedef char *wvect;A weight: an array of \(l\) bytes allocated with walloc and freed with wfree
wplacestruct { tdeg deg; tlevel level; char vect[1]; }A weight within a system, with multiplicity (unsigned short) and level (short). vect[1] is the “struct hack” of pre-1999 C: the vector actually has \(l\) bytes
wblockstruct tblock { struct tblock *next; char body[1]; }A block of 1000 places (bsize); the blocks form a linked list

A weight system is a chain of fixed-size blocks of places

One place (wplace), for an algebra of rank l degmultiplicity, 2 B levellevel, 2 B vect[0] … vect[l−1]Dynkin labels of the weight, 1 byte each paddingup to a multiple of 4 5 + l bytes (4 for deg and level, 1 for alignment, l for the weight), rounded up to a multiple of 4: 8 bytes in A2, 16 in E8 The block list (wblock), 1000 places per block next place 0: highest weight place 1 … place 999 next place 1000 place 1001 … place 1999 next = NULL place 2000 … last weight deg = 0: end of list free places pstart / pnext walk through the places across the blocks and stop at the first deg = 0; wsave adds a block with balloc when the last one is full; bsfree frees the whole chain.
Data structures in wbase.h: wvect, wplace, wblock.

The blocks are “shapeless”: body is just a sequence of bytes, to which the macro place(i, b) gives the shape of a wplace. Using char for the labels saves memory but limits them to the range from −128 to 127.

Back to top

Procedures and iterators

The WBase user works with a few high-level procedures and three iterators, without ever touching the memory blocks. The signatures below are those of the V3.0 code.

ProceduresWhat they do
wstartup(type, rank, debug)
wcleanup(msg)
Create and destroy the algebra tables (Cartan, metric, positive roots). wcleanup(NULL) closes without a message and terminates the program
wread(hw)
wfdisp(hw)
wydisp(hw)
Read a highest weight from stdin; print D, C, H; print the Young tableau (classical series)
wsave(w, base, level)
wremove(w, base)
With level ≥ 0 insert w sorted by level; with level = −1 append it or increase its multiplicity. wremove decreases the multiplicity and removes the weight when it reaches 0
wsyst(hw)
bdisp(base)
bsfree(base)
Build the weight system with multiplicities; print it; free the block list
wpdisp(hw1, hw2, mod)Decomposes hw1 ⊗ hw2; mod combines the flags WFULL (exact), WTREE (weight tree), WYOUNG (tableaux)

Walking through a weight system

pstart/pnext hide the step from one block to the next:

wplace *p; pcurr pc;
for (p = pstart(base, &pc); p != NULL; p = pnext(&pc))
    wdisp(p->vect);   /* also p->deg and p->level */

Extracting the irreps of a product

wpstart/wpnext return at each step the complete weight system of one component:

wblock *b1 = wsyst(hw1), *b2 = wsyst(hw2), *buf, *b;
buf = bprod(b1, b2);
bsfree(b1); bsfree(b2);
for (b = wpstart(buf); b != NULL; b = wpnext(b, buf))
    bdisp(b);

Generating a table of irreps

wsequence returns at each call the next irrep in order of dimension, up to those with dimension strictly less than maxdim, and at the end frees its own list:

wblock *b = NULL; long long dim;
wvect hw = walloc();
while ((b = wsequence(hw, b, maxdim, &dim)) != NULL)
    wfdisp(hw);
wfree(hw);

Two nested wsequence loops produce a table of products: this is what the commands U, V and L do. Exact results need WFULL passed to wpdisp; with mod = 0 the decomposition is the fast, approximate one.

Back to top

Two sessions with F4

Two sessions with the exceptional algebra F4 show WBase at work. V3.0 reproduces exactly the numbers of the original 1995 sessions. Start wbase.exe, type F4 as the algebra, then a command.

Sequence of irreps (command S, maxdim 2000)

WBase lists, in order of dimension, all the irreps with dimension less than 2000:

Below dimension 2000, F4 has 8 irreps, two of them of dimension 1053

In order of dimension; in dark the two different irreps with the same dimension

highest weight dimension (0 0 0 0) (0 0 0 0): dimension 1, index 0, height 0 1 (0 0 0 1) (0 0 0 1): dimension 26, index 6, height 16 26 (1 0 0 0) (1 0 0 0): dimension 52, index 18, height 22 52 (0 0 1 0) (0 0 1 0): dimension 273, index 126, height 30 273 (0 0 0 2) (0 0 0 2): dimension 324, index 162, height 32 324 (1 0 0 1) (1 0 0 1): dimension 1053, index 648, height 38 1,053 C = 648, H = 38 (2 0 0 0) (2 0 0 0): dimension 1053, index 810, height 44 1,053 C = 810, H = 44 (0 1 0 0) (0 1 0 0): dimension 1274, index 882, height 42 1,274
WBase V3.0, F4, command S with maxdim 2000; identical to the original 1995 session.

The two irreps of dimension 1053 differ in the index C (648 and 810) and in the height H (38 and 44): the dimension alone is not enough to identify an irrep.

Sequence of products (command U, maxdim 100)

With maxdim 100 the irreps involved are the 26 and the 52, and WBase decomposes all their products:

ProductDecomposition
26 ⊗ 26324 ⊕ 273 ⊕ 52 ⊕ 26 ⊕ 1
26 ⊗ 521053 ⊕ 273 ⊕ 26
52 ⊗ 521053′ ⊕ 1274 ⊕ 324 ⊕ 52 ⊕ 1

In each row the sum of the dimensions equals the product of the dimensions, for example 26 × 52 = 1352 = 1053 + 273 + 26. Here 1053 is (1 0 0 1) and 1053′ is (2 0 0 0).

Back to top

Corrected errors

Compared with the original 1995 material, this article corrects 9 points. Each correction is checked by running WBase V3.0 or against the code.

TopicIn the originalCorrected
Irrep 15 of SU(3)Last weight: (−2 1)(−2 −1)
Baryon decupletWeight of dds: (1 −2), the same as dss(−1 −1)
Dynkin index\(\mathrm{cas}(\Lambda) = \dim(\Lambda)/\dim(\mathrm{adj})\)\(C(\Lambda) = \dim(\Lambda)\,(\Lambda, \Lambda + 2\delta)/\dim(G)\)
Highest weight\(l\)-tuple of “positive” integersNon-negative integers: zero is allowed, (0 0) is the singlet
wstartupwstartup(type, rank)wstartup(type, rank, debug)
wcleanupMust be called after every wstartupAlso terminates the program (exit)
wsequenceExample with int dimlong long dim (long in V2.0)
wsequenceShows the irreps “up to” maxdimStrictly less than maxdim
F4 products sessionLooks like it used the fast mode LThe output matches the exact mode U
Back to top

Publications on WBase

WBase is described in three publications by A. Candiello, from 1994 to 1995:

Theoretical references cited in the papers:

  • R. Slansky, Group theory for unified model building, Phys. Rep. 79 (1981) 1: the source of the formulas and conventions.
  • R.N. Cahn, Semi-Simple Lie Algebras and Their Representations, Benjamin/Cummings, 1984.
  • W. McKay, J. Patera, Tables of Dimensions, Indices and Branching Rules for Representations of Simple Algebras, Dekker, 1981.
  • G.R.E. Black, R.C. King, B.G. Wybourne, J. Phys. A16 (1983) 1555: the S-function techniques, the alternative to Dynkin's methods.
Back to top