DMRG with Multi-Site Updates?

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!