torch_vn_algebra.chains¶
Source: torch_vn_algebra/chains.py. Signatures and docstrings as in the source.
Module documentation¶
Spin-1/2 chains with a conserved number of up spins (U(1) symmetry, total S^z).
The Hilbert space (C^2)^{(x) L} splits into sectors N = 0, ..., L (number of up spins) of
dimension binom(L, N); every operator that conserves S^z_total is an element of
M = (+)_{N=0}^{L} M_{binom(L, N)}(C),
the algebra obtained by fusing L single-site algebras M_1 (+) M_1 with charges 0, 1
(composite.fused_tensor_product); the basis order of SpinChain coincides with that construction.
Basis states are bit strings: bit i of a label is the spin on site i (1 = up).
chain = SpinChain(L=10, boundary='periodic')
H = chain.xxz(J=1.0, Delta=1.0, h=fields) # fields: (L,) or (batch, L) -> batch of H
H5 = chain.xxz(..., sector=5) # one sector only: no padding
rho_A = chain.reduced_state(rho, n_left=4) # state of sites 0..3 (a SpinChain(4) state)
Hamiltonian: H = sum_<ij> [ J/2 (S+_i S-_j + S-_i S+_j) + J Delta S^z_i S^z_j ] + sum_i h_i S^z_i.
SpinChain¶
class SpinChain(L: int, boundary: str='open', complex_valued: bool=True, precision: str='double', device=None)
SpinChain.algebra¶
@property
def algebra(self) -> TypeIAlgebra
The full algebra (+)_N M_{binom(L, N)} (created on first use; padded to the largest sector).
SpinChain.bonds¶
@property
def bonds(self) -> List[tuple]
Nearest-neighbour bonds (i, i+1); a periodic chain adds (L-1, 0) for L > 2. For L = 2 the two sites
share a single bond, so the periodic and the open chain coincide (the bond is not counted twice).
SpinChain.sector_dim¶
def sector_dim(self, N: int) -> int
SpinChain.sector_algebra¶
def sector_algebra(self, N: int) -> TypeIAlgebra
The single-sector algebra M_{binom(L, N)} (no padding), cached.
SpinChain.bits¶
def bits(self, N: int) -> torch.Tensor
(binom(L, N), L) tensor of 0/1 spins of the basis states of sector N.
SpinChain.xxz¶
def xxz(self, J: float=1.0, Delta: float=1.0, h=None, sector: Optional[int]=None) -> Operator
XXZ Hamiltonian H = sum_bonds J [ (S+_i S-_j + h.c.)/2 + Delta Sz_i Sz_j ] + sum_i h_i Sz_i with fields h
(scalar, (L,) or (batch, L): one Hamiltonian per row); bonds as in `bonds` (periodic L = 2: one bond).
sector=None: operator in the full algebra (all sectors, padded); sector=N: operator in
sector_algebra(N) only.
SpinChain.xxz_sparse¶
def xxz_sparse(self, J: float=1.0, Delta: float=1.0, h=None, sector: int=0)
The XXZ Hamiltonian of one sector in sparse form (krylov.SparseSectorHamiltonian): a batch of
diagonals (one per row of h) and one shared sparse hopping matrix; memory O(batch * k + k * L)
instead of O(batch * k^2). For krylov.ground_state / krylov.evolve.
SpinChain.momentum_dims¶
def momentum_dims(self, N: int) -> List[int]
Dimensions of the momentum sectors k = 2 pi m / L, m = 0..L-1, inside sector N.
SpinChain.momentum_algebra¶
def momentum_algebra(self, N: int) -> TypeIAlgebra
(+)_m M_{d_m}: the operators commuting with N and with translations, sectors labelled by m.
SpinChain.xxz_momentum¶
def xxz_momentum(self, J: float=1.0, Delta: float=1.0, h: float=0.0, sector: int=0) -> Operator
Translation-invariant XXZ Hamiltonian of sector N, block diagonal in the momentum k = 2 pi m / L
(requires a periodic, complex chain; h must be uniform). Basis of block m:
|a, k> = (1/sqrt(N_a)) sum_j e^{-i k j} T^j |a>, N_a = L^2 / R_a, for representatives a of period
R_a with m R_a = 0 mod L. The union of the spectra of all blocks is the spectrum of sector N.
SpinChain.heisenberg¶
def heisenberg(self, J: float=1.0, h=None, sector: Optional[int]=None) -> Operator
SpinChain.random_field_heisenberg¶
def random_field_heisenberg(self, W: float, batch_size: int, J: float=1.0, sector: Optional[int]=None, generator: Optional[torch.Generator]=None) -> Operator
Heisenberg chain with i.i.d. fields h_i ~ U[-W, W]; one disorder realisation per batch element.
SpinChain.sz¶
def sz(self, i: int, sector: Optional[int]=None) -> Operator
S^z on site i.
SpinChain.number¶
def number(self, sector: Optional[int]=None) -> Operator
N = number of up spins (central: N * 1 in sector N).
SpinChain.basis_state¶
def basis_state(self, bitstring: Union[str, Sequence[int]]) -> DensityMatrix
|s><s| for a configuration given as '0110...' (site 0 first) or a 0/1 sequence.
SpinChain.vector_in_sector¶
def vector_in_sector(self, bitstring) -> torch.Tensor
Basis vector of a configuration as a column of its sector (shape (binom(L, N),)).
SpinChain.reduced_state¶
def reduced_state(self, rho: Operator, n_left: int, sector: Optional[int]=None) -> DensityMatrix
Partial trace over sites n_left, ..., L-1. rho lives in the full algebra (sector=None) or in
sector_algebra(sector). Returns a state of SpinChain(n_left, ...).algebra; for U(1)
symmetric states the result is block diagonal in the particle number of the left part.
SpinChain.entanglement_entropy¶
def entanglement_entropy(self, rho: Operator, n_left: int, sector: Optional[int]=None) -> torch.Tensor
von Neumann entropy of the reduced state of sites 0..n_left-1.
SpinChain.site_amplitude_damping¶
def site_amplitude_damping(self, i: int, gamma: float) -> InterSectorChannel
Spin flip down on site i with probability gamma (a map between sectors N -> N-1):
K_0 = |down><down|_i + sqrt(1 - gamma) |up><up|_i, K_1 = sqrt(gamma) S-_i.
SpinChain.lowering¶
def lowering(self, i: int) -> InterSectorChannel
S-_i as a single jump operator between sectors N -> N-1 (for Lindblad loss terms).
SpinChain.level_spacing_ratio¶
@staticmethod
def level_spacing_ratio(energies: torch.Tensor) -> torch.Tensor
Mean ratio of consecutive level spacings r = <min(s_n, s_{n+1}) / max(s_n, s_{n+1})> per row of
sorted energies (Oganesyan-Huse). Exact values proved in the lecture notes (Proposition 5.14): 2 ln 2 - 1 = 0.386
for independent exponential spacings, 4 - 2 sqrt 3 = 0.536 (GOE) and 2 sqrt 3 / pi - 1/2 = 0.603 (GUE) for
3 x 3 matrices. For large GOE matrices the value is about 0.53 (Atas et al. 2013; a numerical result, not
an exact one), so for large spectra compare with a sampled reference of the same size.