Skip to content

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
julia
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 state

  • H::AbstractMPO: operator that generates the time evolution (can be time-dependent).

  • t_span::AbstractVector{<:Number}: time points over which the time evolution is stepped

  • alg: algorithm to use for the time evolution, e.g. TDVP or TDVP2.

  • envs: MPS environment manager

Keyword Arguments

  • verbosity::Int = 0: verbosity level for logging

  • 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 state

  • envs: the updated environment manager

source
MPSKit.timestep Function
julia
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 state

  • H::AbstractMPO: operator that generates the time evolution (can be time-dependent).

  • t::Number: starting time of time-step

  • dt::Number: time-step magnitude

  • alg: algorithm to use for the time evolution, e.g. TDVP or TDVP2.

  • 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 state

  • envs: 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
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.980067
source
MPSKit.timestep! Function
julia
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 state

  • H::AbstractMPO: operator that generates the time evolution (can be time-dependent).

  • t::Number: starting time of time-step

  • dt::Number: time-step magnitude

  • alg: algorithm to use for the time evolution, e.g. TDVP or TDVP2.

  • 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 state

  • envs: 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
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.980067
source

MPS time-evolution algorithms

MPSKit.TDVP Type
julia
struct TDVP{A, E, G, F} <: MPSKit.Algorithm

Single 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 solvers

  • tolgauge::Float64: tolerance for gauging algorithm

  • gaugemaxiter::Int64: maximal amount of iterations for gauging algorithm

  • alg_expand::Any: algorithm used to expand the bond ahead of each local update, or nothing for none (finite CBE-TDVP)

  • alg_gauge::Any: factorization used for the post-update gauge: a QR algorithm (no truncation) or a truncated SVD

  • finalize::Any: callback function applied after each iteration, of signature finalize(t, ψ, H, envs) -> ψ, envs

See also

Used as the algorithm argument of timestep, timestep! and time_evolve.

References

source
MPSKit.TDVP2 Type
julia
struct TDVP2{A, S, F} <: MPSKit.Algorithm

Two-site MPS time-evolution algorithm based on the Time-Dependent Variational Principle.

Fields

  • integrator::Any: algorithm used in the exponential solvers

  • tolgauge::Float64: tolerance for gauging algorithm

  • gaugemaxiter::Int64: maximal amount of iterations for gauging algorithm

  • alg_svd::Any: algorithm used for the singular value decomposition

  • trunc::MatrixAlgebraKit.TruncationStrategy: algorithm used for truncation of the two-site update

  • finalize::Any: callback function applied after each iteration, of signature finalize(t, ψ, H, envs) -> ψ, envs

See also

Used as the algorithm argument of timestep, timestep! and time_evolve.

References

source
MPSKit.BUG Type
julia
struct BUG{A, O, G, F} <: MPSKit.Algorithm

Single-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 solvers

  • alg_orth::Any: algorithm used to orthonormalize the augmented basis [U₀ │ K₁] after each local update

  • alg_gauge::Any: factorization used to gauge and truncate the bond ahead of each local update

  • finalize::Any: callback function applied after each iteration, of signature finalize(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

source

Time-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
julia
make_time_mpo(H::MPOHamiltonian, dt::Number, alg; kwargs...) -> O::MPO

Construct 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.
source
MPSKit.TaylorCluster Type
julia
struct TaylorCluster <: MPSKit.Algorithm

Algorithm for constructing the Nth order time evolution MPO using the Taylor cluster expansion.

Fields

  • N::Int64: order of the Taylor expansion

  • extension::Bool: include higher-order corrections

  • compression::Bool: approximate compression of corrections, accurate up to order N

See also

Used as the algorithm argument of make_time_mpo.

References

source
MPSKit.WI Constant
julia
const WI = TaylorCluster(; N = 1, extension = false, compression = false)

First order Taylor expansion for a time-evolution MPO.

source
MPSKit.WII Type
julia
struct WII <: MPSKit.Algorithm

Generalization of the Euler approximation of the operator exponential for MPOs.

Fields

  • tol::Float64: tolerance for convergence criterium

  • maxiter::Int64: maximal number of iterations

See also

Used as the algorithm argument of make_time_mpo.

References

source

MPO–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
julia
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): operator O and 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 criterium

  • maxiter::Int: maximum amount of iterations

  • verbosity::Int: display progress information

  • trunc: 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.

AlgorithmSchemeState ψ₀bare ψ allowed?approximate!
DMRGsingle-site, fixes bond dimAbstractFiniteMPS
DMRG2two-site, truncates via truncAbstractFiniteMPS
Zipupstreaming MPO-MPS compressionFiniteMPS destination, optional❌ (tuple only)
IDMRGsingle-site, thermodynamic limitInfiniteMPS / MultilineMPS❌ (tuple only)
IDMRG2two-site, thermodynamic limit, needs unit cell ≥ 2InfiniteMPS / MultilineMPS❌ (tuple only)
VOMPStangent-space truncationInfiniteMPS / 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.

source
MPSKit.approximate! Function
julia
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): operator O and 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 criterium

  • maxiter::Int: maximum amount of iterations

  • verbosity::Int: display progress information

  • trunc: 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.

AlgorithmSchemeState ψ₀bare ψ allowed?approximate!
DMRGsingle-site, fixes bond dimAbstractFiniteMPS
DMRG2two-site, truncates via truncAbstractFiniteMPS
Zipupstreaming MPO-MPS compressionFiniteMPS destination, optional❌ (tuple only)
IDMRGsingle-site, thermodynamic limitInfiniteMPS / MultilineMPS❌ (tuple only)
IDMRG2two-site, thermodynamic limit, needs unit cell ≥ 2InfiniteMPS / MultilineMPS❌ (tuple only)
VOMPStangent-space truncationInfiniteMPS / 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.

source
MPSKit.Zipup Type
julia
struct Zipup{U<:MatrixAlgebraKit.TruncatedAlgorithm, D<:Union{Nothing, MatrixAlgebraKit.TruncatedAlgorithm}} <: MPSKit.Algorithm

Algorithm 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.

julia
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

julia
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 sweep

  • alg_zipdown::Union{Nothing, MatrixAlgebraKit.TruncatedAlgorithm}: algorithm used for the final locally gauged truncation pass; nothing skips this pass

  • left_to_right::Bool: if true, zip up from left to right and truncate from right to left, and vice versa

References

source