Magnus expansion
U(t,t₀) = exp(Ω(t,t₀)) with
Ω₁ = Σₐ [fₐ] H⁽ᵃ⁾
Ω₂ = ½ Σₐᵦ [fₐfᵦ] [H⁽ᵃ⁾, H⁽ᵇ⁾]
Ω₃ = ⅙ Σₐᵦ𝚌 [fₐfᵦf𝚌] ( [[H⁽ᵃ⁾,H⁽ᵇ⁾],H⁽ᶜ⁾] + [H⁽ᵃ⁾,[H⁽ᵇ⁾,H⁽ᶜ⁾]] )ψ = time_evolve([(1.0, Hzz), (ramp, Hx)], ψ0, 0.0, 10.0;
alg = "magnus", order = 2, nsteps = 100)
# ...or the driver directly
Ω = magnus_generator(channels, t0, t1; order = 2)
ψ = magnus_evolve(
channels, ψ0, 0.0, 10.0;
nsteps = 100, order = 2,
tdvp_kwargs = (; cutoff = 1e-10, maxdim = 128),
)Because the brackets carry the factors of -i, Ω is anti-Hermitian and exp(Ω) is unitary — so unlike the Dyson driver, magnus_evolve preserves the norm exactly. The exponential is applied as tdvp(Ω, 1.0, ψ): the generator already carries the whole step, so the TDVP "time" is 1, matching the paper's exponentiation of Ω at τ = 1.
The commutator structure is what keeps each term extensive — the non-overlapping ("disjoint") contributions cancel between AB and BA.
Orders
Orders 1–3 are supported; order 2 is the right choice (order 3 converges no faster and costs more). See Why Dyson improves order-by-order but Magnus doesn't for why. A fourth-order Ω₄ is not offered: reaching genuine 6th order requires Ω₃ and Ω₄ together in a nested-commutator basis that is nontrivial to get right, so CFET is the route to higher order here — it is both cheaper and more extensible, since commutator-free schemes are specified by coefficient tables rather than commutator algebra.
Reference
ITensorTDMPO.magnus_generator — Function
magnus_generator(channels::DrivingChannels, t0, t; order = 2, kwargs...)The Magnus generator Ω(t, t0) up to order, as an MPO, such that U(t, t0) ≈ exp(Ω(t, t0)).
Following Vanthilt et al., writing H(t) = Σₐ fₐ(t) H^{(a)}, each Magnus term is a linear combination of (nested) commutators of the time-independent channel operators, with scalar prefactors given by the time-ordered integrals of the driving functions:
\[\Omega_1 = \sum_a [f_a] H^{(a)}, \qquad \Omega_2 = \tfrac{1}{2} \sum_{ab} [f_a f_b] \, [H^{(a)}, H^{(b)}]\]
The commutator structure is what keeps each term extensive: the non-overlapping ("disjoint") contributions cancel between AB and BA. The […] brackets carry the factors of -i, so Ω is anti-Hermitian for Hermitian channel operators and real driving functions, and exp(Ω) is unitary.
Orders
Supported orders are 1 through 3; 2 is the right default:
order | measured convergence order | note |
|---|---|---|
| 1 | 2 | exponential midpoint-like |
| 2 | ~3.9 | the recommended setting |
| 3 | ~3.8 | no better than 2, and costs more per step |
Orders 2 and 3 coincide because the truncated Magnus expansion is time-symmetric, and time-symmetric methods have even order — so the odd term Ω₃ buys nothing. Reaching sixth order would need Ω₄; a partial implementation of it measured ~4th order rather than the expected 6th and was removed rather than shipped unverified. For higher order, prefer cfet_evolve, which reaches fourth order more cheaply and extends to higher-order commutator-free schemes.
prefactor (default -im) sets the factor carried per order; pass -1 for imaginary time, which makes Ω Hermitian and exp(Ω) a non-unitary contraction.
Commutators are formed by direct MPO multiplication rather than through the paper's finite-state-machine encoding. See Scope and limitations.
ITensorTDMPO.magnus_terms — Function
magnus_terms(channels::DrivingChannels, t0, t; order, cutoff, maxdim, npoints, prefactor)The individual terms of the Magnus generator Ω(t, t0), as a vector of MPOs. Summing them gives magnus_generator.
ITensorTDMPO.magnus_evolve — Function
magnus_evolve(channels, ψ0, times; order = 2, kwargs...)
magnus_evolve(channels, ψ0, t_start, t_stop; dt = nothing, nsteps = nothing, kwargs...)Time-evolve ψ0 under the time-dependent Hamiltonian carried by channels by building the Magnus generator Ω on each interval of times and applying exp(Ω) to the state with TDVP.
For real-time evolution Ω is anti-Hermitian, so exp(Ω) is unitary and the norm is preserved. As with the Dyson driver, the time dependence within each step is captured to the given order rather than frozen.
The exponential is applied as tdvp(Ω, 1.0, ψ): the generator already carries the full step, so the TDVP "time" is 1, exactly as in Sec. IV of Vanthilt et al. where Ω is exponentiated with a Taylor MPO at τ = 1.
Keywords
order = 2: order of the Magnus expansion on each step (1–3); seemagnus_generatorfor what each order buys.generator_kwargs = (;): forwarded tomagnus_generator, includingprefactorfor imaginary time.tdvp_kwargs = (; cutoff = 1e-10): forwarded totdvp. Increasenstepshere if the exponentiation ofΩitself needs refining.normalize = false: renormalize after each step. Leavefalsefor real time, where the evolution is already unitary; settruefor imaginary time, whereexp(Ω)contracts the state.(step_observer!) = nothing: callbackstep_observer!(; step, t_start, t_stop, state)after each step.outputlevel = 0: set>= 1to print progress.
Returns the final evolved MPS.
magnus_evolve([(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.