Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,6 @@ RecipesBase = "1.1"
TensorKit = "0.17.1"
TensorKitManifolds = "0.7, 0.8"
TensorOperations = "5.6.2"
TimerOutputs = "0.5.29"
TimerOutputs = "1"
VectorInterface = "0.2, 0.3, 0.4, 0.5, 0.6"
julia = "1.10"
4 changes: 4 additions & 0 deletions docs/src/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,15 @@ When releasing a new version, move the "Unreleased" changes to a new version sec
- `correlator` now throws an `ArgumentError` when the sites are not ordered as `i < j`.
Previously such a call only logged an `@error` and then continued into a contraction that is
not the requested correlator. ([#489](https://github.com/QuantumKitHub/MPSKit.jl/pull/489))
- TimerOutputs 1.x is now required. The timing tables printed at `verbosity > 3` use the new
layout (tree guides, heat bars) and additionally report per-section GC time.

### Deprecated

### Removed

- Support for TimerOutputs 0.5.

### Fixed

- `isfinite(::WindowMPOHamiltonian)` was undefined. ([#489](https://github.com/QuantumKitHub/MPSKit.jl/pull/489))
Expand Down
4 changes: 4 additions & 0 deletions docs/src/lib/lib.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Library documentation

```@meta
CurrentModule = MPSKit
```

```@autodocs
Modules = [MPSKit, MPSKit.DynamicTols, MPSKit.Defaults]
```
2 changes: 1 addition & 1 deletion src/MPSKit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ using Random
using Base: @kwdef, @propagate_inbounds
using LoggingExtras
using OhMyThreads
using TimerOutputs: TimerOutput, @timeit, timeit, reset_timer!, disable_timer!, enable_timer!
using TimerOutputs: TimerOutput, NoTimerOutput, @timeit, timeit, print_timer

# Includes
# --------
Expand Down
24 changes: 18 additions & 6 deletions src/algorithms/algorithm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,22 @@ end

# TIMEROUTPUT utility
# -------------------
# Shared sentinel passed as the default `timeroutput` kwarg by functions that optionally accept a timer.
# `@timeit` is a no-op when the destination timer is disabled, so unrelated callers pay no instrumentation cost.
# The merge sites that mutate `timeroutput` must gate on `timeroutput.enabled` so they don't pollute this shared object.
const DISABLED_TIMER = let t = TimerOutput("DISABLED")
disable_timer!(t)
t

timer_treepoint(::NoTimerOutput) = String[]
timer_treepoint(to::TimerOutput) = String[section.name for section in to.stack]

subtimer(::NoTimerOutput) = NoTimerOutput()
subtimer(to::TimerOutput) = to.enabled ? TimerOutput() : NoTimerOutput()

merge_subtimer!(::NoTimerOutput, ::NoTimerOutput; tree_point) = nothing
merge_subtimer!(::TimerOutput, ::NoTimerOutput; tree_point) = nothing
function merge_subtimer!(to::TimerOutput, sub::TimerOutput; tree_point)
to.enabled && merge!(to, sub; tree_point)
return nothing
end

# `print_timer` is used over plain `show` to opt into the GC time column
struct TimerReport{T}
to::T
end
Base.show(io::IO, r::TimerReport) = print_timer(io, r.to; gc = true)
10 changes: 5 additions & 5 deletions src/algorithms/grassmann.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module GrassmannMPS

using ..MPSKit
using ..MPSKit: AbstractMPSEnvironments, InfiniteEnvironments, MultilineEnvironments,
AC_projection, recalculate!, TimerOutput, DISABLED_TIMER, @timeit, default_allocator
AC_projection, recalculate!, NoTimerOutput, @timeit, default_allocator
using TensorOperations: AbstractBackend, DefaultBackend
using TensorKit
using OhMyThreads
Expand Down Expand Up @@ -149,7 +149,7 @@ that the allocator it selects is inferable.
function fg(
state::FiniteMPS, operator::Union{O, LazySum{O}},
envs::AbstractMPSEnvironments = environments(state, operator, state);
timeroutput::TimerOutput = DISABLED_TIMER,
timeroutput = NoTimerOutput(),
backend::AbstractBackend = DefaultBackend(),
# accepted for interface uniformity, but unused: this gradient is serial regardless
scheduler::Scheduler = SerialScheduler(),
Expand All @@ -168,7 +168,7 @@ end
function fg(
state::InfiniteMPS, operator::Union{O, LazySum{O}},
envs::AbstractMPSEnvironments = environments(state, operator, state);
timeroutput::TimerOutput = DISABLED_TIMER,
timeroutput = NoTimerOutput(),
backend::AbstractBackend = DefaultBackend(),
scheduler::Scheduler = MPSKit.Defaults.scheduler[],
) where {O <: InfiniteMPOHamiltonian}
Expand All @@ -190,7 +190,7 @@ end
function fg(
state::InfiniteMPS, operator::Union{O, LazySum{O}},
envs::AbstractMPSEnvironments = environments(state, operator, state);
timeroutput::TimerOutput = DISABLED_TIMER,
timeroutput = NoTimerOutput(),
backend::AbstractBackend = DefaultBackend(),
scheduler::Scheduler = MPSKit.Defaults.scheduler[],
) where {O <: InfiniteMPO}
Expand All @@ -212,7 +212,7 @@ end
function fg(
state::MultilineMPS, operator::MultilineMPO,
envs::MultilineEnvironments = environments(state, operator, state);
timeroutput::TimerOutput = DISABLED_TIMER,
timeroutput = NoTimerOutput(),
backend::AbstractBackend = DefaultBackend(),
scheduler::Scheduler = MPSKit.Defaults.scheduler[],
)
Expand Down
16 changes: 9 additions & 7 deletions src/algorithms/groundstate/dmrg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -280,16 +280,18 @@ function find_groundstate!(
)
# the sweep is serial, so a single allocator serves all local updates
allocator = default_allocator(ψ, SerialScheduler())
return _find_groundstate_sweep!(ψ, H, alg, envs, allocator)

name = string(nameof(typeof(alg)))
timeroutput = alg.verbosity > 3 ? TimerOutput(name) : NoTimerOutput()

return find_groundstate_sweep!(ψ, H, alg, envs, allocator, timeroutput)
end

function _find_groundstate_sweep!(
ψ::AbstractFiniteMPS, H, alg::Union{DMRG, DMRG2}, envs, allocator
function find_groundstate_sweep!(
ψ::AbstractFiniteMPS, H, alg::Union{DMRG, DMRG2}, envs, allocator, timeroutput
)
name = string(nameof(typeof(alg)))
log = IterLog(name)
timeroutput = TimerOutput(name)
alg.verbosity > 3 || disable_timer!(timeroutput)

Tr = real(scalartype(ψ))
n = _num_updates(alg, ψ)
Expand Down Expand Up @@ -338,12 +340,12 @@ function _find_groundstate_sweep!(
# truncation error rather than the (unreachable) bare `tol`. With no truncation
# (`ϵ_truncs .= 0`, e.g. single-site/QR gauge) this reduces to the plain `ϵ_global ≤ tol`.
if ϵ_global <= max(alg.tol, maximum(ϵ_truncs))
@infov 4 timeroutput
@infov 4 TimerReport(timeroutput)
@infov 2 logfinish!(log, iter, ϵ_global, expectation_value(ψ, H, envs))
break
end
if iter == alg.maxiter
@infov 4 timeroutput
@infov 4 TimerReport(timeroutput)
@warnv 1 logcancel!(log, iter, ϵ_global, expectation_value(ψ, H, envs))
else
@infov 3 logiter!(log, iter, ϵ_global, expectation_value(ψ, H, envs))
Expand Down
11 changes: 8 additions & 3 deletions src/algorithms/groundstate/gradient_grassmann.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,17 @@ function find_groundstate(
@warn "This is not fully supported - split the mps up in a sum of mps's and optimize separately"
normalize!(ψ)

timeroutput = TimerOutput("GradientGrassmann")
method_verbosity = hasproperty(alg.method, :verbosity) ? alg.method.verbosity : 0
method_verbosity > 3 || disable_timer!(timeroutput)
# function barrier: the timer type must be concrete for the closures below to elide timing
timeroutput = method_verbosity > 3 ? TimerOutput("GradientGrassmann") : NoTimerOutput()

# read the scheduler here rather than in `fg`, so that the allocator it selects is inferable
scheduler = Defaults.scheduler[]

return _find_groundstate(ψ, H, alg, envs, scheduler, timeroutput, method_verbosity)
end

function _find_groundstate(ψ, H, alg::GradientGrassmann, envs, scheduler, timeroutput, method_verbosity)
fg(x) = timeit(
() -> GrassmannMPS.fg(x, H, envs; timeroutput, alg.backend, scheduler),
timeroutput, "fg",
Expand Down Expand Up @@ -117,7 +122,7 @@ function find_groundstate(
)

LoggingExtras.withlevel(; verbosity = method_verbosity) do
@infov 4 timeroutput
@infov 4 TimerReport(timeroutput)
end

return x, envs, normgradhistory[end]
Expand Down
21 changes: 10 additions & 11 deletions src/algorithms/groundstate/idmrg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,21 @@ Used as the `algorithm` argument of [`find_groundstate`](@ref), [`leading_bounda
end

# Internal state of the IDMRG algorithm
struct IDMRGState{S, O, E, T, A}
struct IDMRGState{S, O, E, T, TO, A}
mps::S
operator::O
envs::E
iter::Int
ϵ::Float64 # TODO: Could be any <:Real
energy::T
timeroutput::TimerOutput
timeroutput::TO
allocator::A
end
function IDMRGState{T}(
mps::S, operator::O, envs::E, iter::Int, ϵ::Float64, energy,
timeroutput::TimerOutput, allocator::A,
) where {S, O, E, T, A}
return IDMRGState{S, O, E, T, A}(
timeroutput::TO, allocator::A,
) where {S, O, E, T, TO, A}
return IDMRGState{S, O, E, T, TO, A}(
mps, operator, envs, iter, ϵ, T(energy), timeroutput, allocator
)
end
Expand All @@ -98,8 +98,7 @@ function _find_groundstate_idmrg(mps, operator, alg::alg_type, envs) where {alg_
(length(mps) ≤ 1 && alg isa IDMRG2) && throw(ArgumentError("unit cell should be >= 2"))
name = alg isa IDMRG ? "IDMRG" : "IDMRG2"
log = IterLog(name)
timeroutput = TimerOutput(name)
alg.verbosity > 3 || disable_timer!(timeroutput)
timeroutput = alg.verbosity > 3 ? TimerOutput(name) : NoTimerOutput()
mps = copy(mps)
iter = 0
# the sweeps are serial, so one allocator serves the whole solve
Expand All @@ -120,12 +119,12 @@ function _find_groundstate_idmrg(mps, operator, alg::alg_type, envs) where {alg_
return LoggingExtras.withlevel(; alg.verbosity) do
for (mps, envs, ϵ, ΔE) in it
if ϵ ≤ alg.tol
@infov 4 timeroutput
@infov 4 TimerReport(timeroutput)
@infov 2 logfinish!(log, it.iter, ϵ, ΔE)
break
end
if it.iter ≥ alg.maxiter
@infov 4 timeroutput
@infov 4 TimerReport(timeroutput)
@warnv 1 logcancel!(log, it.iter, ϵ, ΔE)
break
end
Expand Down Expand Up @@ -192,7 +191,7 @@ function localupdate_step!(
end

function _localupdate_sweep_idmrg!(
ψ, H, envs, alg_eigsolve, timeroutput::TimerOutput;
ψ, H, envs, alg_eigsolve, timeroutput;
backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator()
)
local E
Expand Down Expand Up @@ -230,7 +229,7 @@ function _localupdate_sweep_idmrg!(
end

function _localupdate_sweep_idmrg2!(
ψ, H, envs, alg_eigsolve, alg_trunc, alg_svd, timeroutput::TimerOutput;
ψ, H, envs, alg_eigsolve, alg_trunc, alg_svd, timeroutput;
backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator()
)
# @timeit wraps its body in try-finally, which is a new lexical scope: declare locals
Expand Down
20 changes: 9 additions & 11 deletions src/algorithms/groundstate/vumps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ Used as the `algorithm` argument of [`find_groundstate`](@ref) and [`leading_bou
end

# Internal state of the VUMPS algorithm
struct VUMPSState{S, O, E}
struct VUMPSState{S, O, E, T}
mps::S
operator::O
envs::E
iter::Int
ϵ::Float64
which::Symbol
timeroutput::TimerOutput
timeroutput::T
end

function find_groundstate(
Expand All @@ -64,8 +64,7 @@ function dominant_eigsolve(
which
)
log = IterLog("VUMPS")
timeroutput = TimerOutput("VUMPS")
alg.verbosity > 3 || disable_timer!(timeroutput)
timeroutput = alg.verbosity > 3 ? TimerOutput("VUMPS") : NoTimerOutput()
iter = 0

mps = copy(mps)
Expand All @@ -81,12 +80,12 @@ function dominant_eigsolve(

for (mps, envs, ϵ) in it
if ϵ ≤ alg.tol
@infov 4 timeroutput
@infov 4 TimerReport(timeroutput)
@infov 2 logfinish!(log, it.iter, ϵ, expectation_value(mps, operator, envs))
return mps, envs, ϵ
end
if it.iter ≥ alg.maxiter
@infov 4 timeroutput
@infov 4 TimerReport(timeroutput)
@warnv 1 logcancel!(log, it.iter, ϵ, expectation_value(mps, operator, envs))
return mps, envs, ϵ
end
Expand Down Expand Up @@ -137,17 +136,16 @@ function localupdate_step!(
ACs = mps.AL
dst_ACs = mps isa Multiline ? eachcol(ACs) : ACs

tree_point = String[section.name for section in state.timeroutput.timer_stack]
tree_point = timer_treepoint(state.timeroutput)
allocator = default_allocator(mps, scheduler)
tforeach(eachsite(mps); scheduler) do site
sub_timeroutput = TimerOutput()
sub_timeroutput = subtimer(state.timeroutput)
dst_ACs[site] = _localupdate_vumps_step!(
site, mps, state.operator, state.envs, src_ACs[site], src_Cs[site];
alg_orth, state.which, alg_eigsolve,
timeroutput = sub_timeroutput, it.backend, allocator,
)
state.timeroutput.enabled &&
merge!(state.timeroutput, sub_timeroutput; tree_point)
merge_subtimer!(state.timeroutput, sub_timeroutput; tree_point)
end

return ACs
Expand All @@ -157,7 +155,7 @@ function _localupdate_vumps_step!(
site, mps, operator, envs, AC₀, C₀;
alg_orth = Defaults.alg_orth(),
alg_eigsolve = Defaults.eigsolver, which,
timeroutput::TimerOutput = DISABLED_TIMER,
timeroutput = NoTimerOutput(),
backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator(),
)
local AC, C
Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/timestep/bug.jl
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ function timestep!(
ψ::AbstractFiniteMPS, H, t::Number, dt::Number, alg::BUG,
envs::AbstractMPSEnvironments = environments(ψ, H, ψ);
imaginary_evolution::Bool = false, normalize::Bool = false,
timeroutput::TimerOutput = DISABLED_TIMER
timeroutput = NoTimerOutput()
)
L = length(ψ)
h = dt / 2
Expand Down
18 changes: 9 additions & 9 deletions src/environments/infinite_envs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ rightenv(envs::InfiniteEnvironments, site::Int, state) = envs.GRs[site]

function environments(
below::InfiniteMPS, operator::Union{InfiniteMPO, InfiniteMPOHamiltonian}, above;
timeroutput::TimerOutput = DISABLED_TIMER, kwargs...
timeroutput = NoTimerOutput(), kwargs...
)
alg = environment_alg(below, operator, above; kwargs...)
return environments(below, operator, above, alg; timeroutput)
end
function environments(
below::InfiniteMPS, operator::Union{InfiniteMPO, InfiniteMPOHamiltonian}, above,
alg;
timeroutput::TimerOutput = DISABLED_TIMER
timeroutput = NoTimerOutput()
)
GLs, GRs = initialize_environments(below, operator, above)
envs = InfiniteEnvironments(GLs, GRs)
Expand Down Expand Up @@ -58,7 +58,7 @@ end
function recalculate!(
envs::InfiniteEnvironments, below,
operator::Union{InfiniteMPO, InfiniteMPOHamiltonian}, above = below;
timeroutput::TimerOutput = DISABLED_TIMER, kwargs...
timeroutput = NoTimerOutput(), kwargs...
)
alg = environment_alg(below, operator, above; kwargs...)
return recalculate!(envs, below, operator, above, alg; timeroutput)
Expand All @@ -84,7 +84,7 @@ function recalculate!(
envs::InfiniteEnvironments, below::InfiniteMPS,
operator::Union{InfiniteMPO, InfiniteMPOHamiltonian},
above::InfiniteMPS, alg;
timeroutput::TimerOutput = DISABLED_TIMER,
timeroutput = NoTimerOutput(),
)
if !issamespace(envs, below, operator, above)
# TODO: in-place initialization?
Expand All @@ -93,17 +93,17 @@ function recalculate!(
copy!(envs.GRs, GRs)
end

tree_point = String[section.name for section in timeroutput.timer_stack]
tree_point = timer_treepoint(timeroutput)
@sync begin
@spawn begin
sub_timeroutput = TimerOutput()
sub_timeroutput = subtimer(timeroutput)
@timeit sub_timeroutput "left_envs" compute_leftenvs!(envs, below, operator, above, alg)
timeroutput.enabled && merge!(timeroutput, sub_timeroutput; tree_point)
merge_subtimer!(timeroutput, sub_timeroutput; tree_point)
end
@spawn begin
sub_timeroutput = TimerOutput()
sub_timeroutput = subtimer(timeroutput)
@timeit sub_timeroutput "right_envs" compute_rightenvs!(envs, below, operator, above, alg)
timeroutput.enabled && merge!(timeroutput, sub_timeroutput; tree_point)
merge_subtimer!(timeroutput, sub_timeroutput; tree_point)
end
end
normalize!(envs, below, operator, above)
Expand Down
Loading
Loading