Time evolution
Reference for the time-evolution drivers and algorithms. For a task-oriented walkthrough see the how-to guides. The full, canonical docstrings for the whole package live in the Library index.
Drivers
MPSKit.time_evolve Function
time_evolve(ψ₀, H, t_span, alg, [envs]; kwargs...) -> (ψ, envs)
time_evolve!(ψ₀, H, t_span, alg, [envs]; kwargs...) -> (ψ₀, envs)Time-evolve the initial state ψ₀ with Hamiltonian H over a given time span by stepping through each of the time points obtained by iterating t_span.
Arguments
ψ₀::AbstractMPS: initial stateH::AbstractMPO: operator that generates the time evolution (can be time-dependent).t_span::AbstractVector{<:Number}: time points over which the time evolution is steppedalg: algorithm to use for the time evolution, e.g.TDVPorTDVP2.envs: MPS environment manager
Keyword Arguments
verbosity::Int = 0: verbosity level for loggingimaginary_evolution::Bool = false: if true, the time evolution is done with an imaginary time step instead, (i.e. instead of ). This can be useful to compute the ground state of a Hamiltonian, or to compute finite-temperature properties of a system.normalize::Bool = false: if true, the state is renormalized after every step, which can be useful to retain numerical stability when the norm loss is not information that is needed.
Returns
ψ: the time-stepped stateenvs: the updated environment manager
MPSKit.timestep Function
timestep(ψ₀, H, t, dt, alg, [envs]; kwargs...) -> (ψ, envs)
timestep!(ψ₀, H, t, dt, alg, [envs]; kwargs...) -> (ψ₀, envs)Time-step the state ψ₀ with Hamiltonian H over a given time step dt at time t, solving the Schroedinger equation:
Arguments
ψ₀::AbstractMPS: initial stateH::AbstractMPO: operator that generates the time evolution (can be time-dependent).t::Number: starting time of time-stepdt::Number: time-step magnitudealg: algorithm to use for the time evolution, e.g.TDVPorTDVP2.envs: MPS environment manager
Keyword Arguments
imaginary_evolution::Bool = false: if true, the time evolution is done with an imaginary time step instead, (i.e. instead of ). This can be useful to compute the ground state of a Hamiltonian, or to compute finite-temperature properties of a system.normalize::Bool = false: if true, the state is renormalized after every step, which can be useful to retain numerical stability when the norm loss is not information that is needed.
Returns
ψ: the time-stepped stateenvs: the updated environment manager
Examples
Real-time evolution of the |+···+⟩ product state under a transverse field H = ∑ Zₖ. Each spin precesses independently, so ⟨Xₖ(t)⟩ = cos(2t); after a step dt = 0.1 this is cos(0.2) ≈ 0.980067. The initial state must be complex, since real-time evolution multiplies by -i:
julia> X = TensorMap(ComplexF64[0 1; 1 0], ℂ^2, ℂ^2);
julia> Z = TensorMap(ComplexF64[1 0; 0 -1], ℂ^2, ℂ^2);
julia> ψ₀ = FiniteMPS(ones(ComplexF64, (ℂ^2)^4));
julia> H = FiniteMPOHamiltonian(fill(ℂ^2, 4), ((i,) => Z for i in 1:4));
julia> ψ, envs = timestep(ψ₀, H, 0.0, 0.1, TDVP());
julia> round(real(expectation_value(ψ, 2 => X)); digits = 6)
0.980067MPSKit.timestep! Function
timestep(ψ₀, H, t, dt, alg, [envs]; kwargs...) -> (ψ, envs)
timestep!(ψ₀, H, t, dt, alg, [envs]; kwargs...) -> (ψ₀, envs)Time-step the state ψ₀ with Hamiltonian H over a given time step dt at time t, solving the Schroedinger equation:
Arguments
ψ₀::AbstractMPS: initial stateH::AbstractMPO: operator that generates the time evolution (can be time-dependent).t::Number: starting time of time-stepdt::Number: time-step magnitudealg: algorithm to use for the time evolution, e.g.TDVPorTDVP2.envs: MPS environment manager
Keyword Arguments
imaginary_evolution::Bool = false: if true, the time evolution is done with an imaginary time step instead, (i.e. instead of ). This can be useful to compute the ground state of a Hamiltonian, or to compute finite-temperature properties of a system.normalize::Bool = false: if true, the state is renormalized after every step, which can be useful to retain numerical stability when the norm loss is not information that is needed.
Returns
ψ: the time-stepped stateenvs: the updated environment manager
Examples
Real-time evolution of the |+···+⟩ product state under a transverse field H = ∑ Zₖ. Each spin precesses independently, so ⟨Xₖ(t)⟩ = cos(2t); after a step dt = 0.1 this is cos(0.2) ≈ 0.980067. The initial state must be complex, since real-time evolution multiplies by -i:
julia> X = TensorMap(ComplexF64[0 1; 1 0], ℂ^2, ℂ^2);
julia> Z = TensorMap(ComplexF64[1 0; 0 -1], ℂ^2, ℂ^2);
julia> ψ₀ = FiniteMPS(ones(ComplexF64, (ℂ^2)^4));
julia> H = FiniteMPOHamiltonian(fill(ℂ^2, 4), ((i,) => Z for i in 1:4));
julia> ψ, envs = timestep(ψ₀, H, 0.0, 0.1, TDVP());
julia> round(real(expectation_value(ψ, 2 => X)); digits = 6)
0.980067MPS time-evolution algorithms
MPSKit.TDVP Type
struct TDVP{A, E, G, F} <: MPSKit.AlgorithmSingle site MPS time-evolution algorithm based on the Time-Dependent Variational Principle.
For finite MPS, setting alg_expand to a bond-expansion algorithm (e.g. OptimalExpand, SketchedExpand) expands the bond with directions orthogonal to the current state ahead of each local integration, recovering Controlled Bond Expansion (CBE) TDVP and lifting the fixed-bond limitation of plain single-site TDVP. A truncating trunc is then required to cut the enlarged bond back down (selecting the truncated-SVD gauge). The expansion is state-preserving, as required for a consistent time evolution.
Note
By default the norm is not preserved: neither the bond expansion nor the truncation renormalizes, so the state norm keeps useful information (the accumulated truncation error in real time, or the decaying weight in imaginary time). Pass normalize = true to timestep/time_evolve to renormalize at every step instead, like a ground-state search. This is independent of imaginary_evolution. CBE is only available for finite MPS.
Fields
integrator::Any: algorithm used in the exponential solverstolgauge::Float64: tolerance for gauging algorithmgaugemaxiter::Int64: maximal amount of iterations for gauging algorithmalg_expand::Any: algorithm used to expand the bond ahead of each local update, ornothingfor none (finite CBE-TDVP)alg_gauge::Any: factorization used for the post-update gauge: a QR algorithm (no truncation) or a truncated SVDfinalize::Any: callback function applied after each iteration, of signaturefinalize(t, ψ, H, envs) -> ψ, envs
See also
Used as the algorithm argument of timestep, timestep! and time_evolve.
References
sourceMPSKit.TDVP2 Type
struct TDVP2{A, S, F} <: MPSKit.AlgorithmTwo-site MPS time-evolution algorithm based on the Time-Dependent Variational Principle.
Fields
integrator::Any: algorithm used in the exponential solverstolgauge::Float64: tolerance for gauging algorithmgaugemaxiter::Int64: maximal amount of iterations for gauging algorithmalg_svd::Any: algorithm used for the singular value decompositiontrunc::MatrixAlgebraKit.TruncationStrategy: algorithm used for truncation of the two-site updatefinalize::Any: callback function applied after each iteration, of signaturefinalize(t, ψ, H, envs) -> ψ, envs
See also
Used as the algorithm argument of timestep, timestep! and time_evolve.
References
sourceMPSKit.BUG Type
struct BUG{A, O, G, F} <: MPSKit.AlgorithmSingle-site time-evolution algorithm for finite MPS, based on the Basis-Update & Galerkin (BUG) integrator, an unconventional robust integrator for dynamical low-rank approximation with an observed second-order convergence.
Unlike TDVP, BUG advances both the basis (K-step) and the core (Galerkin C-step) tensors forward in time, with no backward-in-time substep. This makes it a more natural choice for imaginary-time (dissipative) evolution, where the backward core step of the conventional projector-splitting integrator TDVP can become unstable for large timesteps.
Fields
integrator::Any: algorithm used in the exponential solversalg_orth::Any: algorithm used to orthonormalize the augmented basis[U₀ │ K₁]after each local updatealg_gauge::Any: factorization used to gauge and truncate the bond ahead of each local updatefinalize::Any: callback function applied after each iteration, of signaturefinalize(t, ψ, H, envs) -> ψ, envs
Algorithm
Each half-sweep visits every site in turn and, at each site, (i) splits off the bond ahead of it (in the sweep direction) with alg_gauge, truncating it back to trunc, (ii) evolves the connecting tensor over dt/2, and (iii) augments the basis with the new directions discovered by the evolved tensor (old basis first, [U₀ │ K₁], orthonormalized with alg_orth)
Notably, this last step does not include any truncation, and is meant to truncate the previous half-sweep's augmentation. As a result, a truncation scheme truncrank(D) will result in a final MPS of dimension 2D. To restore a maximal dimension of D, apply changebonds with an SvdCut algorithm.
Note
By default the state is not renormalized, as the (loss of) norm might accumulate useful information, such as the accumulated truncation error in real time, or the decaying weight in imaginary time. Pass normalize = true to timestep/time_evolve to renormalize after every half-sweep instead.
Tip
Pass a TimerOutputs.TimerOutput as timeroutput to timestep/timestep! to obtain a breakdown of the time spent in the three steps above (cut_bond, AC_integrate, augment) over all local updates.
References
sourceTime-evolution MPOs
For evolving with an explicitly constructed propagator MPO, e.g. for an InfiniteMPS, use make_time_mpo with one of the expansion algorithms below.
MPSKit.make_time_mpo Function
make_time_mpo(H::MPOHamiltonian, dt::Number, alg; kwargs...) -> O::MPOConstruct an MPO that approximates
Keyword Arguments
imaginary_evolution::Bool = false: if true, the time evolution is done with an imaginary time step instead, (i.e. instead of ). This can be useful to compute the ground state of a Hamiltonian, or to compute finite-temperature properties of a system.
MPSKit.TaylorCluster Type
struct TaylorCluster <: MPSKit.AlgorithmAlgorithm for constructing the Nth order time evolution MPO using the Taylor cluster expansion.
Fields
N::Int64: order of the Taylor expansionextension::Bool: include higher-order correctionscompression::Bool: approximate compression of corrections, accurate up to orderN
See also
Used as the algorithm argument of make_time_mpo.
References
sourceMPSKit.WI Constant
const WI = TaylorCluster(; N = 1, extension = false, compression = false)First order Taylor expansion for a time-evolution MPO.
sourceMPSKit.WII Type
struct WII <: MPSKit.AlgorithmGeneralization of the Euler approximation of the operator exponential for MPOs.
Fields
tol::Float64: tolerance for convergence criteriummaxiter::Int64: maximal number of iterations
See also
Used as the algorithm argument of make_time_mpo.
References
sourceMPO–MPS products
Applying an MPO to a state — a propagator MPO among others — goes through approximate. The variational algorithms (DMRG2 and friends) treat the destination as an initial guess, whereas Zipup sweeps the product out in one pass and needs none.
MPSKit.approximate Function
approximate(ψ₀, (O, ψ), [environments]; kwargs...) -> (ψ, environments, ϵ)
approximate(ψ₀, (O, ψ), algorithm, [environments]) -> (ψ, environments, ϵ)
approximate!(ψ₀, (O, ψ), algorithm, [environments]) -> (ψ, environments, ϵ)
approximate(ψ₀, ψ, algorithm, [environments]) -> (ψ, environments, ϵ)
approximate!(ψ₀, ψ, algorithm, [environments]) -> (ψ, environments, ϵ)
approximate((O, ψ), algorithm) -> (ψ′, ϵ)
approximate!(ψ₀, (O, ψ), algorithm) -> (ψ, ϵ)Compute an approximation to the application of an operator O to the state ψ in the form of an MPS, using initial guess ψ₀. If only a state ψ is supplied instead of the (O, ψ) pair, ψ₀ is approximated directly to ψ (i.e. O is taken to be the identity).
Not every algorithm supports every combination of arguments below — see the per-algorithm notes at the end of this docstring before picking one.
Arguments
ψ₀::AbstractMPS: initial guess of the approximated state(O::AbstractMPO, ψ::AbstractMPS): operatorOand stateψto be approximatedψ::AbstractMPS: state to be approximated directly (without an operator)algorithm: approximation algorithm. See below for a list of available algorithms.[environments]: MPS environment manager
Keyword Arguments
The keyword-based call (no explicit algorithm) is a convenience method that picks an algorithm for you based on the type of ψ₀ (DMRG/DMRG2 for a finite MPS, VOMPS/IDMRG/ IDMRG2 for an infinite MPS) and only accepts the (O, ψ) tuple form of toapprox. Once you pass an explicit algorithm, keywords are no longer accepted here — configure the algorithm struct itself instead (e.g. DMRG(; tol, maxiter, verbosity)).
tol::Float64: tolerance for convergence criteriummaxiter::Int: maximum amount of iterationsverbosity::Int: display progress informationtrunc: if supplied, a truncated two-site sweep (DMRG2/IDMRG2) is prepended to refine the bond dimension before the single-site algorithm polishes the result.
Algorithms
Each algorithm below only supports a subset of the general interface. Check this table before picking one — in particular, note that only DMRG/DMRG2 accept a bare state ψ; the infinite algorithms always require an explicit (O, ψ) tuple, and VOMPS has no in-place approximate! at all. Zipup is a single sweep rather than an iterative optimization, so it uses no environments and returns (ψ, ϵ); its ψ₀ is a write destination, not an initial guess, and it may be omitted.
| Algorithm | Scheme | State ψ₀ | bare ψ allowed? | approximate! |
|---|---|---|---|---|
DMRG | single-site, fixes bond dim | AbstractFiniteMPS | ✅ | ✅ |
DMRG2 | two-site, truncates via trunc | AbstractFiniteMPS | ✅ | ✅ |
Zipup | streaming MPO-MPS compression | FiniteMPS destination, optional | ❌ (tuple only) | ✅ |
IDMRG | single-site, thermodynamic limit | InfiniteMPS / MultilineMPS | ❌ (tuple only) | ✅ |
IDMRG2 | two-site, thermodynamic limit, needs unit cell ≥ 2 | InfiniteMPS / MultilineMPS | ❌ (tuple only) | ✅ |
VOMPS | tangent-space truncation | InfiniteMPS / MultilineMPS | ❌ (tuple only) | ❌ (out-of-place only) |
InfiniteMPS/InfiniteMPO inputs are converted internally to MultilineMPS/MultilineMPO for IDMRG, IDMRG2, and VOMPS; you can also pass those types directly.
MPSKit.approximate! Function
approximate(ψ₀, (O, ψ), [environments]; kwargs...) -> (ψ, environments, ϵ)
approximate(ψ₀, (O, ψ), algorithm, [environments]) -> (ψ, environments, ϵ)
approximate!(ψ₀, (O, ψ), algorithm, [environments]) -> (ψ, environments, ϵ)
approximate(ψ₀, ψ, algorithm, [environments]) -> (ψ, environments, ϵ)
approximate!(ψ₀, ψ, algorithm, [environments]) -> (ψ, environments, ϵ)
approximate((O, ψ), algorithm) -> (ψ′, ϵ)
approximate!(ψ₀, (O, ψ), algorithm) -> (ψ, ϵ)Compute an approximation to the application of an operator O to the state ψ in the form of an MPS, using initial guess ψ₀. If only a state ψ is supplied instead of the (O, ψ) pair, ψ₀ is approximated directly to ψ (i.e. O is taken to be the identity).
Not every algorithm supports every combination of arguments below — see the per-algorithm notes at the end of this docstring before picking one.
Arguments
ψ₀::AbstractMPS: initial guess of the approximated state(O::AbstractMPO, ψ::AbstractMPS): operatorOand stateψto be approximatedψ::AbstractMPS: state to be approximated directly (without an operator)algorithm: approximation algorithm. See below for a list of available algorithms.[environments]: MPS environment manager
Keyword Arguments
The keyword-based call (no explicit algorithm) is a convenience method that picks an algorithm for you based on the type of ψ₀ (DMRG/DMRG2 for a finite MPS, VOMPS/IDMRG/ IDMRG2 for an infinite MPS) and only accepts the (O, ψ) tuple form of toapprox. Once you pass an explicit algorithm, keywords are no longer accepted here — configure the algorithm struct itself instead (e.g. DMRG(; tol, maxiter, verbosity)).
tol::Float64: tolerance for convergence criteriummaxiter::Int: maximum amount of iterationsverbosity::Int: display progress informationtrunc: if supplied, a truncated two-site sweep (DMRG2/IDMRG2) is prepended to refine the bond dimension before the single-site algorithm polishes the result.
Algorithms
Each algorithm below only supports a subset of the general interface. Check this table before picking one — in particular, note that only DMRG/DMRG2 accept a bare state ψ; the infinite algorithms always require an explicit (O, ψ) tuple, and VOMPS has no in-place approximate! at all. Zipup is a single sweep rather than an iterative optimization, so it uses no environments and returns (ψ, ϵ); its ψ₀ is a write destination, not an initial guess, and it may be omitted.
| Algorithm | Scheme | State ψ₀ | bare ψ allowed? | approximate! |
|---|---|---|---|---|
DMRG | single-site, fixes bond dim | AbstractFiniteMPS | ✅ | ✅ |
DMRG2 | two-site, truncates via trunc | AbstractFiniteMPS | ✅ | ✅ |
Zipup | streaming MPO-MPS compression | FiniteMPS destination, optional | ❌ (tuple only) | ✅ |
IDMRG | single-site, thermodynamic limit | InfiniteMPS / MultilineMPS | ❌ (tuple only) | ✅ |
IDMRG2 | two-site, thermodynamic limit, needs unit cell ≥ 2 | InfiniteMPS / MultilineMPS | ❌ (tuple only) | ✅ |
VOMPS | tangent-space truncation | InfiniteMPS / MultilineMPS | ❌ (tuple only) | ❌ (out-of-place only) |
InfiniteMPS/InfiniteMPO inputs are converted internally to MultilineMPS/MultilineMPO for IDMRG, IDMRG2, and VOMPS; you can also pass those types directly.
MPSKit.Zipup Type
struct Zipup{U<:MatrixAlgebraKit.TruncatedAlgorithm, D<:Union{Nothing, MatrixAlgebraKit.TruncatedAlgorithm}} <: MPSKit.AlgorithmAlgorithm that approximates an open-boundary finite MPO-MPS product using a zip-up sweep, optionally followed by a zip-down sweep in the opposite direction. The MPO and MPS are contracted one site at a time, and the enlarged virtual bond is truncated immediately. The sweep direction is selected by left_to_right.
approximate((O, ϕ), alg::Zipup) -> ψ, ϵ
approximate!(ψ, (O, ϕ), alg::Zipup) -> ψ, ϵContrary to the variational algorithms, this algorithm requires no initial guess: the in-place version simply uses ψ as the destination of the sweep, overwriting its contents, and may alias ϕ. The out-of-place version allocates a destination with the promoted scalar type of O and ϕ. Both return the truncation error ϵ alongside the approximated state.
Constructors
Zipup(; trunc, alg_svd = Defaults.alg_svd(), left_to_right = true)
Zipup(alg_zipup, [alg_zipdown]; left_to_right = true)Create a Zipup algorithm with the given truncated gauge algorithm, or by passing a truncation scheme and singular value decomposition algorithm. The keyword trunc can be either one truncation strategy for a single zip-up sweep, or a tuple (zipup_trunc, zipdown_trunc) for a zip-up sweep followed by a zip-down sweep. Equivalently, one can pass the corresponding truncated gauge algorithms directly as alg_zipup and alg_zipdown. The keyword left_to_right selects the direction of the zip-up sweep, the zip-down sweep always running in the opposite direction.
Following Paeckel et al., if the desired final bond dimension is D, one can use a more permissive zip-up truncation, e.g. rank 2D with stricter tolerances, and use alg_zipdown to impose the final truncation.
Fields
alg_zipup::MatrixAlgebraKit.TruncatedAlgorithm: algorithm used for gauging and truncating the local tensors during the zip-up sweepalg_zipdown::Union{Nothing, MatrixAlgebraKit.TruncatedAlgorithm}: algorithm used for the final locally gauged truncation pass;nothingskips this passleft_to_right::Bool: iftrue, zip up from left to right and truncate from right to left, and vice versa
References
source