Modern C++23 library for low-spin SU(2) Wigner symbols, Racah and recoupling coefficients, Clebsch-Gordan and Gaunt coefficients, spherical harmonics, and Wigner rotation matrix elements.
This project is currently oriented around:
- doubled-spin integer APIs (
two_j = 2j,two_m = 2m) - low-lying spins
- direct closed-form/runtime algorithms for
3j,6j,9j,d, andD - header-only use through CMake
- no dependencies beyond the C++ standard library
Public headers are gathered by:
#include <wigner/wigner.hpp>Currently available functions:
wigner::wigner_3j(two_j1, two_j2, two_j3, two_m1, two_m2, two_m3)wigner::wigner_3j(const wigner::wigner_3j_args&)wigner::wigner_12j_first(const wigner::wigner_12j_first_args&)wigner::wigner_12j_second(const wigner::wigner_12j_second_args&)wigner::wigner_6j(two_a, two_b, two_c, two_d, two_e, two_f)wigner::wigner_6j(const wigner::wigner_6j_args&)wigner::wigner_9j(two_a, two_b, two_c, two_d, two_e, two_f, two_g, two_h, two_i)wigner::wigner_9j(const wigner::wigner_9j_args&)wigner::triangle_coefficient(two_j1, two_j2, two_j3)wigner::allowed_projections(two_j)wigner::allowed_couplings(two_j1, two_j2)wigner::allowed_couplings_12(two_j1, two_j2, two_j3, two_j)wigner::allowed_couplings_13(two_j1, two_j2, two_j3, two_j)wigner::allowed_couplings_23(two_j1, two_j2, two_j3, two_j)wigner::allowed_canonical_3j_arguments(max_two_j)wigner::allowed_canonical_6j_arguments(max_two_j)wigner::allowed_canonical_9j_arguments(max_two_j)wigner::allowed_canonical_12j_first_arguments(max_two_j)wigner::allowed_canonical_12j_second_arguments(max_two_j)wigner::racah_w(two_j1, two_j2, two_j12, two_j3, two_j, two_j23)wigner::recoupling_12_23(two_j1, two_j2, two_j12, two_j3, two_j, two_j23)wigner::recoupling_12_13(two_j1, two_j2, two_j12, two_j3, two_j, two_j13)wigner::recoupling_13_23(two_j1, two_j2, two_j13, two_j3, two_j, two_j23)wigner::recoupling(two_j1, two_j2, two_j12, two_j3, two_j, two_j23)wigner::clebsch_gordan(two_j1, two_m1, two_j2, two_m2, two_j3, two_m3)wigner::gaunt(l1, m1, l2, m2, l3, m3)wigner::spherical_harmonic(l, m, theta, phi)wigner::spherical_harmonic(l, m, x, y, z)wigner::wigner_d(two_j, two_m, two_n, beta)wigner::wigner_D(two_j, two_m, two_n, alpha, beta, gamma)
Example:
#include <iostream>
#include <wigner/wigner.hpp>
int main()
{
std::cout << wigner::wigner_3j(1, 1, 0, 1, -1, 0) << '\n';
std::cout << wigner::wigner_6j(1, 1, 0, 1, 1, 0) << '\n';
std::cout << wigner::wigner_9j(0, 1, 1, 1, 0, 1, 1, 1, 0) << '\n';
std::cout << wigner::racah_w(1, 1, 0, 1, 1, 0) << '\n';
std::cout << wigner::recoupling(1, 1, 0, 1, 1, 0) << '\n';
}A buildable version of this lives in examples/basic.cpp. There is also a doubled-spin walkthrough in examples/doubled_spin.cpp. For the new spherical-harmonic helpers, see examples/spherical_harmonics.cpp. Reference-style command-line tools live in exe.
All angular momenta are passed as doubled integers.
two_j = 0meansj = 0two_j = 1meansj = 1/2two_j = 2meansj = 1
Likewise for magnetic quantum numbers:
two_m = -1meansm = -1/2two_m = 2meansm = 1
This keeps the core SU(2) API simple while supporting both integer and half-integer spins without a custom rational type.
The 12j helpers use the same doubled notation, but package their 12 angular
momenta into explicit argument structs so the ring ordering is clear at the
call site:
wigner::wigner_3j_argswigner::wigner_6j_argswigner::wigner_9j_argswigner::wigner_12j_first_argswigner::wigner_12j_second_args
The same helper layer also exposes canonical argument enumerators. These are mainly useful for tests, table-generation experiments, or user code that wants to scan only one representative from each symmetry class instead of every raw argument tuple.
Two public helpers use ordinary integer orbital-angular-momentum notation instead:
wigner::gaunt(l1, m1, l2, m2, l3, m3)wigner::spherical_harmonic(l, m, theta, phi)wigner::spherical_harmonic(l, m, x, y, z)
A small example focused just on this convention is available in examples/doubled_spin.cpp.
The current library keeps the implementation deliberately simple:
wigner_3j,wigner_6j, andwigner_9juse direct algorithms indetailwigner_12j_firstandwigner_12j_seconduse Wei's factorized single-sum formulas over reduced6jfactorsracah_wandrecouplingare computed fromwigner_6jclebsch_gordanis computed fromwigner_3jgauntis computed fromwigner_3jspherical_harmonicis computed fromwigner_d- the Cartesian
spherical_harmonic(l,m,x,y,z)overload converts the vector direction to polar angles and then reuses the same implementation wigner_dandwigner_Dare computed directly
This makes the code easier to reason about while the library is still being stabilized.
The helper APIs for allowed_projections, allowed_couplings*, and
allowed_canonical_*_arguments are intended to make basis enumeration explicit
and reusable, rather than having each executable or test build those loops by
hand.
Standalone inspection tools live in exe and are built when WIGNER_BUILD_EXECUTABLES=ON.
print_cg_table <target_two_j> [--two-j-max=N] [--all-rows]prints a fixed-jClebsch-Gordan table grouped by contributingj1 x j2channelsprint_cg <two_j1> <two_j2> [two_j]prints the Clebsch-Gordan coefficient tables for all allowed coupledtwo_jvalues, or one chosen coupling channel whentwo_jis providedprint_3j <two_j1> <two_j2> <two_j3>prints all nonzero Wigner3jrows for one fixed channelprint_6j <two_a> <two_b> <two_c> <two_d> <two_e> <two_f>prints one Wigner6jsymbol in decimal and symbolic formprint_9j <two_a> <two_b> <two_c> <two_d> <two_e> <two_f> <two_g> <two_h> <two_i>prints one Wigner9jsymbol in decimal and symbolic formprint_3j_table <target_two_j3> [--two-j-max=N] [--all-rows]prints a fixed-j3Wigner3jtable grouped by contributingj1 x j2channelsprint_6j_table [--two-j-max=N]prints a Varshalovich-inspired canonical6jtableprint_9j_table [--two-j-max=N]prints a canonical nonzero9jtable in standard3 x 3layoutprint_wigner_d_matrix <two_j> [--symbolic]prints the Wigner littledmatrix for fixedjatbeta = pi/2, either numerically or in rationalized symbolic formprint_triangle_table [--two-j-max=N]prints a Varshalovich-inspired triangle-coefficient tableprint_recoupling <two_j1> <two_j2> <two_j3> [two_j] [--matrix] [--symbolic] [--scheme=12-23|12-13|13-23]prints recoupling coefficients for every allowed totalJ, or for one fixedJwhentwo_jis provided, in flat or matrix form for the chosen coupling scheme, with optional symbolic output
The project is set up for g++-14 and C++23.
A small helper script is available at scripts/build.sh.
It configures the project in build/gcc14 with g++-14, examples, tests, and executable tools enabled.
Examples:
./scripts/build.sh
./scripts/build.sh --testscmake -S . -B build/gcc14 \
-DCMAKE_CXX_COMPILER=g++-14 \
-DWIGNER_BUILD_TESTS=ON \
-DWIGNER_BUILD_EXAMPLES=ON \
-DWIGNER_BUILD_EXECUTABLES=ON
cmake --build build/gcc14
./build/gcc14/examples/wigner_example_basic
./build/gcc14/examples/wigner_example_doubled_spin
./build/gcc14/examples/wigner_example_spherical_harmonics
./build/gcc14/exe/print_cg_table 2 --two-j-max=6
./build/gcc14/exe/print_cg 1 1
./build/gcc14/exe/print_3j 1 1 0
./build/gcc14/exe/print_6j 1 1 0 1 1 0
./build/gcc14/exe/print_9j 0 1 1 1 0 1 1 1 0
./build/gcc14/exe/print_9j_table --two-j-max=4
./build/gcc14/exe/print_wigner_d_matrix 2
./build/gcc14/exe/print_wigner_d_matrix 2 --symbolic
./build/gcc14/exe/print_recoupling 1 1 1 1 --matrix
./build/gcc14/exe/print_recoupling 1 1 1 1 --matrix --symbolic
./build/gcc14/exe/print_recoupling 1 1 1 1 --matrix --scheme=12-13
ctest --test-dir build/gcc14 --output-on-failureImportant cache variables:
WIGNER_BUILD_TESTSbuild the test executableWIGNER_BUILD_EXAMPLESbuild the example programsWIGNER_BUILD_EXECUTABLESbuild standalone executable tools
You can override them directly at configure time. For example:
cmake -S . -B build/custom \
-DCMAKE_CXX_COMPILER=g++-14 \
-DWIGNER_BUILD_TESTS=ON \
-DWIGNER_BUILD_EXAMPLES=ON \
-DWIGNER_BUILD_EXECUTABLES=ONMIT License. See LICENSE.
- This library currently targets practical low-spin use, not arbitrarily large angular momentum.
- The public API is intentionally small and integer-based.
clebsch_gordanis computed fromwigner_3j; it does not maintain a separate table.gauntuses the standard spherical-harmonic relation towigner_3j.spherical_harmonicuses the standard relation towigner_d.wigner_dandwigner_Dare computed directly.
The project documentation uses Doxygen for C++ extraction and Sphinx for the published HTML and PDF output.
To install the docs-only Python dependencies:
./scripts/setup_docs.shTo build the documentation:
./scripts/build_docs.shOutputs are written to:
docs/build/html/index.htmldocs/build/latex/wigner.pdf
Implemented and tested:
wigner_3jwigner_12j_firstwigner_12j_secondwigner_6jwigner_9jracah_wrecouplingclebsch_gordangauntspherical_harmonicwigner_dwigner_D
The test suite currently uses CTest with a small standard-library-only executable in tests/test_main.cpp.