Piecewise-constant TDVP
The simplest algorithm: freeze H(t) once per interval and run an ordinary TDVP sweep across it.
using ITensorMPS, ITensorTDMPO
sites = siteinds("S=1/2", 20)
Hzz = MPO(OpSum() + ..., sites) # coupling
Hx = MPO(OpSum() + ..., sites) # transverse field
ramp = Ramp(SmoothstepRamp(), 0.0, 10.0, 0.0, 2.0)
ψ = time_evolve(
[(1.0, Hzz), (ramp, Hx)], ψ0, 0.0, 10.0;
alg = "piecewise_constant", nsteps = 200, cutoff = 1e-10, maxdim = 128,
)The driver piecewise_constant_tdvp also accepts an H0/Ht pair directly, which is the more general form when the time dependence is not channel-separable:
piecewise_constant_tdvp(Hzz, t -> ramp(t) * Hx, ψ0, 0.0, 10.0; nsteps = 200)Note the sign convention: generator_prefactor defaults to -im, so each step applies exp(-i·dt·H). This differs from bare ITensorMPS.tdvp, where you pass -im*t yourself. Pass generator_prefactor = -1 for imaginary-time evolution.
Step calibration
A schedule(t, ψ) -> TDVPStepSpec callback chooses, per step, between 1-site and 2-site TDVP and whether to do a global Krylov subspace expansion first (needed to grow the bond dimension under 1-site TDVP):
schedule = (t, ψ) -> maxlinkdim(ψ) < 128 ?
TDVPStepSpec(; nsite = 2) :
TDVPStepSpec(; nsite = 1, expand_krylov = true,
expand_kwargs = (; krylovdim = 2, cutoff = 1e-8))Never select nsite = 1 without expand_krylov = true when the state cannot already represent the target entanglement. One-site TDVP cannot grow the bond dimension, so starting from a product state it stays at bond dimension 1 and the result is simply wrong — measured error 0.82 (trace distance), independent of step count, on a case where two-site TDVP reaches 1e-7. The default schedule uses nsite = 2.
Other keywords: eval_at (:midpoint or :start), combine_kwargs, step_observer!(; step, t_start, t_stop, state), outputlevel. An explicit non-uniform time grid can be passed in place of t_start, t_stop.
Reference
ITensorTDMPO.piecewise_constant_tdvp — Function
piecewise_constant_tdvp(H0, Ht, ψ0, times; kwargs...)
piecewise_constant_tdvp(H0, Ht, ψ0, t_start, t_stop; dt=nothing, nsteps=nothing, kwargs...)Time-evolve ψ0 under the time-dependent Hamiltonian H(t) = H0 + Ht(t) (or just Ht(t) if H0 === nothing) using TDVP, approximating H(t) as piecewise constant on each interval of times (or of the regular grid from t_start to t_stop built from dt/nsteps, following the same conventions as ITensorMPS.tdvp).
This is the simplest general driver for adiabatic ramps and other time-dependent Hamiltonians: H(t) is frozen at one evaluation point per interval and the state is evolved across that interval with an ordinary (time-independent) TDVP sweep.
Arguments
H0::Union{MPO,Nothing}: the time-independent part of the Hamiltonian, ornothingif the full Hamiltonian is time dependent.Ht: a functionHt(t) -> MPOgiving the time-dependent part of the Hamiltonian (or the full Hamiltonian, ifH0 === nothing).ψ0::MPS: the initial state.times: the interval endpoints of the piecewise-constant time grid.
Keywords
schedule = default_tdvp_schedule: a functionschedule(t, ψ) -> TDVPStepSpeccalibrating, for the interval evaluated at timetwith current stateψ, whether to use 1-site or 2-site TDVP and whether to perform a global Krylov subspace expansion beforehand (needed to grow the bond dimension under 1-site TDVP). SeeTDVPStepSpec.eval_at = :midpoint: whether to freezeH(t)at the:midpointor the:startof each interval.generator_prefactor = -im: each step evolves the state byexp(generator_prefactor * dt * H(t)), matching the convention ofITensorMPS.tdvp. The default-imgives real-time Schrödinger evolution; pass-1for imaginary-time evolution.tdvp_kwargs = (;): keyword arguments forwarded toITensorMPS.tdvpon every step, e.g.cutoff,maxdim,updater_backend,order.combine_kwargs = (; alg = "directsum"): keyword arguments used to combineH0andHt(t), forwarded to+(H0, Ht(t); combine_kwargs...).(step_observer!) = nothing: an optional callbackstep_observer!(; step, t_start, t_stop, state)invoked after each interval.outputlevel = 0: set to>= 1to print progress after each step.
Returns the final evolved MPS.
piecewise_constant_tdvp(channels::DrivingChannels, ψ0::MPS, times; kwargs...)
piecewise_constant_tdvp(channels, ψ0, t_start, t_stop; dt, nsteps, kwargs...)Evolve ψ0 with H(t) frozen on each interval, taking the Hamiltonian from a DrivingChannels decomposition rather than an H0/Ht pair. This is the form shared with dyson_evolve and magnus_evolve, so the same Hamiltonian description drives every method; see time_evolve for the common entry point.
operator_cutoff/operator_maxdim control the truncation used when assembling H(t) = Σₐ fₐ(t) H^{(a)} at each evaluation point; all other keywords are as for the H0/Ht method above.
piecewise_constant_tdvp([(f1, H1), (f2, H2), ...], ψ0, args...; kwargs...)Convenience form taking the channels as a plain list of (driving, MPO) tuples or pairs (see DrivingChannels), for calling this driver directly without building the DrivingChannels object yourself.
ITensorTDMPO.TDVPStepSpec — Type
TDVPStepSpec(; nsite, expand_krylov = false, expand_kwargs = (;))Describes how a single piecewise-constant TDVP step should be carried out: whether to use 1-site or 2-site updates (nsite), and whether to perform a global Krylov subspace expansion (see ITensorMPS.expand with alg = "global_krylov") before the step. Subspace expansion is only needed when nsite == 1, since 1-site TDVP cannot grow the MPS bond dimension on its own.
ITensorTDMPO.default_tdvp_schedule — Function
default_tdvp_schedule(t, ψ)Default TDVP calibration function: always use 2-site TDVP and never perform a global Krylov expansion, since 2-site TDVP grows the bond dimension on its own. t is the time at which the step is evaluated and ψ is the current MPS state.
ITensorTDMPO.DrivenHamiltonian — Type
DrivenHamiltonian(H0, Ht; combine_kwargs = (; alg = "directsum"))Bundles a time-independent MPO H0 with a function Ht(t) -> MPO giving the time-dependent part of the Hamiltonian. Calling H(t) returns the total Hamiltonian at time t as an MPO, H0 + Ht(t).
H0 can be nothing if the full Hamiltonian is time dependent, in which case H(t) === Ht(t).
combine_kwargs are passed to +(H0, Ht(t); combine_kwargs...) and default to an exact (non-truncating) direct sum, appropriate for Hamiltonian MPOs which typically already have a small bond dimension.