Periodic XXX chains: states and conventions¶
This guide connects a numerical result to the periodic spin-1/2 Heisenberg model it represents. Start with the Hamiltonian normalization, then follow the quantum numbers through to rapidities, energy, and momentum. For a first command-line run, see the CLI guide. For plotted finite-size and boundary comparisons, see the XXX tutorial. For intensities as well as energies, see the finite-ring two-spinon structure factor.
Hamiltonian and normalization¶
The Hamiltonian is
This is the spin-1/2, not Pauli-matrix, normalization. For N=2 the periodic sum counts the bond twice, giving E=-3/2. For N=4, E=-2; for N=6, E=-(2+sqrt(13))/2. Complex roots and infinite-root SU(2) descendants are not supported by this solver. The API here is periodic; free-end XXX and finite-size XXZ have separate APIs. Boundary fields and other boundary conditions remain unsupported.
Calculate a state from C++¶
#include <bethe/heisenberg.hpp>
auto result = bethe::heisenberg::ground_state<long double>(16);
if (!result.converged) {
// Inspect result.residual_norm and result.iterations, or increase the budget.
}
// result.energy includes N/4; result.rapidities contains the N/2 real roots.
using uni20::half_int;
auto sector = bethe::heisenberg::sector_ground_state<long double>(15, half_int::parse("3/2"));
auto sectors = bethe::heisenberg::sector_ground_states<long double>(16);
auto branch = bethe::heisenberg::one_spinon_branch<long double>(65);
bethe::heisenberg::QuantumNumbers numbers{half_int{-1}, half_int{1}};
auto specified = bethe::heisenberg::solve_real<long double>(5, numbers);
// Optional initial roots are the fourth solve_real argument, after options.
Rapidity and quantum-number conventions¶
For M finite real roots, the conventions are:
solve_real uses \(S^z =N /2-M\) and the conventional all-1-string quantum-number
window: \(M \le N /2\), \(\lvert 2I_{i} \rvert \le N -M -1\), and \(2I_{i}\) has the parity of \(N -M -1\).
This explicitly supported window is not a classification of every real-root
solution. Quantum numbers and \(S^z\) use uni20::half_int; conversion to the
selected real type uses the doubled integer directly, never to_double().
The empty quantum-number set gives the fully polarized state.
Sectors and state labels¶
For sector minima, \(M =N /2-\lvert S^z \rvert\). Even chains occupy the consecutive numbers
\(I_{i} =i -(M -1)/2\), with zero-based \(i\). Odd chains use \(I_{i} =i -M /2\), one of two
reflection-related minima when \(M \gt 0\); negating and reversing that sequence
selects the other momentum. Negative \(S^z\) uses the all-down reference vacuum
and sets spin_reversed=true. Its roots count up spins rather than down spins.
RealState<Real> contains the roots, quantum numbers, sz, energy, diagnostics,
and an exact integer momentum_index with P=2*pi*momentum_index/N in \([0,2\,\pi)\).
The integer index is derived modulo \(N\), without rounding floating-point phases.
GroundState<Real> remains an alias for compatibility. Results with
converged=false are numerical iterates, not established eigenstates; their
momentum labels specify the requested state.
Iteration and convergence¶
The simultaneous fixed-point update starts at zero roots and follows Eq. (9)
of the reference paper. It uses
compensated phase/energy sums, O(M^2) work per sweep, and O(M) storage per state.
The helpers returning all sectors or an entire branch retain every state's
roots, using O(N^2) storage. Use the single-state functions to stream large scans.
Convergence means max_i abs(F_i)/N <= residual_tolerance; the default is
32 times the selected type's epsilon. This is a residual test, not a rigorous
energy-error bound. Unsupported inputs throw std::invalid_argument, nonfinite
arithmetic throws std::runtime_error, and budget exhaustion returns the last
roots with converged=false.
Arbitrary precision¶
The precision tutorial demonstrates an energy scale that is lost in binary64, with exact-reference checks and a comparison of stable formulas versus additional working precision.
With MPFR enabled, every
bethe-xxx-pbc mode accepts bits-N or digits-N:
bethe-xxx-pbc 32 --precision digits-100 --roots
bethe-xxx-pbc 16 --sectors --precision bits-256
bethe-xxx-pbc 17 --spinons --precision bits-256
bethe-xxx-pbc 16 --excitations all --threads 4 --precision bits-256
This includes --sz (also negative sectors) and --quantum-numbers.
Tolerance parsing, root iterations, energies, momenta, spinon bulk subtraction
and file output all use the selected precision. The default root tolerance is
32*epsilon(p); --tolerance overrides it at that same precision, regardless
of option order. Increasing precision does not certify a result's accuracy
or add missing string/infinite-root states. Budget exhaustion still reports
unconverged estimates and returns exit status 2.
The C++ API takes an explicit options object; there is no ambient precision:
using Real = uni20::mpreal;
auto p = uni20::Precision::bits(256);
bethe::SolverOptions<Real> options(p);
auto ground = bethe::heisenberg::ground_state<Real>(32, options);
auto branch = bethe::heisenberg::one_spinon_branch<Real>(17, options);
auto bulk = bethe::heisenberg::bulk_energy_density(Real(1, p));
auto dispersion = bethe::heisenberg::spinon_energy(branch.front().spinon_momentum);
The bulk-energy helper requires a finite-precision exchange argument for
mpreal; the dispersion takes its precision from the momentum, with exact
J=1 as the default exchange. A finite-precision exchange must match that
momentum. Parallel excitation scans carry precision per calculation, so
independent scans at different precisions can share a scheduler.
Uni20's arbitrary-precision scalar family enables MPFR and MPC together. Both root solves and finite-ring form factors work without MPLAPACK; normal dispatch supplies CPU LU where needed. The OBC solver/frontend supports the same per-call precision contract for states, sector minima and real-root scans.
Validation¶
Tests use exact small-chain energies and roots, an independent evaluation of the equations, a published N=16 value, reflection symmetry, iteration-budget checks, invalid input, and precision-preserving CLI output. High-precision tests use an irrational exact energy to detect accidental double narrowing. The suite also compares independently converged results across precisions. Independent bit-basis exact diagonalization checks every sector minimum for N=2..9 and the odd-chain one-spinon energies and momenta through N=9. The momentum check adds a multiple of \((T +T ^{-1})/2\) to the Hamiltonian. This oracle uses double precision; separate irrational analytic references test native long-double and binary128 accuracy.
Next: enumerate real-root excitations or interpret the one-spinon branch. Methods and attribution are in References and provenance.