I have a fixed lattice (300-site spin-1/2 chain), but different Hamiltonians. I want to be able to do the following.
- Store states computed using DMRG on different machines.
- Load them later and, e.g., compute inner products between them.
- Avoid spurious issues due to unintended index collisions (see example below).
- Ideally, have reproducible computations (which return the same result if reran).
What is the recommended way to handle the indices to achieve this?
I currently use a method that works more than 90% of the time, but sometimes fails spectacularly, as illustrated by the following example (requires a file with a saved state to reproduce):
# Reproducible 100% of the time due to seeding. Happens rarely otherwise.
import HDF5
using ITensors
import Random
HDF5.h5open("example.hdf5") do f
global loaded_state = read(f, "elben_xxz_dmrg_res/states/2", MPS)
end;
# Ensure same site indices:
Random.seed!(index_id_rng(), 300)
sites = siteinds("S=1/2", 300)
sz_id = MPO(ITensor[op("Id", s) for s in sites])
z_prod = MPO(ITensor[2 * op("Sz", s) for s in sites])
zprod_proj1 = (sz_id - z_prod) / 2;
# Some unrelated computation (not used in the end result,
# but the issue does not reproduce if it is removed):
ops = OpSum()
for i in 1:(length(sites)-1)
J = isodd(i) ? 1.0 : 0.0
ops .+= J, "S+", i, "S-", i+1
ops .+= J, "S-", i, "S+", i+1
end
ham = MPO(ops, sites)
_ = sz_id + z_prod;
ops = OpSum()
ops .+= 1.0, "Id", 1
obs1 = MPO(ops, sites);
_ = apply(obs1, obs1)
psi1 = productMPS(sites, [isodd(i) ? "Dn" : "Up" for i in 1:length(sites)])
sweeps = Sweeps(10)
noise!(sweeps, 1e-6, 1e-7, 1e-8, 1e-9, 0)
psi1 = dmrg(ham, psi1, sweeps)[2]
_ = inner(psi1', ham, psi1)
_ = inner(psi1, psi1)
_ = apply(zprod_proj1, psi1)
_ = dmrg(ham, psi1; nsweeps=1, cutoff=1e-12)[2]
_ = inner(psi1', obs1, psi1)
_ = apply(zprod_proj1, psi1)
# The issue:
psi2 = loaded_state
psi2_a = apply(zprod_proj1, psi2) # norm-1 MPS, correct
psi2_b = apply(zprod_proj1, psi2) # 0 MPS, incorrect, even though produced by the same formula
psi2_a_norm = norm(psi2_a)
psi2_b_norm = norm(psi2_b)
@assert (psi2_a_norm == psi2_b_norm) "$(psi2_a_norm) != $(psi2_b_norm)"
# AssertionError: 1.0000000000000469 != 0.0