Symmetries
TensorKit for MPS users already showed the key fact: a symmetry in MPSKit is not a flag passed to an algorithm, it is a property of the vector spaces that a tensor is built from, and every algorithm is written once, generically, for any such space. That page built the mental model of a TensorMap and introduced graded spaces through a single ℤ₂ example. This page stays at the same level of abstraction but widens the lens: what kinds of symmetry a graded space can encode, what changes qualitatively as you move from an abelian group to a non-abelian one or to fermionic or anyonic statistics, and — the question every user eventually asks — when the extra bookkeeping of a bigger symmetry group is actually worth it. For the hands-on version of the ℤ₂ case worked all the way through a ground-state search, see Using symmetries; this page explains the reasoning behind that recipe and extends it to the other symmetry classes MPSKit supports.
As on the sibling page, none of the symmetry machinery lives in MPSKit or MPSKitModels itself: using MPSKit does not bring a single sector or space type into scope, and neither does using MPSKitModels. Every symmetric object — Z2Irrep, U1Irrep, SU2Irrep, Z2Space, U1Space, and so on — comes from TensorKit, so every example on this page loads all three packages explicitly.
using MPSKit, MPSKitModels, TensorKitSectors, charges, and block-sparsity
A sector is a label for an irreducible representation of the symmetry: for a group symmetry it is one irrep, and a graded space is built by declaring how many copies ("degeneracy" or "multiplicity") of each sector it contains. TensorKit for MPS users did this for ℤ₂ with Z2Space(0 => 1, 1 => 1); the same sector => degeneracy syntax works for every symmetry, so a U(1)-graded space that keeps track of, say, a conserved particle number or magnetization from -1 to 1 reads:
V = U1Space(-1 => 1, 0 => 1, 1 => 1)
dim(V)3The space still knows its full sector content, queryable with sectors and dim applied to a specific sector:
collect(sectors(V))3-element Vector{TensorKitSectors.U1Irrep}:
0
1
-1[dim(V, c) for c in sectors(V)]3-element Vector{Int64}:
1
1
1Charge conservation is the statement that a symmetric tensor may only have nonzero entries between sectors whose charges add up correctly (for a Hamiltonian term, incoming and outgoing charge must match). Concretely this means the tensor is block-diagonal in the sector label: what would be one dense array for a plain ℂ^n space becomes a handful of smaller, independent dense blocks, one per allowed sector combination, and the entries that connect different sectors are not merely zero — they are never allocated or touched at all. This is the mechanism behind everything that follows: the type of symmetry only changes what the sector labels are and how they combine (their fusion rules); the block-sparse storage and the charge-conservation bookkeeping are handled identically underneath.
A taxonomy of symmetry types
MPSKitModels' heisenberg_XXX model is a convenient single thread through the taxonomy, because the same Heisenberg Hamiltonian can be built with a trivial symmetry or with any of the three main non-trivial types below, purely by passing a different sector type as the first argument:
H_triv = heisenberg_XXX(FiniteChain(4); spin = 1 // 2)
H_Z2 = heisenberg_XXX(Z2Irrep, FiniteChain(4); spin = 1 // 2)
H_U1 = heisenberg_XXX(U1Irrep, FiniteChain(4); spin = 1 // 2)
H_SU2 = heisenberg_XXX(SU2Irrep, FiniteChain(4); spin = 1 // 2)4-site FiniteMPOHamiltonian(ComplexF64, Rep[SU₂]) with maximal dimension 5:
┬─[4]─ (1/2 => 1)
│ ((0=>1) ⊞ (1=>1) ⊞ (0=>1))
┼─[3]─ (1/2 => 1)
│ ((0=>1) ⊞ (1=>1) ⊞ (0=>1))
┼─[2]─ (1/2 => 1)
│ ((0=>1) ⊞ (1=>1) ⊞ (0=>1))
┴─[1]─ (1/2 => 1)Four Hamiltonians, four different tensor structures, one physical model.
Abelian symmetries: ℤ_N and U(1)
Z2Irrep, Z3Irrep, Z4Irrep, and the general ZNIrrep, together with U1Irrep, are the abelian family: their sectors are literally the elements of ℤ_N or of the integers (or half-integers), and two sectors fuse by addition modulo N, or ordinary addition for U(1). Every irrep is one-dimensional, so an abelian symmetry buys exactly the block-sparsity described above and nothing more: H_Z2above encodes the same spin-flip parity used throughout [Using symmetries](@ref tutorial_using_symmetries), whileH_U1encodes conservation of total magnetizationS^z_{\mathrm{tot}}$, with sectors running over the possible values of$S^z_{\mathrm{tot}}.transverse_field_isingis a useful reminder that not every model has every symmetry available: it acceptsTrivial,Z2Irrep, orFermionParity, but raises an error forU1Irrep, because the transverse-field Ising model genuinely only has the ℤ₂ spin-flip symmetry — there is no conserved U(1) charge to exploit.
Non-abelian symmetries: SU(2)
SU2Irrep sectors are labelled by a total spin H_SU2 above is built exactly this way: it is the same Heisenberg chain, only now every eigenstate additionally carries a total-spin label, and the tensors only ever store one number per multiplet rather than one number per individual magnetic sublevel. The next section makes this saving concrete.
Fermionic symmetries and product sectors
FermionParity grades a space into an even and an odd fermion-number sector, and — crucially — TensorKit's fermionic tensor category attaches the anticommutation sign directly to the braiding of FermionParity-graded legs, so that once physical and virtual legs carry this sector, index permutations automatically pick up the correct fermionic signs instead of requiring the sign rule to be implemented by hand in every algorithm (Mortier et al., 2025). Models with more than one physical species combine sectors with ⊠ (typed \boxtimes) into a ProductSector, for instance an odd fermion paired with unit U(1) charge:
FermionParity(1) ⊠ U1Irrep(1)(FermionParity(1) ⊠ Irrep[U₁](1))hubbard_model exercises this directly: it takes an independent particle symmetry and spin symmetry, and assembles the physical space internally out of FermionParity ⊠ (particle symmetry) and FermionParity ⊠ (spin symmetry) pieces. Choosing U(1) for particle number and SU(2) for spin gives the maximally symmetric Hubbard chain:
H_hub = hubbard_model(ComplexF64, U1Irrep, SU2Irrep, FiniteChain(4); t = 1.0, U = 8.0)4-site FiniteMPOHamiltonian(ComplexF64, Vect[(FermionParity ⊠ Irrep[U₁] ⊠ Irrep[SU₂])]) with maximal dimension 6:
┬─[4]─ ((0, 0, 0) => 1, (1, 1, 1/2) => 1, (0, 2, 0) => 1)
│ (((0, 0, 0)=>1) ⊞ ((1, 1, 1/2)=>1, (1, -1, 1/2)=>1) ⊞ ((0, 0, 0)=>1))
┼─[3]─ ((0, 0, 0) => 1, (1, 1, 1/2) => 1, (0, 2, 0) => 1)
│ (((0, 0, 0)=>1) ⊞ ((1, 1, 1/2)=>1, (1, -1, 1/2)=>1) ⊞ ((0, 0, 0)=>1))
┼─[2]─ ((0, 0, 0) => 1, (1, 1, 1/2) => 1, (0, 2, 0) => 1)
│ (((0, 0, 0)=>1) ⊞ ((1, 1, 1/2)=>1, (1, -1, 1/2)=>1) ⊞ ((0, 0, 0)=>1))
┴─[1]─ ((0, 0, 0) => 1, (1, 1, 1/2) => 1, (0, 2, 0) => 1)The first argument is the scalar element type, required here because a lattice is given explicitly; the two symmetry types then set the particle-number and spin symmetries in that order.
By contrast, bose_hubbard_model only accepts Trivial or U1Irrep: bosons carry no parity grading, so there is no fermionic sign to encode and no spin degree of freedom to make non-abelian. At the far end of this spectrum, quantum_chemistry_hamiltonian does not expose a symmetry choice at all — it always builds its tensors with the fixed, maximal
Anyonic symmetries
The generality goes further than groups. Sectors such as FibonacciAnyon or IsingAnyon are not group representations at all — their fusion rules come from a modular tensor category — yet because every MPSKit algorithm is written against the abstract Sector interface, they are handled by exactly the same code paths, with no special-casing. The hard-hexagon model example puts this to work: its transfer matrix is built from FibonacciAnyon-graded tensors (Vect[FibonacciAnyon](:I => …, :τ => …)), and the standard statistical-mechanics workflow computes its partition function just as it would for an ordinary symmetry.
When does SU(2) pay off
Two distinct effects are at play whenever a symmetry is switched on, and it is worth separating them because only one of them scales with the size of the symmetry group.
The first effect is the block-sparsity already described: at a fixed total bond dimension, the computer multiplies several smaller dense blocks instead of one large one, and the (forbidden) cross-sector entries are never stored. Using symmetries demonstrates this concretely for ℤ₂: the same 16-dimensional bond becomes two roughly-8-dimensional blocks. This first effect is present for any symmetry, abelian or not, and its benefit grows with the number of distinct sectors the bond dimension gets spread over.
The second effect is specific to non-abelian symmetries and is qualitatively larger: because a whole
V_SU2 = SU2Space(0 => 2, 1 // 2 => 4)
dim(V_SU2)10[dim(V_SU2, c) for c in sectors(V_SU2)]2-element Vector{Int64}:
2
4The total dimension dim(V_SU2) is 10, because each spin-dim(V_SU2, c) returns the stored multiplicity of each sector — here [2, 4], just six numbers in total — because the
The gap between the physical dimension (10) and the six numbers actually stored is the source of SU(2)'s reputation for letting DMRG reach much larger effective bond dimensions at the same computational cost — the same principle used to push non-abelian symmetric uniform MPS to large SU(3) bond dimensions in practice (Devos et al., 2022).
None of this is free. Every symmetric block carries the overhead of tracking fusion trees and recombining Clebsch–Gordan coefficients whenever legs are permuted or contracted, and for a non-abelian group this bookkeeping is genuinely more expensive per block than for an abelian one. In practice this means SU(2) (or any non-abelian symmetry) is worth reaching for when the physics genuinely has that symmetry — a spin chain with full rotational invariance, for instance — and when the bond dimension is large enough that the multiplet-reduction saving dominates the per-block overhead; for small bond dimensions, or for a symmetry the Hamiltonian does not actually have, the abelian or even trivial case is often simpler and just as fast.
Fixing the total charge
Sector labels are not only a storage optimization: they are physical quantum numbers, and MPSKit lets a calculation target a specific one directly.
For an MPS, the total charge is fixed by giving the state a non-trivial left or right virtual space, rather than the default unit (trivial-charge) one:
ψ_odd = FiniteMPS(
4, Z2Space(0 => 1, 1 => 1), Z2Space(0 => 2, 1 => 2);
left = Z2Space(1 => 1)
)
left_virtualspace(ψ_odd, 1)Rep[ℤ₂](…) of dim 1:
1 => 1Every tensor in ψ_odd is now forced, by charge conservation, to represent a state of odd total parity — there is no way for a symmetric MPS built this way to drift into the even sector. The same idea appears for excited states and for transfer-matrix spectra: the sector keyword of excitations and of transfer_spectrum restricts the search to a chosen total charge instead of the default trivial one, exactly as used to isolate the odd-parity excitation of the TFIM in Using symmetries. Excited states collects further recipes for working with sector, and Constructing states collects the analogous recipes for building states with a prescribed symmetry and charge.
Where to go next
For the tensor mechanics underneath all of this — spaces,
TensorMaps, index conventions — see TensorKit for MPS users.For the fully worked ℤ₂ example, from Hamiltonian to ground state to a sector-targeted excitation, see Using symmetries.
For how symmetric tensors assemble into states and operators, see Matrix product states and Operators and Hamiltonians.
For task recipes that use a
sectoror a charged virtual space, see Constructing states, Excited states, and Entanglement entropy and spectrum.
<!– Maintainer notes (not rendered):
All @example blocks were executed end-to-end in one shared session against TensorKit v0.17.0 / MPSKitModels v0.4.7 (docs project). heisenberg_XXX needs an explicit spin = 1 // 2 (default spin = 1; Z2Irrep is spin-1/2 only), and hubbard_model needs an explicit ComplexF64 element type when a lattice is passed — both now reflected in the code above.
No bib entry directly supports the canonical SU(2)-specific non-abelian-DMRG scaling claim; devos2022 (SU(3)) is used as the closest available citation and flagged as such. Consider adding a citation for this if the maintainer has one on hand (e.g. a symmetric DMRG methods paper).
–>