Hi,
I am curious as to whether there is a simple functionality in the (finite) ITensor DMRG code that lets us change the 2-site update to a more general multi-site update; this is necessary for certain classes of problems to help get DMRG unstuck.
There is of course a way to “cheat” and simply define a d^p dimensional custom Hilbert space containing p on-site qudits, so that using the two-site update on this custom Hilbert space is like doing a 2p-site update from the perspective of a model with only one qudit per unit cell. But this seems rather messy since we would have to redefine our custom Hilbert spaces and reconstruct the on-site operators + Hamiltonian for each value of p. Hence I am wondering if there is any pre-existing functionality that accomplishes this in ITensor.
Thanks,
Amogh
Unfortunately that’s not available in a simple form for users to use right now.
For broader context, in ITensorTDVP.jl/ITensorMPS.jl and ITensorNetworks.jl we are working on next-generation DMRG (and DMRG-like) solvers for MPS and more general tensor networks based around a more general concept of sweeping and updating a tensor network (based on the internal alternating_update
function).
This will provide a lot more flexibility than the standard ITensors.dmrg
function which is very hardcoded to a certain sweep pattern, 2-site updates, and performing DMRG by updating with an eigensolver. However, the new codes are still hard coded to either doing 1-site or 2-site updates in certain places, but we plan to generalize beyond that to n-site updates (which will be easier to do in those more general settings).
1 Like
@amoghanakru I’ve tried out what you suggested with merging neighboring sites. It’s relatively simple to do, below I included the code I used to do this (no guarantee it’s bug free). With some modification you could split the sites apart after running DMRG to get back to the original site structure. But I second that it would be nice to easily switch to standard DMRG on an arbitrary number of sites.
function merge_pairs_of_sites(psi::MPS)::MPS
@assert mod(length(psi), 2) == 0
sites = siteinds(psi)
mergedTensors = Vector{ITensor}()
for i in 1:2:length(psi)
mergedTensor = psi[i] * psi[i + 1]
c = combiner(sites[i], sites[i + 1], dir=dir(sites[i]))
push!(mergedTensors, mergedTensor * c)
end
return MPS(mergedTensors)
end
function merge_pairs_of_sites(H::MPO)::MPO
@assert mod(length(H), 2) == 0
sites = noprime(siteinds(first, H))
mergedTensors = Vector{ITensor}()
for i in 1:2:length(H)
cIn = combiner(dag(sites[i]), dag(sites[i + 1]), dir=dir(dag(sites[i])))
cOut = combiner(prime(sites[i]), prime(sites[i + 1]), dir=dir(prime(sites[i])))
iIn = combinedind(cIn)
iOut = combinedind(cOut)
mergedTensor = (H[i] * H[i + 1]) * cIn * cOut
replaceind!(mergedTensor, iOut, prime(dag(iIn)))
push!(mergedTensors, mergedTensor)
end
return MPO(mergedTensors)
end
function make_sites_match!(H::MPO, psi::MPS)::Nothing
sitesOfH = noprime(siteinds(first, H))
sitesOfPsi = siteinds(psi)
for i in eachindex(psi)
replaceind!(psi[i], sitesOfPsi[i], sitesOfH[i])
end
return nothing
end
Usage is
psi = merge_pairs_of_sites(psi)
H = merge_pairs_of_sites(H)
make_sites_match!(H, psi)
2 Likes
Thank you, this will be very helpful!