Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a73f713
setup benchmarks
lkdvos Nov 1, 2025
ecab865
add main entry point
lkdvos Nov 1, 2025
1779d3d
add Utility module
lkdvos Nov 1, 2025
2511205
start setting up benchmark suite
lkdvos Nov 2, 2025
337a252
add heisenberg script
lkdvos Nov 2, 2025
4488368
add test suites
lkdvos Nov 2, 2025
8be1a08
small updates
lkdvos Nov 2, 2025
f4beed4
update scripts
lkdvos Nov 3, 2025
773c760
Precomputed derivatives I
lkdvos Nov 3, 2025
ee0bc38
Precomputed derivatives II
lkdvos Nov 3, 2025
7fbefdf
Precomputed derivatives III
lkdvos Nov 3, 2025
c1301f5
add plot script
lkdvos Nov 4, 2025
1428273
Precomputed derivatives IV
lkdvos Dec 14, 2025
2cb10f5
rework benchmarks
lkdvos Dec 16, 2025
13132ab
temporary revert
lkdvos Dec 16, 2025
d0ad7e6
Avoid copy in matrix contract
lkdvos Dec 16, 2025
3250a6a
Add buffer allocator
lkdvos Dec 17, 2025
2b7e4d2
clean up code
lkdvos Dec 17, 2025
458a928
small fixes
lkdvos Dec 17, 2025
cac1593
some more fixes
lkdvos Dec 18, 2025
4e66437
avoid unbound type parameters
lkdvos Jan 2, 2026
6c53e5f
remove unused code
lkdvos Jan 2, 2026
f127d76
include preparation in algorithms
lkdvos Jan 2, 2026
7c20b5e
small fixes
lkdvos Jan 2, 2026
b473e5e
convert to complex if necessary
lkdvos Jan 2, 2026
f28c7bd
avoid missing converters
lkdvos Jan 2, 2026
36f0880
more rework of convert to complex
lkdvos Jan 2, 2026
2730908
include TDVP for operator prep
lkdvos Jan 3, 2026
de634e6
small changes to buffer
lkdvos Jan 3, 2026
bc319cc
fix projection for columns
lkdvos Jan 15, 2026
32ccfb0
use projection where applicable, hamiltonian where not
lkdvos Jan 15, 2026
2e38a93
replace allocator with TensorOperations implementation
lkdvos Feb 26, 2026
c06f64d
updates, possibly working now?
lkdvos Feb 27, 2026
44745a2
fix projection operators
lkdvos Feb 27, 2026
5308124
update benchmarks
lkdvos Feb 27, 2026
f9c43c2
fixes for type stability
lkdvos Mar 1, 2026
4be4667
test for inferred
lkdvos Mar 1, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ Manifest.toml
.vscode
.DS_Store
**/dev/
benchmark/results
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ RecipesBase = "1.1"
TensorKit = "0.16.3"
TensorKitManifolds = "0.7"
TensorKitTensors = "0.2"
TensorOperations = "5"
TensorOperations = "5.5"
Test = "1"
TestExtras = "0.3"
VectorInterface = "0.2, 0.3, 0.4, 0.5"
Expand Down
2 changes: 2 additions & 0 deletions benchmark/LocalPreferences.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[TensorOperations]
precompile_workload = true
59 changes: 59 additions & 0 deletions benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
module MPSKitBenchmarks

using BenchmarkTools
using MPSKit
using TOML

include("utils/BenchUtils.jl")

BenchmarkTools.DEFAULT_PARAMETERS.seconds = 20.0
BenchmarkTools.DEFAULT_PARAMETERS.samples = 10000
BenchmarkTools.DEFAULT_PARAMETERS.time_tolerance = 0.15
BenchmarkTools.DEFAULT_PARAMETERS.memory_tolerance = 0.01

const PARAMS_PATH = joinpath(@__DIR__, "etc", "params.json")
const SUITE = BenchmarkGroup()
const MODULES = Dict{String, Symbol}(
"derivatives" => :DerivativesBenchmarks
)

include("derivatives/DerivativesBenchmarks.jl")

load!(id::AbstractString; kwargs...) = load!(SUITE, id; kwargs...)

function load!(group::BenchmarkGroup, id::AbstractString; tune::Bool = false)
modsym = MODULES[id]
modpath = joinpath(dirname(@__FILE__), id, "$(modsym).jl")
Core.eval(@__MODULE__, :(include($modpath)))
mod = Core.eval(@__MODULE__, modsym)
modsuite = @invokelatest getglobal(mod, :SUITE)
group[id] = modsuite
if tune
results = BenchmarkTools.load(PARAMS_PATH)[1]
haskey(results, id) && loadparams!(modsuite, results[id], :evals)
end
return group
end

loadall!(; kwargs...) = loadall!(SUITE; kwargs...)

function loadall!(group::BenchmarkGroup; verbose::Bool = true, tune::Bool = false)
for id in keys(MODULES)
if verbose
print("loading group $(repr(id))... ")
time = @elapsed load!(group, id, tune = false)
println("done (took $time seconds)")
else
load!(group, id; tune = false)
end
end
if tune
results = BenchmarkTools.load(PARAMS_PATH)[1]
for (id, suite) in group
haskey(results, id) && loadparams!(suite, results[id], :evals)
end
end
return group
end

end
101 changes: 101 additions & 0 deletions benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
struct AC2Spec{S <: ElementarySpace} # <: BenchmarkSpec
physicalspaces::NTuple{2, S}
mps_virtualspaces::NTuple{3, S}
mpo_virtualspaces::NTuple{3, SumSpace{S}}
nonzero_keys::NTuple{2, Vector{Tuple{Int, Int}}}
end

function AC2Spec(mps, mpo; site = length(mps) ÷ 2)
physicalspaces = (physicalspace(mps, site), physicalspace(mps, site + 1))
mps_virtualspaces = (left_virtualspace(mps, site), right_virtualspace(mps, site), right_virtualspace(mps, site + 1))
mpo_virtualspaces = (left_virtualspace(mpo, site), right_virtualspace(mpo, site), right_virtualspace(mpo, site + 1))
ks = (
map(x -> (x.I[1], x.I[4]), nonzero_keys(mpo[site])),
map(x -> (x.I[1], x.I[4]), nonzero_keys(mpo[site])),
)
return AC2Spec(physicalspaces, mps_virtualspaces, mpo_virtualspaces, ks)
end

benchname(spec::AC2Spec) = dim(spec.mps_virtualspaces[1]), dim(spec.mpo_virtualspaces[1])

# Benchmarks
# ----------

function prepare_state(spec::AC2Spec{S}; T::Type = Float64) where {S}
GL = randn(T, spec.mps_virtualspaces[1] ⊗ spec.mpo_virtualspaces[1]' ← spec.mps_virtualspaces[1])
GR = randn(T, spec.mps_virtualspaces[3] ⊗ spec.mpo_virtualspaces[3] ← spec.mps_virtualspaces[3])

W1 = MPSKit.JordanMPOTensor{T, S}(undef, spec.mpo_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.physicalspaces[1] ⊗ spec.mpo_virtualspaces[2])
for (r, c) in spec.nonzero_keys[1]
r == c == 1 && continue
r == size(W1, 1) && c == size(W1, 4) && continue
W1[r, 1, 1, c] = randn!(W1[r, 1, 1, c])
end
W2 = MPSKit.JordanMPOTensor{T, S}(undef, spec.mpo_virtualspaces[2] ⊗ spec.physicalspaces[2] ← spec.physicalspaces[2] ⊗ spec.mpo_virtualspaces[3])
for (r, c) in spec.nonzero_keys[2]
r == c == 1 && continue
r == size(W2, 1) && c == size(W2, 4) && continue
W2[r, 1, 1, c] = randn!(W2[r, 1, 1, c])
end
H = InfiniteMPOHamiltonian(PeriodicVector([W1, W2]))

A = PeriodicVector(
[
randn(T, spec.mps_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[2]),
randn(T, spec.mps_virtualspaces[2] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[3]),
]
)
C = PeriodicVector(
[
randn(T, spec.mps_virtualspaces[2] ← spec.mps_virtualspaces[2]),
randn(T, spec.mps_virtualspaces[3] ← spec.mps_virtualspaces[3]),
]
)
psi = InfiniteMPS{eltype(A), eltype(C)}(A, A, C, A)

GLs, GRs = MPSKit.initialize_environments(psi, H, psi)
envs = MPSKit.InfiniteEnvironments(GLs, GRs)

return psi, H, envs
end

function contraction_benchmark(spec::AC2Spec; T::Type = Float64)
psi, H, envs = prepare_state(spec; T)
H_eff = MPSKit.AC2_hamiltonian(1, psi, H, psi, envs)
V = spec.mps_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[3] ⊗ spec.physicalspaces[2]'
return @benchmarkable $H_eff * x setup = x = randn($T, $V)
end

function preparation_benchmark(spec::AC2Spec; T::Type = Float64)
psi, H, envs = prepare_state(spec; T)
return @benchmarkable MPSKit.AC2_hamiltonian(1, $psi, $H, $psi, $envs)
end

# Converters
# ----------
function tomlify(spec::AC2Spec)
return Dict(
"physicalspaces" => collect(tomlify.(spec.physicalspaces)),
"mps_virtualspaces" => collect(tomlify.(spec.mps_virtualspaces)),
"mpo_virtualspaces" => collect(tomlify.(spec.mpo_virtualspaces)),
"nonzero_keys" => collect(map(Base.Fix1(map, collect), spec.nonzero_keys))
)
end

function untomlify(::Type{AC2Spec}, x)
to_space = Base.Fix1(untomlify, VectorSpace)
physicalspaces = Tuple(map(to_space, x["physicalspaces"]))
mps_virtualspaces = Tuple(map(to_space, x["mps_virtualspaces"]))
mpo_virtualspaces = Tuple(map(to_space, x["mpo_virtualspaces"]))
nonzero_keys = Tuple(map(Base.Fix1(map, Tuple), x["nonzero_keys"]))
return AC2Spec(physicalspaces, mps_virtualspaces, mpo_virtualspaces, nonzero_keys)
end

function Base.convert(::Type{AC2Spec{S₁}}, spec::AC2Spec{S₂}) where {S₁, S₂}
return S₁ === S₂ ? spec : AC2Spec(
S₁.(spec.physicalspaces),
S₁.(spec.mps_virtualspaces),
SumSpace{S₁}.(spec.mpo_virtualspaces),
spec.nonzero_keys
)
end
44 changes: 44 additions & 0 deletions benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module DerivativesBenchmarks

export AC2Spec

using BenchmarkTools
using TOML
using TensorKit
using BlockTensorKit
using MPSKit
using ..BenchUtils
import ..BenchUtils: tomlify, untomlify

const SUITE = BenchmarkGroup()

const allparams = Dict(
"heisenberg_nn" => TOML.parsefile(joinpath(@__DIR__, "heisenberg_nn.toml")),
"heisenberg_nnn" => TOML.parsefile(joinpath(@__DIR__, "heisenberg_nnn.toml")),
"heisenberg_cylinder" => TOML.parsefile(joinpath(@__DIR__, "heisenberg_cylinder.toml")),
"heisenberg_coulomb" => TOML.parsefile(joinpath(@__DIR__, "heisenberg_coulomb.toml"))
)

include("AC2_benchmarks.jl")

T = Float64

suite_init = addgroup!(SUITE, "AC2_preparation")
suite_apply = addgroup!(SUITE, "AC2_contraction")

for (model, params) in allparams
g_prep = addgroup!(suite_init, model)
g_contract = addgroup!(suite_apply, model)
for (symmetry, specs) in params
g_prep_sym = addgroup!(g_prep, symmetry)
g_contract_sym = addgroup!(g_contract, symmetry)
for spec_dict in specs
spec = untomlify(AC2Spec, spec_dict)
name = benchname(spec)
g_contract_sym[name] = contraction_benchmark(spec; T)
g_prep_sym[name] = preparation_benchmark(spec; T)
end
end
end

end
Loading
Loading