Skip to content

Commit 917da4c

Browse files
committed
start setting up benchmark suite
1 parent e04bd7a commit 917da4c

File tree

8 files changed

+194
-31
lines changed

8 files changed

+194
-31
lines changed

benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ BenchmarkTools.DEFAULT_PARAMETERS.memory_tolerance = 0.01
1414
const PARAMS_PATH = joinpath(@__DIR__, "etc", "params.json")
1515
const SUITE = BenchmarkGroup()
1616
const MODULES = Dict{String, Symbol}(
17-
"derivatives" => :Derivatives
17+
"derivatives" => :DerivativesBenchmarks
1818
)
1919

20+
include("derivatives/DerivativesBenchmarks.jl")
21+
2022
load!(id::AbstractString; kwargs...) = load!(SUITE, id; kwargs...)
2123

2224
function load!(group::BenchmarkGroup, id::AbstractString; tune::Bool = false)
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
struct AC2Spec{S <: ElementarySpace} # <: BenchmarkSpec
2+
physicalspaces::NTuple{2, S}
3+
mps_virtualspaces::NTuple{3, S}
4+
mpo_virtualspaces::NTuple{3, SumSpace{S}}
5+
nonzero_keys::NTuple{2, Vector{Tuple{Int, Int}}}
6+
end
7+
8+
function AC2Spec(mps, mpo; site = length(mps) ÷ 2)
9+
physicalspaces = (physicalspace(mps, site), physicalspace(mps, site + 1))
10+
mps_virtualspaces = (left_virtualspace(mps, site), right_virtualspace(mps, site), right_virtualspace(mps, site + 1))
11+
mpo_virtualspaces = (left_virtualspace(mpo, site), right_virtualspace(mpo, site), right_virtualspace(mpo, site + 1))
12+
ks = (
13+
map(x -> (x.I[1], x.I[4]), nonzero_keys(mpo[site])),
14+
map(x -> (x.I[1], x.I[4]), nonzero_keys(mpo[site])),
15+
)
16+
return AC2Spec(physicalspaces, mps_virtualspaces, mpo_virtualspaces, ks)
17+
end
18+
19+
# Benchmarks
20+
# ----------
21+
function MPSKit.MPO_AC2_Hamiltonian(spec::AC2Spec{S}; T::Type = Float64) where {S}
22+
GL = randn(T, spec.mps_virtualspaces[1] spec.mpo_virtualspaces[1]' spec.mps_virtualspaces[1])
23+
GR = randn(T, spec.mps_virtualspaces[3] spec.mpo_virtualspaces[3] spec.mps_virtualspaces[3])
24+
W1 = JordanMPOTensor{T, S}(undef, spec.mpo_virtualspaces[1] spec.physicalspaces[1] spec.physicalspaces[1] spec.mpo_virtualspaces[2])
25+
for (r, c) in spec.nonzero_keys[1]
26+
r == c == 1 && continue
27+
r == size(W1, 1) && c == size(W1, 4) && continue
28+
W1[r, 1, 1, c] = randn!(W1[r, 1, 1, c])
29+
end
30+
W2 = JordanMPOTensor{T, S}(undef, spec.mpo_virtualspaces[2] spec.physicalspaces[2] spec.physicalspaces[2] spec.mpo_virtualspaces[3])
31+
for (r, c) in spec.nonzero_keys[2]
32+
r == c == 1 && continue
33+
r == size(W2, 1) && c == size(W2, 4) && continue
34+
W2[r, 1, 1, c] = randn!(W2[r, 1, 1, c])
35+
end
36+
37+
return MPSKit.MPO_AC2_Hamiltonian(GL, W1, W2, GR)
38+
end
39+
40+
function contraction_benchmark(spec::AC2Spec; T::Type = Float64)
41+
AA = randn(T, spec.mps_virtualspaces[1] spec.physicalspaces[1] spec.mps_virtualspaces[3] spec.physicalspaces[2]')
42+
H_eff = MPSKit.MPO_AC2_Hamiltonian(spec; T)
43+
H_prep, x_prep = MPSKit.prepare_operator!!(H_eff, AA)
44+
init() = randn!(similar(x_prep))
45+
46+
return @benchmarkable $H_prep * x setup = (x = $init())
47+
end
48+
49+
function preparation_benchmark(spec::AC2Spec; T::Type = Float64)
50+
init() = randn(T, spec.mps_virtualspaces[1] spec.physicalspaces[1] spec.mps_virtualspaces[3] spec.physicalspaces[2]')
51+
H_eff = MPSKit.MPO_AC2_Hamiltonian(spec; T)
52+
53+
return @benchmarkable begin
54+
O′, x′ = MPSKit.prepare_operator!!($H_eff, x)
55+
y = MPSKit.unprepare_operator!!(x′, O′, x)
56+
end setup = (x = $init())
57+
end
58+
59+
# Converters
60+
# ----------
61+
function tomlify(spec::AC2Spec)
62+
return Dict(
63+
"physicalspaces" => collect(tomlify.(spec.physicalspaces)),
64+
"mps_virtualspaces" => collect(tomlify.(spec.mps_virtualspaces)),
65+
"mpo_virtualspaces" => collect(tomlify.(spec.mpo_virtualspaces)),
66+
"nonzero_keys" => collect(map(Base.Fix1(map, collect), spec.nonzero_keys))
67+
)
68+
end
69+
70+
function untomlify(::Type{AC2Spec}, x)
71+
physicalspaces = Tuple(map(untomlify, x["physicalspaces"]))
72+
mps_virtualspaces = Tuple(map(untomlify, x["mps_virtualspaces"]))
73+
mpo_virtualspaces = Tuple(map(untomlify, x["mpo_virtualspaces"]))
74+
nonzero_keys = Tuple(map(Base.Fix1(map, Base.Fix1(map, Tuple)), x["nonzero_keys"]))
75+
return AC2Spec(physicalspaces, mps_virtualspaces, mpo_virtualspaces, nonzero_keys)
76+
end
77+
78+
function Base.convert(::Type{AC2Spec{S₁}}, spec::AC2Spec{S₂}) where {S₁, S₂}
79+
return S₁ === S₂ ? spec : AC2Spec(
80+
S₁.(spec.physicalspaces),
81+
S₁.(spec.mps_virtualspaces),
82+
SumSpace{S₁}.(spec.mpo_virtualspaces),
83+
spec.nonzero_keys
84+
)
85+
end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module DerivativesBenchmarks
2+
3+
export AC2Spec
4+
5+
using BenchmarkTools
6+
using TensorKit
7+
using BlockTensorKit
8+
using MPSKit
9+
using ..BenchUtils
10+
import ..BenchUtils: tomlify, untomlify
11+
12+
const SUITE = BenchmarkGroup()
13+
14+
include("AC2_benchmarks.jl")
15+
16+
17+
end
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
11
module BenchUtils
22

3+
export tomlify, untomlify
4+
5+
using TensorKit
6+
using BlockTensorKit
7+
using TOML
8+
9+
tomlify(x::VectorSpace) = string(x)
10+
untomlify(::Type{<:VectorSpace}, x) = eval(Meta.parse(x))
11+
12+
13+
# Type piracy but oh well
14+
TensorKit.ComplexSpace(V::ElementarySpace) = ComplexSpace(dim(V), isdual(V))
15+
16+
function TensorKit.U1Space(V::SU2Space)
17+
dims = TensorKit.SectorDict{U1Irrep, Int}()
18+
for c in sectors(V), m in (-c.j):(c.j)
19+
u1 = U1Irrep(m)
20+
dims[u1] = get(dims, u1, 0) + 1
21+
end
22+
return U1Space(dims; dual = isdual(V))
23+
end
24+
25+
BlockTensorKit.SumSpace{S}(V::SumSpace) where {S} = SumSpace(map(S, V.spaces))
26+
327
end

src/MPSKit.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ using MatrixAlgebraKit: TruncationStrategy, PolarViaSVD, LAPACK_SVDAlgorithm
6565
using BlockTensorKit
6666
using BlockTensorKit: TensorMapSumSpace
6767
using TensorOperations
68+
using TensorOperations: AbstractBackend, DefaultBackend, DefaultAllocator
6869
using KrylovKit
6970
using KrylovKit: KrylovAlgorithm
7071
using OptimKit

src/algorithms/derivatives/derivatives.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,31 @@ const DerivativeOrMultiplied{D <: DerivativeOperator} = Union{MultipliedOperator
213213
(x::LazySum{<:DerivativeOrMultiplied})(y, t::Number) = sum(O -> O(y, t), x)
214214
(x::LazySum{<:DerivativeOrMultiplied})(y) = sum(O -> O(y), x)
215215
Base.:*(h::LazySum{<:Union{DerivativeOrMultiplied}}, v) = h(v)
216+
217+
# Operator preparation
218+
# --------------------
219+
"""
220+
prepare_operator!!(O, x, [backend], [allocator]) -> O′, x′
221+
222+
Given an operator and vector, try to construct a more efficient representation of that operator for repeated application.
223+
This should always be used in conjunction with [`unprepare_operator!!`](@ref).
224+
"""
225+
function prepare_operator!!(
226+
O, x,
227+
backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator()
228+
)
229+
return O, x
230+
end
231+
232+
"""
233+
unprepare_operator!!(y, O, x, [backend], [allocator]) -> y′
234+
235+
Given the result `y` of applying a prepared operator `O` on vectors like `x`, undo the preparation work on the vector, and clean up the operator.
236+
This should always be used in conjunction with [`prepare_operator!!`](@ref).
237+
"""
238+
function unprepare_operator!!(
239+
y, O, x,
240+
backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator()
241+
)
242+
return y
243+
end

src/algorithms/derivatives/hamiltonian_derivatives.jl

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,13 @@ const _HAM_MPS_TYPES = Union{
7575
InfiniteMPS{<:MPSTensor},
7676
}
7777

78-
function AC_hamiltonian(
79-
site::Int, below::_HAM_MPS_TYPES, operator::MPOHamiltonian{<:JordanMPOTensor},
80-
above::_HAM_MPS_TYPES, envs
78+
function prepare_operator!!(
79+
O::MPO_AC_Hamiltonian{<:Any, <:JordanMPOTensor, <:Any}, x::MPSTensor,
80+
backend::AbstractBackend, allocator
8181
)
82-
GL = leftenv(envs, site, below)
83-
GR = rightenv(envs, site, below)
84-
W = operator[site]
82+
GL = O.leftenv
83+
W = only(O.operators)
84+
GR = O.rightenv
8585

8686
# starting
8787
if nonzero_length(W.C) > 0
@@ -117,7 +117,7 @@ function AC_hamiltonian(
117117
end
118118

119119
# not_started
120-
if isfinite(operator) && site == length(operator)
120+
if size(W, 4) == 1
121121
not_started = missing
122122
elseif !ismissing(starting)
123123
I = id(storagetype(GR[1]), physicalspace(W))
@@ -128,7 +128,7 @@ function AC_hamiltonian(
128128
end
129129

130130
# finished
131-
if isfinite(operator) && site == 1
131+
if size(W, 1) == 1
132132
finished = missing
133133
elseif !ismissing(ending)
134134
I = id(storagetype(GL[end]), physicalspace(W))
@@ -142,19 +142,20 @@ function AC_hamiltonian(
142142
A = W.A
143143
continuing = (GL[2:(end - 1)], A, GR[2:(end - 1)])
144144

145-
return JordanMPO_AC_Hamiltonian(
145+
O′ = JordanMPO_AC_Hamiltonian(
146146
onsite, not_started, finished, starting, ending, continuing
147147
)
148+
149+
return O′, x
148150
end
149151

150-
function AC2_hamiltonian(
151-
site::Int, below::_HAM_MPS_TYPES, operator::MPOHamiltonian{<:JordanMPOTensor},
152-
above::_HAM_MPS_TYPES, envs
152+
function prepare_operator!!(
153+
O::MPO_AC2_Hamiltonian{<:Any, <:JordanMPOTensor, <:JordanMPOTensor, <:Any}, x::MPOTensor,
154+
backend::AbstractBackend, allocator
153155
)
154-
GL = leftenv(envs, site, below)
155-
GR = rightenv(envs, site + 1, below)
156-
W1 = operator[site]
157-
W2 = operator[site + 1]
156+
GL = O.leftenv
157+
W1, W2 = O.operators
158+
GR = O.rightenv
158159

159160
# starting left - continuing right
160161
if nonzero_length(W1.C) > 0 && nonzero_length(W2.A) > 0
@@ -256,7 +257,7 @@ function AC2_hamiltonian(
256257
end
257258

258259
# finished
259-
if isfinite(operator) && site + 1 == length(operator)
260+
if size(W2, 4) == 1
260261
II = missing
261262
elseif !ismissing(IC)
262263
I = id(storagetype(GR[1]), physicalspace(W2))
@@ -271,7 +272,7 @@ function AC2_hamiltonian(
271272
end
272273

273274
# unstarted
274-
if isfinite(operator) && site == 1
275+
if size(W1, 1) == 1
275276
EE = missing
276277
elseif !ismissing(BE)
277278
I = id(storagetype(GL[end]), physicalspace(W1))
@@ -289,7 +290,8 @@ function AC2_hamiltonian(
289290
# TODO: MPODerivativeOperator code reuse + optimization
290291
AA = (GL[2:(end - 1)], W1.A, W2.A, GR[2:(end - 1)])
291292

292-
return JordanMPO_AC2_Hamiltonian(II, IC, ID, CB, CA, AB, AA, BE, DE, EE)
293+
O′ = JordanMPO_AC2_Hamiltonian(II, IC, ID, CB, CA, AB, AA, BE, DE, EE)
294+
return O′, x
293295
end
294296

295297
# Actions

src/algorithms/fixedpoint.jl

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,30 @@ Compute the fixedpoint of a linear operator `A` using the specified eigensolver
88
fixedpoint is assumed to be unique.
99
"""
1010
function fixedpoint(A, x₀, which::Symbol, alg::Lanczos)
11-
vals, vecs, info = eigsolve(A, x₀, 1, which, alg)
11+
A′, x₀′ = prepare_operator!!(A, x₀)
12+
vals, vecs, info = eigsolve(A′, x₀′, 1, which, alg)
1213

13-
if info.converged == 0
14+
info.converged == 0 &&
1415
@warnv 1 "fixedpoint not converged after $(info.numiter) iterations: normres = $(info.normres[1])"
15-
end
1616

17-
return vals[1], vecs[1]
17+
λ = vals[1]
18+
v = unprepare_operator!!(vecs[1], A′, x₀)
19+
20+
return λ, v
1821
end
1922

2023
function fixedpoint(A, x₀, which::Symbol, alg::Arnoldi)
21-
TT, vecs, vals, info = schursolve(A, x₀, 1, which, alg)
24+
A′, x₀′ = prepare_operator!!(A, x₀)
25+
TT, vecs, vals, info = schursolve(A′, x₀′, 1, which, alg)
2226

23-
if info.converged == 0
27+
info.converged == 0 &&
2428
@warnv 1 "fixedpoint not converged after $(info.numiter) iterations: normres = $(info.normres[1])"
25-
end
26-
if size(TT, 2) > 1 && TT[2, 1] != 0
27-
@warnv 1 "non-unique fixedpoint detected"
28-
end
29+
size(TT, 2) > 1 && TT[2, 1] != 0 && @warnv 1 "non-unique fixedpoint detected"
30+
31+
λ = vals[1]
32+
v = unprepare_operator!!(vecs[1], A′, x₀)
2933

30-
return vals[1], vecs[1]
34+
return λ, v
3135
end
3236

3337
function fixedpoint(A, x₀, which::Symbol; kwargs...)

0 commit comments

Comments
 (0)