Skip to content

Performance with long range interactions is really poor #459

Description

I had some code that I decided to migrate from TenPy, but unfortunately performance is far worse for some reason. The relevant part of the Julia code is this:

disordered_distance(i, j, dx) = abs(j - i + dx[j] - dx[i])

function build_rydberg_hamiltonian(L, Δ, Ω, σ, t, V, seed)
    # Random displacements per site, uniform in [-sigma/2, sigma/2]
    rng = MersenneTwister(seed)
    dx = (rand(rng, L) .- 0.5) .* σ

    Vphys = ℂ^2
    physical_spaces = fill(Vphys, L)

    σx = TensorMap([0 1; 1 0], Vphys ← Vphys)
    σz = TensorMap([1 0; 0 -1], Vphys ← Vphys)
    Id = id(Vphys)
    Nop = (Id + σz) / 2
    Sp = TensorMap([0 1; 0 0], Vphys ← Vphys)
    Sm = TensorMap([0 0; 1 0], Vphys ← Vphys)

    lattice = fill(Vphys, L)

    on_site_terms = [(i,) => -Δ * Nop + Ω * σx for i in 1:L]
    interaction_terms = []
    for i in 1:L, j in 1:L 
        if i < j
            r = disordered_distance(i,j,dx)
            Vij = V/r^6
            tij = t/r^3
            push!(interaction_terms, (i,j) => Vij*Nop⊗Nop + tij * ( Sp ⊗ Sm + Sm⊗Sp)) 
        end
    end
    H = FiniteMPOHamiltonian(lattice, on_site_terms..., interaction_terms...) 

    return H, physical_spaces
end

# Sample values 
Δ = 1.0; Ω = 1.0; V = 1.0; t=1.0;
L = 25
chi_max = 50
psi = FiniteMPS(L, ComplexSpace(2), ComplexSpace(chi_max))

H, physical_spaces = build_rydberg_hamiltonian(L, Δ, Ω, sigma, t, V, seed)

psi, envs, dmrg_info = find_groundstate!(psi, H, DMRG(; maxiter=10))

As you can see this implements a Hamiltonian with long range interactions. For comparison, the TenPy code model definition is:

class RydbergModel(CouplingMPOModel):
    
    def init_sites(self, model_params):
        # symmetry settings
        conserve = model_params.get('conserve', None, str)
        sort_charge = model_params.get('sort_charge', True, bool)

        # define spin-1/2 local Hilbert space
        site = SpinHalfSite(conserve=conserve, sort_charge=sort_charge)
        n = np.diag([1,0])
        # site.add_op('N', 0.5 * site.Sigmaz + 0.5 * site.Id)
        site.add_op('N',n)
        return site
    
    def init_terms(self, model_params):
        counter = 0
        # read parameters
    
        Delta = model_params.get('Delta', 0.0)              
        Omega = model_params.get('Omega', 0.0) 
        sigma = model_params.get('sigma', 0.0) 
        t = model_params.get('t', 0.0)
        V = model_params.get('V', 1.0)
        seed = model_params.get('seed', 0.0)
            
        N = self.lat.N_sites

        L = self.lat.Ls[0] 
        #for dx in range(1, L):
        # randomness on possition dxi:
        # so true position of each atom is no longer i, but i + dxi
        rng = np.random.default_rng(seed)
        dx_randomness = rng.uniform(-0.5, 0.5, size=L) * sigma

        # This is for non-periodic boundary conditions
        for i in range(L):
            for j in range(i+1,L): # This ensures i < j    
                dx = abs((j+dx_randomness[j]) - (i + dx_randomness[i]))
                Vij = V / dx**6
                tij = t / ( dx**3) # run again with this value
                self.add_coupling_term(tij, i,j, 'Sp', 'Sm', plus_hc=True)
                self.add_coupling_term(Vij, i, j,'N','N')


        self.add_onsite(-Delta, 0, 'N')

        self.add_onsite(Omega, 0, 'Sigmax') 

and then for the actual ground state computation I run something like

model = MyTFIChain(model_params)
                psi = MPS.from_lat_product_state(model.lat, [['up']])

                dmrg_params = {
                'mixer': True,  # setting this to True helps to escape local minima
                'max_E_err': 1.e-6,
                'trunc_params': {
                    'chi_max': chi_max,
                    'svd_min': 1.e-10,
                    },
                'verbose': True,
                'combine': True
                }

                # get the data:
                eng = dmrg.TwoSiteDMRGEngine(psi, model, dmrg_params)
                E, psi = eng.run()

The TenPy version runs a lot faster. In my actual code, I perform sweeps over regions of Δ and Ω. The TenPy version took about 4.5 minutes to run a sweep over a 5x5 region, while MPSKit takes almost as much time for even the first DMRG calculation (I don't count the time for compilation).

Am I using the wrong algorithm for something, is it a problem with my code, or is TenPy just faster currently?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions