Skip to content

SU2Group

SU(2) non-Abelian symmetry group with spin-based quantum numbers.

SU2Group dataclass

SU2Group()

Bases: UnitaryGroup

SU(2) symmetry group with integer-valued quantum numbers.

The SU(2) group represents rotational symmetry in quantum mechanics. Quantum numbers are non-negative integers representing twice the physical spin (2j convention): 0, 1, 2, 3, 4, ... corresponding to physical spins 0, ½, 1, 3/2, 2, ...

This convention avoids fractions while preserving all half-integer spins.

Fusion of two spins follows the triangular inequality: 2j1 ⊗ 2j2 → |2j1 - 2j2|, |2j1 - 2j2| + 2, ..., 2j1 + 2j2 (step size: 2)

Examples:

>>> group = SU2Group()
>>> group.neutral
0
>>> # Spin-1/2 ⊗ spin-1/2 (1 ⊗ 1 in 2j notation) → 0, 2 (spin-0, spin-1)
>>> group.fuse_channels(1, 1)
(0, 2)
>>> # Spin-1 ⊗ spin-1 (2 ⊗ 2) → 0, 2, 4 (spin-0, spin-1, spin-2)
>>> group.fuse_channels(2, 2)
(0, 2, 4)
>>> # SU(2) representations are self-dual
>>> group.dual(3)  # spin-3/2
3

Attributes

name property

name: str

Return the group name.

neutral property

neutral: int

Return the neutral element (spin-0, represented as 2j=0).

Functions

irrep_dim

irrep_dim(two_j: int) -> int

Return dimension of spin-j irreducible representation.

For SU(2), the dimension of a spin-j representation is 2j+1.

Parameters:

Name Type Description Default
two_j int

Quantum number (2j, where j is the physical spin).

required

Returns:

Type Description
int

Dimension of the representation: 2j + 1.

dual

dual(two_j: int) -> int

Return the dual representation.

For SU(2), all representations are self-dual (real), meaning the dual of a spin-j representation is spin-j itself.

Parameters:

Name Type Description Default
two_j int

Quantum number (2j, where j is the physical spin).

required

Returns:

Type Description
int

The same quantum number (2j).

fuse_channels

fuse_channels(*two_js: int) -> Tuple[int, ...]

Fuse multiple spins, returning all possible total spin channels.

Returns all total spin values achievable by fusing the given spins, independent of the fusion tree structure. For SU(2), any value from the minimum to maximum in steps of 2 can be achieved by some choice of fusion tree.

In the 2j convention:

  • For two spins: 2j1 ⊗ 2j2 → |2j1 - 2j2|, ..., 2j1 + 2j2 (step: 2)
  • For n spins: 2j_min, 2j_min + 2, ..., 2j_max where:
  • 2j_max = 2j1 + 2j2 + ... + 2jn (all aligned)
  • 2j_min: largest value ≤ |2j_largest - sum_of_others| with matching integrality

Integrality constraint: All achievable total spins must be either all integer or all half-integer. In 2j notation, this means all returned values have the same parity (even for integer, odd for half-integer).

Parameters:

Name Type Description Default
*two_js int

One or more quantum numbers (2j values) to fuse.

()

Returns:

Type Description
Tuple[int, ...]

Tuple of all achievable total spin channels (2j values), sorted from smallest to largest. The actual fusion tree structure needed to achieve each value is determined by external packages.

Examples:

>>> group = SU2Group()
>>> # Spin-1/2 ⊗ spin-1/2 (1 ⊗ 1)
>>> group.fuse_channels(1, 1)
(0, 2)
>>> # Spin-1 ⊗ spin-1 (2 ⊗ 2)
>>> group.fuse_channels(2, 2)
(0, 2, 4)
>>> # Three spin-1/2 (1 ⊗ 1 ⊗ 1)
>>> group.fuse_channels(1, 1, 1)
(1, 3)
>>> # Spin-1 ⊗ spin-1 ⊗ spin-1/2 (2 ⊗ 2 ⊗ 1)
>>> group.fuse_channels(2, 2, 1)
(1, 3, 5)
>>> # Four spin-1/2 (1 ⊗ 1 ⊗ 1 ⊗ 1)
>>> group.fuse_channels(1, 1, 1, 1)
(0, 2, 4)

equal

equal(a: int, b: int) -> bool

Check if two quantum numbers are equal.

Parameters:

Name Type Description Default
a int

Quantum numbers (2j values) to compare.

required
b int

Quantum numbers (2j values) to compare.

required

Returns:

Type Description
bool

True if the quantum numbers are equal.

validate_charge

validate_charge(two_j: Any) -> None

Validate that a charge is a valid SU(2) quantum number.

Valid SU(2) charges are non-negative integers representing 2j, where j is the physical spin: 0, 1, 2, 3, 4, ... corresponding to physical spins 0, ½, 1, 3/2, 2, ...

Parameters:

Name Type Description Default
two_j Any

Charge to validate (should be 2j as an integer).

required

Raises:

Type Description
TypeError

If charge is not an integer.

ValueError

If charge is negative.

Examples:

>>> group = SU2Group()
>>> group.validate_charge(0)   # Valid: spin-0 (2j=0)
>>> group.validate_charge(1)   # Valid: spin-1/2 (2j=1)
>>> group.validate_charge(2)   # Valid: spin-1 (2j=2)
>>> group.validate_charge(3)   # Valid: spin-3/2 (2j=3)
>>> group.validate_charge(-1)  # Raises ValueError
>>> group.validate_charge(1.5) # Raises TypeError

Description

Represents the SU(2) group of rotational symmetry. Unlike Abelian groups, SU(2) representations have an internal dimension (irrep dimension) and fuse into multiple channels simultaneously via Clebsch–Gordan decomposition.

Charge Convention: 2j Integers

Charges are non-negative integers representing twice the physical spin (the 2j convention):

Charge (2j) Physical spin j Irrep dim (2j+1)
0 0 1 (singlet)
1 1/2 2 (doublet)
2 1 3 (triplet)
3 3/2 4 (quartet)
4 2 5 (quintet)

This convention keeps all quantum numbers as plain integers, avoiding fractions for half-integer spins.

Irrep Dimension

Every SU(2) charge carries an irrep dimension equal to 2j + 1. This is the number of magnetic quantum number states (m = -j, ..., +j) within each multiplet. Nicole works in the reduced tensor formalism: each block in a tensor stores the reduced tensor element, and the full tensor elements are reconstructed by contracting with Clebsch–Gordan coefficients stored in Bridge intertwiners.

Fusion Channels

SU(2) spins fuse via the triangular inequality — two spins j1 and j2 can combine into any total spin from |j1 − j2| to j1 + j2 in integer steps. In 2j notation:

from nicole import SU2Group

group = SU2Group()

# Spin-1/2 ⊗ spin-1/2 → spin-0 or spin-1
group.fuse_channels(1, 1)   # (0, 2)

# Spin-1 ⊗ spin-1 → spin-0, spin-1, or spin-2
group.fuse_channels(2, 2)   # (0, 2, 4)

# Three spin-1/2 → spin-1/2 or spin-3/2
group.fuse_channels(1, 1, 1)  # (1, 3)

Self-Duality

All SU(2) representations are self-dual — the contragredient of a spin-j representation is again spin-j:

group.dual(0)  # 0  (singlet is its own dual)
group.dual(1)  # 1  (doublet is its own dual)
group.dual(2)  # 2  (triplet is its own dual)

Physical Applications

  • Spin-S systems: Arbitrary spin magnitude, e.g. spin-½ chains, spin-1 Haldane chains
  • Angular momentum conservation: Total angular momentum of a multi-particle system
  • Wigner–Eckart theorem: Operator matrix elements factorize into CG coefficients and a single reduced matrix element

Using with Product Group

SU2Group can be combined with Abelian groups via ProductGroup. The SU(2) factor must always be the last component:

from nicole import ProductGroup, U1Group, Z2Group, SU2Group

# U(1) × SU(2): particle number + full spin rotation (e.g. Hubbard model)
group = ProductGroup([U1Group(), SU2Group()])
print(group.name)      # "U1×SU2"
print(group.neutral)   # (0, 0)
print(group.is_abelian)  # False

# Charges are tuples (n, 2j)
# e.g. (2, 1) means 2 particles above, spin-1/2 multiplet

Index and Sector Semantics

For SU(2) tensors, Sector(charge=2j, dim=n) means n independent spin-j multiplets. The total number of physical states in that sector is n × (2j + 1), accessible via Index.num_states:

from nicole import Index, Sector, Direction, SU2Group

group = SU2Group()
idx = Index(
    Direction.OUT,
    group,
    sectors=(
        Sector(charge=0, dim=1),  # 1 singlet  → 1 physical state
        Sector(charge=1, dim=2),  # 2 doublets → 4 physical states
        Sector(charge=2, dim=1),  # 1 triplet  → 3 physical states
    )
)

print(idx.dim)         # 4  (total multiplets: 1 + 2 + 1)
print(idx.num_states)  # 8  (total states: 1×1 + 2×2 + 1×3)

See Also

Notes

  • SU(2) tensors carry intertwiners (yuzuha Bridge objects) attached to each data block; these encode the Clebsch–Gordan structure in the R-W-C decomposition and are managed automatically by Nicole. See the Yuzuha Protocol for a full explanation.
  • All standard operations (contract, trace, decomp, permute, conj, etc.) handle SU(2) transparently.
  • is_abelian returns False for SU2Group and for any ProductGroup containing it.