DMRG¶
The Density Matrix Renormalization Group (DMRG) finds the ground state of a 1D quantum Hamiltonian given as a Matrix Product Operator (MPO).
Background¶
DMRG variationally optimises a Matrix Product State (MPS) by sweeping through the chain and updating one or two site tensors at a time. At each step it solves a local eigenvalue problem (Lanczos) for the effective Hamiltonian projected into the MPS subspace, then truncates via SVD to control the bond dimension.
Key properties of the Tenax implementation:
2-site and 1-site variants (
DMRGConfig.two_site).Outer sweep loop is a Python for-loop (bond dimensions change dynamically).
The effective Hamiltonian matvec is
@jax.jitcompiled.Lanczos eigensolver uses a simple Python loop (suitable for moderate iteration counts).
Configuration¶
from tenax import DMRGConfig
config = DMRGConfig(
max_bond_dim=64, # maximum MPS bond dimension
num_sweeps=30, # full left-right sweep cycles
convergence_tol=1e-10, # stop early when |dE| < tol
two_site=True, # 2-site DMRG (allows bond growth)
lanczos_max_iter=50, # Lanczos iteration cap
lanczos_tol=1e-12, # Lanczos convergence tolerance
noise=0.0, # density-matrix perturbation
verbose=True,
)
Example – Heisenberg chain¶
from tenax import (
DMRGConfig, dmrg,
build_mpo_heisenberg, build_random_mps,
)
L = 20
mpo = build_mpo_heisenberg(L, Jz=1.0, Jxy=1.0, hz=0.0)
mps = build_random_mps(L, physical_dim=2, bond_dim=4)
config = DMRGConfig(max_bond_dim=64, num_sweeps=30, verbose=True)
result = dmrg(mpo, mps, config)
print(f"Energy: {result.energy:.10f}")
print(f"Converged: {result.converged}")
print(f"Sweeps: {len(result.energies_per_sweep)}")
Result object¶
dmrg() returns a DMRGResult named tuple:
Field |
Type |
Description |
|---|---|---|
|
|
Final ground-state energy |
|
|
Energy at the end of each sweep |
|
|
Optimised MPS |
|
|
Truncation error at each bond update |
|
|
Whether energy converged within tolerance |
MPO construction¶
build_mpo_heisenberg builds the standard 5-state MPO for the XXZ
Heisenberg model:
For custom Hamiltonians, see the AutoMPO tutorial.
Example – 2D Heisenberg cylinder¶
For 2D systems, map the lattice to a 1D chain (column-major ordering) and
use AutoMPO to build the long-range MPO:
from tenax import AutoMPO, DMRGConfig, build_random_mps, dmrg
Lx, Ly, N = 8, 4, 32
auto = AutoMPO(L=N, d=2)
for x in range(Lx):
for y in range(Ly):
# Within-ring bond (periodic y-direction)
i, j = x * Ly + y, x * Ly + (y + 1) % Ly
auto += (1.0, "Sz", min(i,j), "Sz", max(i,j))
auto += (0.5, "Sp", min(i,j), "Sm", max(i,j))
auto += (0.5, "Sm", min(i,j), "Sp", max(i,j))
# Between-ring bond (open x-direction)
if x < Lx - 1:
i, j = x * Ly + y, (x + 1) * Ly + y
auto += (1.0, "Sz", i, "Sz", j)
auto += (0.5, "Sp", i, "Sm", j)
auto += (0.5, "Sm", i, "Sp", j)
mpo = auto.to_mpo(compress=True)
mps = build_random_mps(N, physical_dim=2, bond_dim=16)
config = DMRGConfig(max_bond_dim=200, num_sweeps=15, verbose=True)
result = dmrg(mpo, mps, config)
print(f"E/N = {result.energy / N:.8f}")
See examples/heisenberg_cylinder.py for a complete working example with
multiple cylinder sizes and exact-diagonalisation cross-checks.
Label conventions¶
MPS and MPO tensors follow these leg-label conventions:
MPS site tensors:
Left virtual bond:
v{i-1}_{i}Physical leg:
p{i}Right virtual bond:
v{i}_{i+1}Boundary sites omit one virtual bond
MPO site tensors:
Left MPO bond:
w{i-1}_{i}Top physical (ket):
mpo_top_{i}Bottom physical (bra):
mpo_bot_{i}Right MPO bond:
w{i}_{i+1}