TDVP for time-dependent Hamiltonian operators

Dear ITensor developers,

I would like to know how to use TDVP with a Hamiltonian operator that is time-dependent. I found the example

There, the time dependence is in the form of a time-dependent factor multiplying a time-independent Hamiltonian MPO, H(t) = f_1(t) H_1(0) + f_2(t) H_2(0), and the time-dependent Hamiltonian is given as an argument to tdvp by using the TimeDependentSum function:

ψₜ_ode = tdvp(-im * TimeDependentSum(f⃗, H⃗₀), time_stop, ψ₀;
    updater=ode_updater,
    updater_kwargs=(; reltol=tol, abstol=tol),
    time_step,
    maxdim,
    cutoff,
    nsite,
    outputlevel,)

What would be the syntax for tdvp when the Hamiltonian is not separable into a factor f(t) and a time-independent MPO? I am specifically interested in reproducing the results of the paper [https://journals.aps.org/prxquantum/pdf/10.1103/PRXQuantum.5.020361], where the adiabatic gauge potential term in the Hamiltonian is time-dependent. I am using the julia ITensor version 0.6.16.

It’s a good question. A good way to do totally arbitrary, time-dependent Hamiltonians is to make a custom updater function. If you look further at the example you linked to, you’ll see that the calls to the tdvp function also pass a keyword argument:

tdvp(...,
updater=ode_updater
...

and the ode_updater function is defined in the 03_updaters.jl file also in the example folder.

You can think of the TimeDependentSum type passed into tdvp and then all the way down to the updater as being a stand-in for any object that you want to pass. If your updater is custom, that type (which gets passed as the operator argument of the updater) really can be any object you like. The updater also gets passed keyword arguments from which you can obtain the current time and the time step. Then you can use this information to process the operator any way that suits your calculation in order to finally make an input to the “time stepper” that you want to use.

The example code uses the ODEProblem type and solve function from the OrdinaryDiffEQ package, but you can also use the more standard exponentiate function from the KrylovKit package which we use as our default TDVP time stepper. All that KrylovKit requires is that you pass an operator object which can be called (i.e. operators the “parenthesis” operation of calling the object like a function) and which accepts an ITensor as input. For more information about exponentiate please see the KrylovKit docs and also you can take a look at our default exponentiate_updater in the file src/tdvp.jl in the ITensorTDVP code repo.

A very useful thing to do in all this is to put ITensorTDVP into “dev” mode and then add lines printing out or @show’ing various things like types of objects passed into the updater and the keyword arguments received by the updater etc. This is what I often do to remind myself of what objects and information are flowing into each function.

Please respond below if you have further questions.