Adding ITensors objects with different index sites

HI all,
I have a question about how to add two Hamiltonians which runs over different site elements.
My system is a spin chain that run from 1 to n. Their is an inner interaction between the site 1:n-1, and a coupling interaction between all the site to n site. It looks like this:
My two Hamiltonians are:

H_{syk}= \sum_{\alpha, \beta=1}^{3}\sum_{i=1,j=i+1}^{n-2,n-1} J_{I,j}^{\alpha,\beta}S_{I}^{\alpha}S_{j}^{\beta}
H_{int}= \sum_{i=1}^{n-1} g_{I}S_{I}^{z}S_{n}^{z}

My goal is to write those two Hamiltonians as one, but unfortunately I have an index error because the coupling to site in the n place.

s= sittings("Qubit",n)
J= randn(n(n+1)/2)
g=randn(n-1)
J[1]*op("Sz",s[1])*op("Sx",s[2])+...+J[4]*op("Sx",s[1])*op("Sy",s[3])+g[1]*op("Sz",s[1])*op("Sz",s[end])

The problem is that this method gives me an error

no valid permutation of dimension

Does anyone knows what will be the best to add those two Hamiltonians together ?

This looks like it could be a good candidate for the OpSum system, where you define a Hamiltonian as a sum of many terms then convert the OpSum to an MPO.
You can see an example of the usage of OpSum here:
https://itensor.github.io/ITensors.jl/stable/tutorials/DMRG.html

The code you wrote looks like you are trying to make the Hamiltonian instead as a large ITensor. Is that your goal? (It could be, for example if you are planning to do a kind of “exact diagonalization” or full Hilbert space calculation as a test.) Or are you wanting your Hamiltonian as an MPO ultimately, like for doing a DMRG or time dependent MPS calculation?

Hey Miles,
Thank you for the help. My goal is to develop an MPS in time with this object, eventually I would like to define an object of type ITensor and push them all into this object kind of like in this example:
https://itensor.github.io/ITensors.jl/stable/tutorials/MPSTimeEvolution.html
I am basically trying to do the same process, but it doesn’t work (because of indices mismatch dimensions).
So my final goal is to do MPS time dependent calculations.

The extra context is very helpful here, thanks. So while it is correct that to build Trotter gates you would need to form ITensors, you will find that doing time evolution that way for a Hamiltonian this complicated will not end up being very feasible. Most importantly, even if you can build a correct code it will not scale well with system size and time.

So the much better approach here would be to use the TDVP algorithm. We have a good TDVP code in this new package:
https://github.com/ITensor/ITensorTDVP.jl
though unfortunately it is still somewhat under development. This does not mean that the code does not work. It does and the interface is very close to the final one. The main drawback is that some of the remaining techniques needed to get the algorithm to be reliable for more challenging Hamiltonians are not all put in, like the “global subspace expansion” method.

But you can still try out this method and it may well be that you do not need any such tricks other than the 2-site (default) version of TDVP.

I should have mentioned a key aspect of TDVP is that it takes as its input the MPO form of the Hamiltonian, and that will be easy to make for your Hamiltonian using the OpSum system, as in our DMRG code examples.

Thanks, I will try that!
Another question is why using the following method isn’t correct.
I constructed my two Hamiltonians seperated as an ITensor object like the example in the tutorial, and after I had two individual H’s, doing the following procces:

g= H_syk 
f= H_interaction
lg= length(g)/2
lf= length(f)/2
gf= [g[1:lg]...,f[1:lf]....,g[1+lg:end]...,f[1+lf:end]]

This method should give me the same result no ?
I tried this method for this and I got good results, but the problem is the when I replaced the Hamiltonian H_syk, in simpler H I got something fishy and then I thought I might need to change something.

H_{magnetic field}=\sum_{I=1}^{n-1}h_i S_i^z

for that H I just combined the two H’s and got much nicer results.
So my question is, does the method I suggested ok for my calculations for complicated interactions like H_syk ? or I should turn to another method ?

Does someone knows if what I wrote above is correct ?

Are you asking about how to set up a Trotter time evolution code to time evolve with two different Hamiltonians added together?

What kind of objects are H_syk and H_interaction? Are they arrays of some kind? What are their elements supposed to be?

The two Hamiltonians will be exactly as the example I shared MPS Time Evolution · ITensors.jl
Am I doing here a Trotterization correct ? because this method gives me good result for a complicated H, but for a simpler one- not.
and my question is: if the method I applied should work or not ?
another question I have from what you have written before: what do you mean “that my system won’t scale well” ?

I’m still not 100% sure of all of the details of what you are doing, but I think I can guess. It would be helpful if you would mention details like H_syk is an array of Trotter time-evolution gates made from each term in the Hamiltonian. (Because in that tutorial, the array called gates is not a “Hamiltonian” but is an array of time evolution operators made by exponentiating each term in the Hamiltonian. So when you say H_syk is a Hamiltonian I was wondering what kind of array is it?)

Anyway I am guessing that H_syk and H_interaction are arrays of Trotter gates.

Then the answer is, no that is not the correct way to apply such Trotter gates when the Hamiltonian is a sum of two Hamiltonians. Instead of applying all of the g-gates then all of the f-gates, the correct thing to do will end up being something like applying them in a mixed way, like one g gate followed by one f gate, etc.

I actually don’t remember the best pattern to use for Trotterizing Hamiltonians which aren’t nearest neighbor (which I think is your case), so I don’t want to mislead you here. The best thing to do would be to look up some references on “Trotter-Suzuki” for non-nearest-neighbor Hamiltonians.

The simplest thing to try here, in terms of generalizing Trotter Suzuki patterns for nearest-neighbor to further neighbor is the following:

  1. write the (total) Hamiltonian, including both of your sets of terms as
H = \sum_{i} \sum_{j} h_{ij}
  1. next, order the terms based on their “i” index.

  2. use the same pattern as in the tutorial, but making gates involving h_{1,1}, h_{1,2}, h_{1,3} and applying all those first. Then apply gates made from h_{2,2}, h_{2,3}, h_{2,4} etc. and apply those next. Hopefully you can see the pattern here is applying them in a order based on their “i” index, followed by their “j” index. (Of course if some of these Hamiltonian terms are zero, you just skip over that term.)

  3. lastly, you apply all of the gates in the reversed order. Doing the gates twice with a time step of \tau/2, once in the forward order and again in the reversed order is what makes the error scale as a higher power of \tau, as I believe you know.

This is the function of H_syk

function SYK(s,J,N,tau)
    gates = ITensor[]
    temp=1
    A= ["Sx", "Sy", "Sz"]
    for j in 1:N-2 
        for i in j+1:N-1
            tempy = []
            s1= s[i]
            s2= s[j]
            for α in 1:3
                for β in 1:3
                    hj= J[temp]*op(A[α],s2)*op(A[β],s1) #J is random vector of gaussian distribution 
                    push!(tempy, hj)
                    temp= temp+1
                end
            end
            Gj = exp(-1.0im * tau/2 * sum(tempy))
            push!(gates,Gj)
        end
    end
    append!((gates),reverse(gates))
    return gates
end

This is the H_int

function interaction(site,N,g,tau)
    gates = ITensor[]
    for j in 1:N-1
        gj= g[j]*op("Sz",site[j])*op("Sy",site[end])
        Gj = exp(1.0im * tau * gj)
        push!(gates,Gj)
    end
    append!((gates),reverse(gates))
    return gates
end

So this is what I tried to do, I actually tried to arranged all my site gates in groups, and then applying them.

I understand you, the problem is that I can’t write them in the same H because they have different site index.

Can you pass the same set of site indices to both functions so that they end up having the same site indices?