From a73f7132d9a8cc672b159e128f50df2e878f3dfd Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sat, 1 Nov 2025 08:35:22 -0400 Subject: [PATCH 01/37] setup benchmarks --- .../MPSKitBenchmarks/MPSKitBenchmarks.jl | 55 +++++++++++++++++++ benchmark/Project.toml | 8 +++ 2 files changed, 63 insertions(+) create mode 100644 benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl create mode 100644 benchmark/Project.toml diff --git a/benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl b/benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl new file mode 100644 index 000000000..ff4a4e108 --- /dev/null +++ b/benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl @@ -0,0 +1,55 @@ +module MPSKitBenchmarks + +using BenchmarkTools +using MPSKit +using TOML + +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" => :Derivatives +) + +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 diff --git a/benchmark/Project.toml b/benchmark/Project.toml new file mode 100644 index 000000000..891d982fa --- /dev/null +++ b/benchmark/Project.toml @@ -0,0 +1,8 @@ +[deps] +BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +BlockTensorKit = "5f87ffc2-9cf1-4a46-8172-465d160bd8cd" +CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +MPSKit = "bb1c41ca-d63c-52ed-829e-0820dda26502" +MPSKitModels = "ca635005-6f8c-4cd1-b51d-8491250ef2ab" +TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +TensorKit = "07d1fe3e-3e46-537d-9eac-e9e13d0d4cec" From ecab865d490268d486b456af4a1f90d238ae5d85 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sat, 1 Nov 2025 08:36:27 -0400 Subject: [PATCH 02/37] add main entry point --- benchmark/benchmarks.jl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 benchmark/benchmarks.jl diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl new file mode 100644 index 000000000..1e89b2161 --- /dev/null +++ b/benchmark/benchmarks.jl @@ -0,0 +1,17 @@ +# Load benchmark code +include("MPSKitBenchmarks/MPSKitBenchmarks.jl") +const SUITE = MPSKitBenchmarks.SUITE + +# Populate benchmarks +# Detect if user supplied extra arguments to load only specific modules +# e.g. julia benchmarks.jl --modules=linalg,tensornetworks +modules_pattern = r"(?:--modules=)(\w+)" +arg_id = findfirst(contains(modules_pattern), ARGS) +if isnothing(arg_id) + MPSKitBenchmarks.loadall!() +else + modules = split(only(match(modules_pattern, ARGS[arg_id]).captures[1]), ",") + for m in modules + MPSKitBenchmarks.load!(m) + end +end From 1779d3d70bf7b2c187f09989e9b634d5f61b28ea Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sat, 1 Nov 2025 08:44:12 -0400 Subject: [PATCH 03/37] add Utility module --- benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl | 2 ++ benchmark/MPSKitBenchmarks/utils/BenchUtils.jl | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 benchmark/MPSKitBenchmarks/utils/BenchUtils.jl diff --git a/benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl b/benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl index ff4a4e108..079560584 100644 --- a/benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl +++ b/benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl @@ -4,6 +4,8 @@ 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 diff --git a/benchmark/MPSKitBenchmarks/utils/BenchUtils.jl b/benchmark/MPSKitBenchmarks/utils/BenchUtils.jl new file mode 100644 index 000000000..ab184d795 --- /dev/null +++ b/benchmark/MPSKitBenchmarks/utils/BenchUtils.jl @@ -0,0 +1,3 @@ +module BenchUtils + +end From 2511205a6703ea7aa9455869e36216209694062d Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sun, 2 Nov 2025 16:05:23 -0500 Subject: [PATCH 04/37] start setting up benchmark suite --- .../MPSKitBenchmarks/MPSKitBenchmarks.jl | 4 +- .../derivatives/AC2_benchmarks.jl | 85 +++++++++++++++++++ .../derivatives/DerivativesBenchmarks.jl | 17 ++++ .../MPSKitBenchmarks/utils/BenchUtils.jl | 24 ++++++ src/MPSKit.jl | 1 + src/algorithms/derivatives/derivatives.jl | 28 ++++++ .../derivatives/hamiltonian_derivatives.jl | 40 ++++----- src/algorithms/fixedpoint.jl | 26 +++--- 8 files changed, 194 insertions(+), 31 deletions(-) create mode 100644 benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl create mode 100644 benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl diff --git a/benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl b/benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl index 079560584..c70a01f70 100644 --- a/benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl +++ b/benchmark/MPSKitBenchmarks/MPSKitBenchmarks.jl @@ -14,9 +14,11 @@ BenchmarkTools.DEFAULT_PARAMETERS.memory_tolerance = 0.01 const PARAMS_PATH = joinpath(@__DIR__, "etc", "params.json") const SUITE = BenchmarkGroup() const MODULES = Dict{String, Symbol}( - "derivatives" => :Derivatives + "derivatives" => :DerivativesBenchmarks ) +include("derivatives/DerivativesBenchmarks.jl") + load!(id::AbstractString; kwargs...) = load!(SUITE, id; kwargs...) function load!(group::BenchmarkGroup, id::AbstractString; tune::Bool = false) diff --git a/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl b/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl new file mode 100644 index 000000000..8c9a602ff --- /dev/null +++ b/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl @@ -0,0 +1,85 @@ +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 + +# Benchmarks +# ---------- +function MPSKit.MPO_AC2_Hamiltonian(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 = 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 = 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 + + return MPSKit.MPO_AC2_Hamiltonian(GL, W1, W2, GR) +end + +function contraction_benchmark(spec::AC2Spec; T::Type = Float64) + AA = randn(T, spec.mps_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[3] ⊗ spec.physicalspaces[2]') + H_eff = MPSKit.MPO_AC2_Hamiltonian(spec; T) + H_prep, x_prep = MPSKit.prepare_operator!!(H_eff, AA) + init() = randn!(similar(x_prep)) + + return @benchmarkable $H_prep * x setup = (x = $init()) +end + +function preparation_benchmark(spec::AC2Spec; T::Type = Float64) + init() = randn(T, spec.mps_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[3] ⊗ spec.physicalspaces[2]') + H_eff = MPSKit.MPO_AC2_Hamiltonian(spec; T) + + return @benchmarkable begin + O′, x′ = MPSKit.prepare_operator!!($H_eff, x) + y = MPSKit.unprepare_operator!!(x′, O′, x) + end setup = (x = $init()) +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) + physicalspaces = Tuple(map(untomlify, x["physicalspaces"])) + mps_virtualspaces = Tuple(map(untomlify, x["mps_virtualspaces"])) + mpo_virtualspaces = Tuple(map(untomlify, x["mpo_virtualspaces"])) + nonzero_keys = Tuple(map(Base.Fix1(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 diff --git a/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl new file mode 100644 index 000000000..41d3b1941 --- /dev/null +++ b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl @@ -0,0 +1,17 @@ +module DerivativesBenchmarks + +export AC2Spec + +using BenchmarkTools +using TensorKit +using BlockTensorKit +using MPSKit +using ..BenchUtils +import ..BenchUtils: tomlify, untomlify + +const SUITE = BenchmarkGroup() + +include("AC2_benchmarks.jl") + + +end diff --git a/benchmark/MPSKitBenchmarks/utils/BenchUtils.jl b/benchmark/MPSKitBenchmarks/utils/BenchUtils.jl index ab184d795..c16f28ef1 100644 --- a/benchmark/MPSKitBenchmarks/utils/BenchUtils.jl +++ b/benchmark/MPSKitBenchmarks/utils/BenchUtils.jl @@ -1,3 +1,27 @@ module BenchUtils +export tomlify, untomlify + +using TensorKit +using BlockTensorKit +using TOML + +tomlify(x::VectorSpace) = string(x) +untomlify(::Type{<:VectorSpace}, x) = eval(Meta.parse(x)) + + +# Type piracy but oh well +TensorKit.ComplexSpace(V::ElementarySpace) = ComplexSpace(dim(V), isdual(V)) + +function TensorKit.U1Space(V::SU2Space) + dims = TensorKit.SectorDict{U1Irrep, Int}() + for c in sectors(V), m in (-c.j):(c.j) + u1 = U1Irrep(m) + dims[u1] = get(dims, u1, 0) + 1 + end + return U1Space(dims; dual = isdual(V)) +end + +BlockTensorKit.SumSpace{S}(V::SumSpace) where {S} = SumSpace(map(S, V.spaces)) + end diff --git a/src/MPSKit.jl b/src/MPSKit.jl index cd465643d..7b18a31c6 100644 --- a/src/MPSKit.jl +++ b/src/MPSKit.jl @@ -65,6 +65,7 @@ using MatrixAlgebraKit: TruncationStrategy, PolarViaSVD, LAPACK_SVDAlgorithm using BlockTensorKit using BlockTensorKit: TensorMapSumSpace using TensorOperations +using TensorOperations: AbstractBackend, DefaultBackend, DefaultAllocator using KrylovKit using KrylovKit: KrylovAlgorithm using OptimKit diff --git a/src/algorithms/derivatives/derivatives.jl b/src/algorithms/derivatives/derivatives.jl index 1f3980e37..1e65c3f15 100644 --- a/src/algorithms/derivatives/derivatives.jl +++ b/src/algorithms/derivatives/derivatives.jl @@ -213,3 +213,31 @@ const DerivativeOrMultiplied{D <: DerivativeOperator} = Union{MultipliedOperator (x::LazySum{<:DerivativeOrMultiplied})(y, t::Number) = sum(O -> O(y, t), x) (x::LazySum{<:DerivativeOrMultiplied})(y) = sum(O -> O(y), x) Base.:*(h::LazySum{<:Union{DerivativeOrMultiplied}}, v) = h(v) + +# Operator preparation +# -------------------- +""" + prepare_operator!!(O, x, [backend], [allocator]) -> O′, x′ + +Given an operator and vector, try to construct a more efficient representation of that operator for repeated application. +This should always be used in conjunction with [`unprepare_operator!!`](@ref). +""" +function prepare_operator!!( + O, x, + backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() + ) + return O, x +end + +""" + unprepare_operator!!(y, O, x, [backend], [allocator]) -> y′ + +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. +This should always be used in conjunction with [`prepare_operator!!`](@ref). +""" +function unprepare_operator!!( + y, O, x, + backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() + ) + return y +end diff --git a/src/algorithms/derivatives/hamiltonian_derivatives.jl b/src/algorithms/derivatives/hamiltonian_derivatives.jl index b922205f8..2b4f67235 100644 --- a/src/algorithms/derivatives/hamiltonian_derivatives.jl +++ b/src/algorithms/derivatives/hamiltonian_derivatives.jl @@ -75,13 +75,13 @@ const _HAM_MPS_TYPES = Union{ InfiniteMPS{<:MPSTensor}, } -function AC_hamiltonian( - site::Int, below::_HAM_MPS_TYPES, operator::MPOHamiltonian{<:JordanMPOTensor}, - above::_HAM_MPS_TYPES, envs +function prepare_operator!!( + O::MPO_AC_Hamiltonian{<:Any, <:JordanMPOTensor, <:Any}, x::MPSTensor, + backend::AbstractBackend, allocator ) - GL = leftenv(envs, site, below) - GR = rightenv(envs, site, below) - W = operator[site] + GL = O.leftenv + W = only(O.operators) + GR = O.rightenv # starting if nonzero_length(W.C) > 0 @@ -117,7 +117,7 @@ function AC_hamiltonian( end # not_started - if isfinite(operator) && site == length(operator) + if size(W, 4) == 1 not_started = missing elseif !ismissing(starting) I = id(storagetype(GR[1]), physicalspace(W)) @@ -128,7 +128,7 @@ function AC_hamiltonian( end # finished - if isfinite(operator) && site == 1 + if size(W, 1) == 1 finished = missing elseif !ismissing(ending) I = id(storagetype(GL[end]), physicalspace(W)) @@ -142,19 +142,20 @@ function AC_hamiltonian( A = W.A continuing = (GL[2:(end - 1)], A, GR[2:(end - 1)]) - return JordanMPO_AC_Hamiltonian( + O′ = JordanMPO_AC_Hamiltonian( onsite, not_started, finished, starting, ending, continuing ) + + return O′, x end -function AC2_hamiltonian( - site::Int, below::_HAM_MPS_TYPES, operator::MPOHamiltonian{<:JordanMPOTensor}, - above::_HAM_MPS_TYPES, envs +function prepare_operator!!( + O::MPO_AC2_Hamiltonian{<:Any, <:JordanMPOTensor, <:JordanMPOTensor, <:Any}, x::MPOTensor, + backend::AbstractBackend, allocator ) - GL = leftenv(envs, site, below) - GR = rightenv(envs, site + 1, below) - W1 = operator[site] - W2 = operator[site + 1] + GL = O.leftenv + W1, W2 = O.operators + GR = O.rightenv # starting left - continuing right if nonzero_length(W1.C) > 0 && nonzero_length(W2.A) > 0 @@ -256,7 +257,7 @@ function AC2_hamiltonian( end # finished - if isfinite(operator) && site + 1 == length(operator) + if size(W2, 4) == 1 II = missing elseif !ismissing(IC) I = id(storagetype(GR[1]), physicalspace(W2)) @@ -271,7 +272,7 @@ function AC2_hamiltonian( end # unstarted - if isfinite(operator) && site == 1 + if size(W1, 1) == 1 EE = missing elseif !ismissing(BE) I = id(storagetype(GL[end]), physicalspace(W1)) @@ -289,7 +290,8 @@ function AC2_hamiltonian( # TODO: MPODerivativeOperator code reuse + optimization AA = (GL[2:(end - 1)], W1.A, W2.A, GR[2:(end - 1)]) - return JordanMPO_AC2_Hamiltonian(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) + O′ = JordanMPO_AC2_Hamiltonian(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) + return O′, x end # Actions diff --git a/src/algorithms/fixedpoint.jl b/src/algorithms/fixedpoint.jl index 188c65559..9846624e4 100644 --- a/src/algorithms/fixedpoint.jl +++ b/src/algorithms/fixedpoint.jl @@ -8,26 +8,30 @@ Compute the fixed point of a linear operator `A` using the specified eigensolver fixedpoint is assumed to be unique. """ function fixedpoint(A, x₀, which::Symbol, alg::Lanczos) - vals, vecs, info = eigsolve(A, x₀, 1, which, alg) + A′, x₀′ = prepare_operator!!(A, x₀) + vals, vecs, info = eigsolve(A′, x₀′, 1, which, alg) - if info.converged == 0 + info.converged == 0 && @warnv 1 "fixed point not converged after $(info.numiter) iterations: normres = $(info.normres[1])" - end - return vals[1], vecs[1] + λ = vals[1] + v = unprepare_operator!!(vecs[1], A′, x₀) + + return λ, v end function fixedpoint(A, x₀, which::Symbol, alg::Arnoldi) - TT, vecs, vals, info = schursolve(A, x₀, 1, which, alg) + A′, x₀′ = prepare_operator!!(A, x₀) + TT, vecs, vals, info = schursolve(A′, x₀′, 1, which, alg) - if info.converged == 0 + info.converged == 0 && @warnv 1 "fixed point not converged after $(info.numiter) iterations: normres = $(info.normres[1])" - end - if size(TT, 2) > 1 && TT[2, 1] != 0 - @warnv 1 "non-unique fixed point detected" - end + size(TT, 2) > 1 && TT[2, 1] != 0 && @warnv 1 "non-unique fixed point detected" + + λ = vals[1] + v = unprepare_operator!!(vecs[1], A′, x₀) - return vals[1], vecs[1] + return λ, v end function fixedpoint(A, x₀, which::Symbol; kwargs...) From 337a252bcd4efd69ae6fa64aa546cf481beb6187 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sun, 2 Nov 2025 17:11:31 -0500 Subject: [PATCH 05/37] add heisenberg script --- .../scripts/setup_heisenberg.jl | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl diff --git a/benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl b/benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl new file mode 100644 index 000000000..58031ae1d --- /dev/null +++ b/benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl @@ -0,0 +1,81 @@ +using TensorKit +using MPSKit +using MPSKit.BlockTensorKit: nonzero_keys +using MPSKit.BlockTensorKit +using MPSKitModels +using TOML + +include(joinpath(@__DIR__, "..", "MPSKitBenchmarks.jl")) +using .MPSKitBenchmarks +# MPSKitBenchmarks.load!("derivatives") +using .MPSKitBenchmarks.DerivativesBenchmarks: AC2Spec +using .MPSKitBenchmarks.BenchUtils: tomlify + +# Utility functions +# ---------------- +# setup "product state" -> ⨂^N |↑↓ - ↓↑⟩ +function initial_state(H) + @assert iseven(length(H)) + @assert allequal(physicalspace(H)) + + pspace = physicalspace(H, 1) + A = rand(oneunit(pspace) ⊗ pspace^2 ← oneunit(pspace)) + As = MPSKit.decompose_localmps(A) + return FiniteMPS(repeat(As, length(H) ÷ 2)) +end + +function generate_spaces(H, alg; D_min = 2, D_steps = 5) + # compute maximal spaces + psi_init = initial_state(H) + psi, = find_groundstate(psi_init, H, alg) + + D_max = maximum(dim, left_virtualspace(psi)) + Ds = round.(Int, logrange(D_min, D_max, D_steps)) + + return map(Ds) do D + mps = changebonds(psi, SvdCut(; trscheme = truncrank(D))) + return AC2Spec(mps, H) + end +end + +# Parameters +# ---------- +T = Float64 +spin = 1 + +D_max = 10_000 + +D_steps = 10 +D_min = 3 + + +# FiniteChain +# ----------- +L = 100 +lattice = FiniteChain(L) + +symmetry = SU2Irrep +alg = DMRG2(; + maxiter = 10, tol = 1.0e-12, + alg_eigsolve = (; tol = 1.0e-5, dynamic_tols = false, maxiter = 3), + trscheme = truncrank(D_max) +) + +H = heisenberg_XXX(T, symmetry, lattice; spin); +specs_su2 = generate_spaces(H, alg; D_min, D_steps) + +specs_triv = filter!(convert.(AC2Spec{ComplexSpace}, specs_su2)) do spec + dim(spec.mps_virtualspaces[1]) < 1000 +end + +specs_u1 = filter!(convert.(AC2Spec{U1Space}, specs_su2)) do spec + dim(spec.mps_virtualspaces[1]) < 5000 +end + +specs = vcat(specs_triv, specs_u1, specs_su2) + +output_file = joinpath(@__DIR__, "heisenberg_NN_specs.toml") +open(output_file, "w") do io + TOML.print(io, Dict("specs" => tomlify.(specs))) +end +@info("Spaces written to $output_file") From 4488368279e06ddfa809296998295af234d4ce0a Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sun, 2 Nov 2025 17:28:54 -0500 Subject: [PATCH 06/37] add test suites --- .../derivatives/DerivativesBenchmarks.jl | 21 +++ .../derivatives/heisenberg_NN.toml | 150 ++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 benchmark/MPSKitBenchmarks/derivatives/heisenberg_NN.toml diff --git a/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl index 41d3b1941..0dd7cccca 100644 --- a/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl +++ b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl @@ -3,6 +3,7 @@ module DerivativesBenchmarks export AC2Spec using BenchmarkTools +using TOML using TensorKit using BlockTensorKit using MPSKit @@ -11,7 +12,27 @@ import ..BenchUtils: tomlify, untomlify const SUITE = BenchmarkGroup() +const allparams = Dict( + "heisenberg_NN" => TOML.parsefile(joinpath(@__DIR__, "heisenberg_NN_specs.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) + specs = untomlify.(AC2Spec, params["specs"]) + + for spec in specs + name = benchname(spec) + g_prep[name] = preparation_benchmark(spec; T) + g_contract[name] = contraction_benchmark(spec; T) + end +end end diff --git a/benchmark/MPSKitBenchmarks/derivatives/heisenberg_NN.toml b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_NN.toml new file mode 100644 index 000000000..0d96ee0c4 --- /dev/null +++ b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_NN.toml @@ -0,0 +1,150 @@ +[[specs]] +mps_virtualspaces = ["ℂ^1", "ℂ^3", "ℂ^1"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[specs]] +mps_virtualspaces = ["ℂ^4", "ℂ^4", "ℂ^4"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[specs]] +mps_virtualspaces = ["ℂ^4", "ℂ^4", "ℂ^4"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[specs]] +mps_virtualspaces = ["ℂ^9", "ℂ^7", "ℂ^9"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[specs]] +mps_virtualspaces = ["ℂ^12", "ℂ^12", "ℂ^12"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[specs]] +mps_virtualspaces = ["ℂ^21", "ℂ^21", "ℂ^21"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[specs]] +mps_virtualspaces = ["ℂ^29", "ℂ^24", "ℂ^29"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[specs]] +mps_virtualspaces = ["ℂ^44", "ℂ^44", "ℂ^44"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[specs]] +mps_virtualspaces = ["ℂ^65", "ℂ^63", "ℂ^65"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[specs]] +mps_virtualspaces = ["ℂ^81", "ℂ^96", "ℂ^81"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[specs]] +mps_virtualspaces = ["Rep[U₁](0 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[SU₂](0 => 1)", "Rep[SU₂](1 => 1)", "Rep[SU₂](0 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 1, 2 => 1)", "Rep[SU₂](0 => 1, 1 => 2)", "Rep[SU₂](0 => 1, 1 => 1, 2 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 2, 2 => 1)", "Rep[SU₂](0 => 1, 1 => 2, 2 => 1)", "Rep[SU₂](0 => 1, 1 => 2, 2 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 3, 2 => 2)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 2)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 2)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 4, 2 => 3)", "Rep[SU₂](0 => 2, 1 => 4, 2 => 2)", "Rep[SU₂](0 => 2, 1 => 4, 2 => 3)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)", "Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)", "Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 2)", "Rep[SU₂](0 => 3, 1 => 7, 2 => 5, 3 => 2)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 2)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[[specs]] +mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)", "Rep[SU₂](0 => 5, 1 => 10, 2 => 8, 3 => 3)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] From 8be1a08cf30f9ed190f97b3c2b932ab3bcc27dd2 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sun, 2 Nov 2025 18:12:26 -0500 Subject: [PATCH 07/37] small updates --- .../derivatives/AC2_benchmarks.jl | 15 ++- .../derivatives/DerivativesBenchmarks.jl | 17 +-- .../derivatives/heisenberg_NN.toml | 106 +++++++++--------- .../scripts/setup_heisenberg.jl | 17 ++- 4 files changed, 85 insertions(+), 70 deletions(-) diff --git a/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl b/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl index 8c9a602ff..f302a0435 100644 --- a/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl +++ b/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl @@ -16,18 +16,20 @@ function AC2Spec(mps, mpo; site = length(mps) ÷ 2) return AC2Spec(physicalspaces, mps_virtualspaces, mpo_virtualspaces, ks) end +benchname(spec::AC2Spec) = dim(spec.mps_virtualspaces[1]), dim(spec.mpo_virtualspaces[1]) + # Benchmarks # ---------- function MPSKit.MPO_AC2_Hamiltonian(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 = JordanMPOTensor{T, S}(undef, spec.mpo_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.physicalspaces[1] ⊗ spec.mpo_virtualspaces[2]) + 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 = JordanMPOTensor{T, S}(undef, spec.mpo_virtualspaces[2] ⊗ spec.physicalspaces[2] ← spec.physicalspaces[2] ⊗ spec.mpo_virtualspaces[3]) + 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 @@ -68,10 +70,11 @@ function tomlify(spec::AC2Spec) end function untomlify(::Type{AC2Spec}, x) - physicalspaces = Tuple(map(untomlify, x["physicalspaces"])) - mps_virtualspaces = Tuple(map(untomlify, x["mps_virtualspaces"])) - mpo_virtualspaces = Tuple(map(untomlify, x["mpo_virtualspaces"])) - nonzero_keys = Tuple(map(Base.Fix1(map, Base.Fix1(map, Tuple)), x["nonzero_keys"])) + 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 diff --git a/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl index 0dd7cccca..017e08d9f 100644 --- a/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl +++ b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl @@ -13,7 +13,7 @@ import ..BenchUtils: tomlify, untomlify const SUITE = BenchmarkGroup() const allparams = Dict( - "heisenberg_NN" => TOML.parsefile(joinpath(@__DIR__, "heisenberg_NN_specs.toml")) + "heisenberg_NN" => TOML.parsefile(joinpath(@__DIR__, "heisenberg_NN.toml")) ) include("AC2_benchmarks.jl") @@ -26,12 +26,15 @@ suite_apply = addgroup!(SUITE, "AC2_contraction") for (model, params) in allparams g_prep = addgroup!(suite_init, model) g_contract = addgroup!(suite_apply, model) - specs = untomlify.(AC2Spec, params["specs"]) - - for spec in specs - name = benchname(spec) - g_prep[name] = preparation_benchmark(spec; T) - g_contract[name] = contraction_benchmark(spec; T) + 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_prep_sym[name] = preparation_benchmark(spec; T) + g_contract_sym[name] = contraction_benchmark(spec; T) + end end end diff --git a/benchmark/MPSKitBenchmarks/derivatives/heisenberg_NN.toml b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_NN.toml index 0d96ee0c4..ad1412195 100644 --- a/benchmark/MPSKitBenchmarks/derivatives/heisenberg_NN.toml +++ b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_NN.toml @@ -1,150 +1,152 @@ -[[specs]] +[[Trivial]] mps_virtualspaces = ["ℂ^1", "ℂ^3", "ℂ^1"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] -[[specs]] +[[Trivial]] mps_virtualspaces = ["ℂ^4", "ℂ^4", "ℂ^4"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] -[[specs]] -mps_virtualspaces = ["ℂ^4", "ℂ^4", "ℂ^4"] +[[Trivial]] +mps_virtualspaces = ["ℂ^4", "ℂ^7", "ℂ^4"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] -[[specs]] -mps_virtualspaces = ["ℂ^9", "ℂ^7", "ℂ^9"] +[[Trivial]] +mps_virtualspaces = ["ℂ^12", "ℂ^12", "ℂ^12"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] -[[specs]] -mps_virtualspaces = ["ℂ^12", "ℂ^12", "ℂ^12"] +[[Trivial]] +mps_virtualspaces = ["ℂ^21", "ℂ^21", "ℂ^21"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] -[[specs]] -mps_virtualspaces = ["ℂ^21", "ℂ^21", "ℂ^21"] +[[Trivial]] +mps_virtualspaces = ["ℂ^29", "ℂ^31", "ℂ^29"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] -[[specs]] -mps_virtualspaces = ["ℂ^29", "ℂ^24", "ℂ^29"] +[[Trivial]] +mps_virtualspaces = ["ℂ^53", "ℂ^56", "ℂ^53"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] -[[specs]] -mps_virtualspaces = ["ℂ^44", "ℂ^44", "ℂ^44"] +[[Trivial]] +mps_virtualspaces = ["ℂ^81", "ℂ^88", "ℂ^81"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] -[[specs]] -mps_virtualspaces = ["ℂ^65", "ℂ^63", "ℂ^65"] +[[Trivial]] +mps_virtualspaces = ["ℂ^81", "ℂ^148", "ℂ^81"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] -[[specs]] -mps_virtualspaces = ["ℂ^81", "ℂ^96", "ℂ^81"] +[[Trivial]] +mps_virtualspaces = ["ℂ^81", "ℂ^243", "ℂ^81"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] -[[specs]] + +[["Irrep[U₁]"]] mps_virtualspaces = ["Rep[U₁](0 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] -[[specs]] +[["Irrep[U₁]"]] mps_virtualspaces = ["Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] -[[specs]] +[["Irrep[U₁]"]] mps_virtualspaces = ["Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] -[[specs]] +[["Irrep[U₁]"]] mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)", "Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)", "Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)", "Rep[U₁](0 => 6, 1 => 5, -1 => 5, 2 => 4, -2 => 4, 3 => 3, -3 => 3, 4 => 2, -4 => 2, 5 => 1, -5 => 1)", "Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] -[[specs]] + +[["Irrep[SU₂]"]] mps_virtualspaces = ["Rep[SU₂](0 => 1)", "Rep[SU₂](1 => 1)", "Rep[SU₂](0 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] -[[specs]] +[["Irrep[SU₂]"]] mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 2)", "Rep[SU₂](0 => 1, 1 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 1, 2 => 1)", "Rep[SU₂](0 => 1, 1 => 2)", "Rep[SU₂](0 => 1, 1 => 1, 2 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 2, 2 => 1)", "Rep[SU₂](0 => 1, 1 => 2, 2 => 1)", "Rep[SU₂](0 => 1, 1 => 2, 2 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 2, 2 => 1)", "Rep[SU₂](0 => 1, 1 => 2, 2 => 1)", "Rep[SU₂](0 => 1, 1 => 2, 2 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 3, 2 => 2)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 2)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 2)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 3, 2 => 2)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 2)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 2)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 4, 2 => 3)", "Rep[SU₂](0 => 2, 1 => 4, 2 => 2, 3 => 1)", "Rep[SU₂](0 => 2, 1 => 4, 2 => 3)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 4, 2 => 3)", "Rep[SU₂](0 => 2, 1 => 4, 2 => 2)", "Rep[SU₂](0 => 2, 1 => 4, 2 => 3)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 5, 3 => 1)", "Rep[SU₂](0 => 3, 1 => 7, 2 => 5, 3 => 1)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 5, 3 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)", "Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)", "Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)", "Rep[SU₂](0 => 4, 1 => 10, 2 => 8, 3 => 2)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 2)", "Rep[SU₂](0 => 3, 1 => 7, 2 => 5, 3 => 2)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 2)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)", "Rep[SU₂](0 => 6, 1 => 12, 2 => 11, 3 => 6, 4 => 1)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] -[[specs]] -mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)", "Rep[SU₂](0 => 5, 1 => 10, 2 => 8, 3 => 3)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)", "Rep[SU₂](0 => 6, 1 => 15, 2 => 15, 3 => 10, 4 => 4, 5 => 1)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] diff --git a/benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl b/benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl index 58031ae1d..9842959d5 100644 --- a/benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl +++ b/benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl @@ -1,7 +1,8 @@ using TensorKit +using TensorKit: type_repr using MPSKit -using MPSKit.BlockTensorKit: nonzero_keys -using MPSKit.BlockTensorKit +using BlockTensorKit +using BlockTensorKit: nonzero_keys using MPSKitModels using TOML @@ -51,7 +52,7 @@ D_min = 3 # FiniteChain # ----------- -L = 100 +L = 10 lattice = FiniteChain(L) symmetry = SU2Irrep @@ -74,8 +75,14 @@ end specs = vcat(specs_triv, specs_u1, specs_su2) -output_file = joinpath(@__DIR__, "heisenberg_NN_specs.toml") +output_file = joinpath(@__DIR__, "..", "derivatives", "heisenberg_NN.toml") open(output_file, "w") do io - TOML.print(io, Dict("specs" => tomlify.(specs))) + TOML.print( + io, Dict( + type_repr(Trivial) => tomlify.(specs_triv), + type_repr(U1Irrep) => tomlify.(specs_u1), + type_repr(SU2Irrep) => tomlify.(specs_su2) + ) + ) end @info("Spaces written to $output_file") From f4beed4c7a3672d1fec119e98b193ca257acf97d Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Mon, 3 Nov 2025 07:25:07 -0500 Subject: [PATCH 08/37] update scripts --- .../derivatives/DerivativesBenchmarks.jl | 5 +- .../derivatives/heisenberg_coulomb.toml | 132 ++++++++++++++++++ .../derivatives/heisenberg_cylinder.toml | 132 ++++++++++++++++++ ...{heisenberg_NN.toml => heisenberg_nn.toml} | 72 ++++------ .../derivatives/heisenberg_nnn.toml | 132 ++++++++++++++++++ .../scripts/setup_heisenberg.jl | 129 ++++++++++++++++- .../MPSKitBenchmarks/utils/BenchUtils.jl | 4 +- 7 files changed, 552 insertions(+), 54 deletions(-) create mode 100644 benchmark/MPSKitBenchmarks/derivatives/heisenberg_coulomb.toml create mode 100644 benchmark/MPSKitBenchmarks/derivatives/heisenberg_cylinder.toml rename benchmark/MPSKitBenchmarks/derivatives/{heisenberg_NN.toml => heisenberg_nn.toml} (64%) create mode 100644 benchmark/MPSKitBenchmarks/derivatives/heisenberg_nnn.toml diff --git a/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl index 017e08d9f..db1cf8ecb 100644 --- a/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl +++ b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl @@ -13,7 +13,10 @@ import ..BenchUtils: tomlify, untomlify const SUITE = BenchmarkGroup() const allparams = Dict( - "heisenberg_NN" => TOML.parsefile(joinpath(@__DIR__, "heisenberg_NN.toml")) + "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") diff --git a/benchmark/MPSKitBenchmarks/derivatives/heisenberg_coulomb.toml b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_coulomb.toml new file mode 100644 index 000000000..0a945aced --- /dev/null +++ b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_coulomb.toml @@ -0,0 +1,132 @@ +[[Trivial]] +mps_virtualspaces = ["ℂ^1", "ℂ^3", "ℂ^1"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^4", "ℂ^4", "ℂ^4"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^7", "ℂ^7", "ℂ^7"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^19", "ℂ^19", "ℂ^19"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^40", "ℂ^40", "ℂ^40"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^76", "ℂ^76", "ℂ^76"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^140", "ℂ^143", "ℂ^140"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^272", "ℂ^274", "ℂ^272"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^498 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] + +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 7, 1 => 5, -1 => 5, 2 => 1, -2 => 1)", "Rep[U₁](0 => 7, 1 => 5, -1 => 5, 2 => 1, -2 => 1)", "Rep[U₁](0 => 7, 1 => 5, -1 => 5, 2 => 1, -2 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 14, 1 => 10, -1 => 10, 2 => 3, -2 => 3)", "Rep[U₁](0 => 14, 1 => 10, -1 => 10, 2 => 3, -2 => 3)", "Rep[U₁](0 => 14, 1 => 10, -1 => 10, 2 => 3, -2 => 3)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 24, 1 => 18, -1 => 18, 2 => 7, -2 => 7, 3 => 1, -3 => 1)", "Rep[U₁](0 => 24, 1 => 18, -1 => 18, 2 => 7, -2 => 7, 3 => 1, -3 => 1)", "Rep[U₁](0 => 24, 1 => 18, -1 => 18, 2 => 7, -2 => 7, 3 => 1, -3 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 42, 1 => 32, -1 => 32, 2 => 14, -2 => 14, 3 => 3, -3 => 3)", "Rep[U₁](0 => 43, 1 => 33, -1 => 33, 2 => 14, -2 => 14, 3 => 3, -3 => 3)", "Rep[U₁](0 => 42, 1 => 32, -1 => 32, 2 => 14, -2 => 14, 3 => 3, -3 => 3)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 80, 1 => 62, -1 => 62, 2 => 28, -2 => 28, 3 => 6, -3 => 6)", "Rep[U₁](0 => 80, 1 => 63, -1 => 63, 2 => 28, -2 => 28, 3 => 6, -3 => 6)", "Rep[U₁](0 => 80, 1 => 62, -1 => 62, 2 => 28, -2 => 28, 3 => 6, -3 => 6)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>166, 1=>166, -1=>166) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] + +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 1)", "Rep[SU₂](1 => 1)", "Rep[SU₂](0 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 2)", "Rep[SU₂](0 => 1, 1 => 2)", "Rep[SU₂](0 => 1, 1 => 2)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 4, 2 => 1)", "Rep[SU₂](0 => 2, 1 => 4, 2 => 1)", "Rep[SU₂](0 => 2, 1 => 4, 2 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 4, 1 => 7, 2 => 3)", "Rep[SU₂](0 => 4, 1 => 7, 2 => 3)", "Rep[SU₂](0 => 4, 1 => 7, 2 => 3)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 6, 1 => 11, 2 => 6, 3 => 1)", "Rep[SU₂](0 => 6, 1 => 11, 2 => 6, 3 => 1)", "Rep[SU₂](0 => 6, 1 => 11, 2 => 6, 3 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 10, 1 => 18, 2 => 11, 3 => 3)", "Rep[SU₂](0 => 10, 1 => 19, 2 => 11, 3 => 3)", "Rep[SU₂](0 => 10, 1 => 18, 2 => 11, 3 => 3)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 18, 1 => 34, 2 => 22, 3 => 6)", "Rep[SU₂](0 => 17, 1 => 35, 2 => 22, 3 => 6)", "Rep[SU₂](0 => 18, 1 => 34, 2 => 22, 3 => 6)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 28, 1 => 58, 2 => 43, 3 => 14, 4 => 1)", "Rep[SU₂](0 => 30, 1 => 59, 2 => 43, 3 => 13, 4 => 1)", "Rep[SU₂](0 => 28, 1 => 58, 2 => 43, 3 => 14, 4 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 41, 1 => 84, 2 => 64, 3 => 26, 4 => 11, 5 => 6, 6 => 3)", "Rep[SU₂](0 => 34, 1 => 71, 2 => 63, 3 => 30, 4 => 12, 5 => 6, 6 => 3, 7 => 1)", "Rep[SU₂](0 => 40, 1 => 83, 2 => 62, 3 => 29, 4 => 12, 5 => 7, 6 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]], [[1, 1], [3, 3], [2, 2], [2, 3], [1, 2], [1, 3]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>166) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] diff --git a/benchmark/MPSKitBenchmarks/derivatives/heisenberg_cylinder.toml b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_cylinder.toml new file mode 100644 index 000000000..bd1e55b79 --- /dev/null +++ b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_cylinder.toml @@ -0,0 +1,132 @@ +[[Trivial]] +mps_virtualspaces = ["ℂ^3", "ℂ^1", "ℂ^3"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1 ⊞ ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^3", "ℂ^4", "ℂ^3"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1 ⊞ ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^16", "ℂ^12", "ℂ^16"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1 ⊞ ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^43", "ℂ^41", "ℂ^45"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1 ⊞ ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^110", "ℂ^104", "ℂ^110"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1 ⊞ ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^269", "ℂ^267", "ℂ^266"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1 ⊞ ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^668", "ℂ^669", "ℂ^669"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1 ⊞ ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] + +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 1, -2 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 13, 1 => 9, -1 => 9, 2 => 5, -2 => 5, 3 => 1, -3 => 1)", "Rep[U₁](0 => 11, 1 => 10, -1 => 10, 2 => 4, -2 => 4, 3 => 1, -3 => 1)", "Rep[U₁](0 => 13, 1 => 9, -1 => 9, 2 => 6, -2 => 6, 3 => 1, -3 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 26, 1 => 22, -1 => 22, 2 => 13, -2 => 13, 3 => 6, -3 => 6, 4 => 1, -4 => 1)", "Rep[U₁](0 => 26, 1 => 21, -1 => 21, 2 => 12, -2 => 12, 3 => 5, -3 => 5, 4 => 1, -4 => 1)", "Rep[U₁](0 => 26, 1 => 22, -1 => 22, 2 => 13, -2 => 13, 3 => 6, -3 => 6, 4 => 1, -4 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 59, 1 => 53, -1 => 53, 2 => 32, -2 => 32, 3 => 14, -3 => 14, 4 => 5, -4 => 5, 5 => 1, -5 => 1)", "Rep[U₁](0 => 61, 1 => 51, -1 => 51, 2 => 35, -2 => 35, 3 => 12, -3 => 12, 4 => 4, -4 => 4, 5 => 1, -5 => 1)", "Rep[U₁](0 => 58, 1 => 52, -1 => 52, 2 => 32, -2 => 32, 3 => 14, -3 => 14, 4 => 5, -4 => 5, 5 => 1, -5 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 140, 1 => 121, -1 => 121, 2 => 83, -2 => 83, 3 => 41, -3 => 41, 4 => 14, -4 => 14, 5 => 4, -5 => 4, 6 => 1, -6 => 1)", "Rep[U₁](0 => 145, 1 => 131, -1 => 131, 2 => 83, -2 => 83, 3 => 38, -3 => 38, 4 => 9, -4 => 9, 5 => 1, -5 => 1)", "Rep[U₁](0 => 141, 1 => 122, -1 => 122, 2 => 83, -2 => 83, 3 => 40, -3 => 40, 4 => 14, -4 => 14, 5 => 4, -5 => 4, 6 => 1, -6 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 328, 1 => 293, -1 => 293, 2 => 204, -2 => 204, 3 => 107, -3 => 107, 4 => 43, -4 => 43, 5 => 11, -5 => 11, 6 => 1, -6 => 1)", "Rep[U₁](0 => 344, 1 => 298, -1 => 298, 2 => 206, -2 => 206, 3 => 102, -3 => 102, 4 => 37, -4 => 37, 5 => 8, -5 => 8, 6 => 1, -6 => 1)", "Rep[U₁](0 => 329, 1 => 293, -1 => 293, 2 => 203, -2 => 203, 3 => 108, -3 => 108, 4 => 43, -4 => 43, 5 => 11, -5 => 11, 6 => 1, -6 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 771, 1 => 692, -1 => 692, 2 => 495, -2 => 495, 3 => 283, -3 => 283, 4 => 124, -4 => 124, 5 => 41, -5 => 41, 6 => 8, -6 => 8, 7 => 1, -7 => 1)", "Rep[U₁](0 => 787, 1 => 704, -1 => 704, 2 => 493, -2 => 493, 3 => 275, -3 => 275, 4 => 118, -4 => 118, 5 => 36, -5 => 36, 6 => 8, -6 => 8, 7 => 1, -7 => 1)", "Rep[U₁](0 => 771, 1 => 692, -1 => 692, 2 => 495, -2 => 495, 3 => 282, -3 => 282, 4 => 124, -4 => 124, 5 => 41, -5 => 41, 6 => 8, -6 => 8, 7 => 1, -7 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] + +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](0 => 1)", "Rep[SU₂](1 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](1 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 1, 2 => 1, 3 => 1)", "Rep[SU₂](0 => 1, 1 => 2, 2 => 1)", "Rep[SU₂](0 => 1, 1 => 1, 2 => 1, 3 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 4, 1 => 4, 2 => 4, 3 => 1)", "Rep[SU₂](0 => 1, 1 => 6, 2 => 3, 3 => 1)", "Rep[SU₂](0 => 4, 1 => 3, 2 => 5, 3 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 4, 1 => 9, 2 => 7, 3 => 5, 4 => 1)", "Rep[SU₂](0 => 5, 1 => 9, 2 => 7, 3 => 4, 4 => 1)", "Rep[SU₂](0 => 4, 1 => 9, 2 => 7, 3 => 5, 4 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 6, 1 => 21, 2 => 18, 3 => 9, 4 => 4, 5 => 1)", "Rep[SU₂](0 => 10, 1 => 16, 2 => 23, 3 => 8, 4 => 3, 5 => 1)", "Rep[SU₂](0 => 6, 1 => 20, 2 => 18, 3 => 9, 4 => 4, 5 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 19, 1 => 38, 2 => 42, 3 => 27, 4 => 10, 5 => 3, 6 => 1)", "Rep[SU₂](0 => 14, 1 => 48, 2 => 45, 3 => 29, 4 => 8, 5 => 1)", "Rep[SU₂](0 => 19, 1 => 39, 2 => 43, 3 => 26, 4 => 10, 5 => 3, 6 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 35, 1 => 89, 2 => 97, 3 => 64, 4 => 32, 5 => 10, 6 => 1)", "Rep[SU₂](0 => 46, 1 => 92, 2 => 104, 3 => 65, 4 => 29, 5 => 7, 6 => 1)", "Rep[SU₂](0 => 36, 1 => 90, 2 => 95, 3 => 65, 4 => 32, 5 => 10, 6 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 79, 1 => 197, 2 => 212, 3 => 159, 4 => 83, 5 => 33, 6 => 7, 7 => 1)", "Rep[SU₂](0 => 83, 1 => 211, 2 => 218, 3 => 157, 4 => 82, 5 => 28, 6 => 7, 7 => 1)", "Rep[SU₂](0 => 79, 1 => 197, 2 => 213, 3 => 158, 4 => 83, 5 => 33, 6 => 7, 7 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 169, 1 => 427, 2 => 488, 3 => 380, 4 => 217, 5 => 92, 6 => 29, 7 => 6, 8 => 1)", "Rep[SU₂](0 => 185, 1 => 432, 2 => 510, 3 => 380, 4 => 210, 5 => 89, 6 => 26, 7 => 6)", "Rep[SU₂](0 => 168, 1 => 426, 2 => 489, 3 => 380, 4 => 217, 5 => 92, 6 => 29, 7 => 6, 8 => 1)"] +nonzero_keys = [[[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]], [[1, 1], [10, 10], [7, 7], [6, 6], [9, 9], [8, 8], [5, 5], [2, 10], [3, 10], [4, 10], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] diff --git a/benchmark/MPSKitBenchmarks/derivatives/heisenberg_NN.toml b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_nn.toml similarity index 64% rename from benchmark/MPSKitBenchmarks/derivatives/heisenberg_NN.toml rename to benchmark/MPSKitBenchmarks/derivatives/heisenberg_nn.toml index ad1412195..1e508e53a 100644 --- a/benchmark/MPSKitBenchmarks/derivatives/heisenberg_NN.toml +++ b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_nn.toml @@ -1,152 +1,132 @@ [[Trivial]] -mps_virtualspaces = ["ℂ^1", "ℂ^3", "ℂ^1"] +mps_virtualspaces = ["ℂ^3", "ℂ^1", "ℂ^3"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] [[Trivial]] -mps_virtualspaces = ["ℂ^4", "ℂ^4", "ℂ^4"] +mps_virtualspaces = ["ℂ^7", "ℂ^7", "ℂ^7"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] [[Trivial]] -mps_virtualspaces = ["ℂ^4", "ℂ^7", "ℂ^4"] +mps_virtualspaces = ["ℂ^16", "ℂ^16", "ℂ^16"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] [[Trivial]] -mps_virtualspaces = ["ℂ^12", "ℂ^12", "ℂ^12"] +mps_virtualspaces = ["ℂ^44", "ℂ^44", "ℂ^44"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] [[Trivial]] -mps_virtualspaces = ["ℂ^21", "ℂ^21", "ℂ^21"] +mps_virtualspaces = ["ℂ^108", "ℂ^108", "ℂ^108"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] [[Trivial]] -mps_virtualspaces = ["ℂ^29", "ℂ^31", "ℂ^29"] +mps_virtualspaces = ["ℂ^271", "ℂ^271", "ℂ^271"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] [[Trivial]] -mps_virtualspaces = ["ℂ^53", "ℂ^56", "ℂ^53"] -nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] -mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] -physicalspaces = ["ℂ^3", "ℂ^3"] -[[Trivial]] -mps_virtualspaces = ["ℂ^81", "ℂ^88", "ℂ^81"] -nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] -mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] -physicalspaces = ["ℂ^3", "ℂ^3"] -[[Trivial]] -mps_virtualspaces = ["ℂ^81", "ℂ^148", "ℂ^81"] -nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] -mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] -physicalspaces = ["ℂ^3", "ℂ^3"] -[[Trivial]] -mps_virtualspaces = ["ℂ^81", "ℂ^243", "ℂ^81"] +mps_virtualspaces = ["ℂ^661", "ℂ^667", "ℂ^669"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] physicalspaces = ["ℂ^3", "ℂ^3"] [["Irrep[U₁]"]] -mps_virtualspaces = ["Rep[U₁](0 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1)"] -nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] -mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] -physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] -[["Irrep[U₁]"]] -mps_virtualspaces = ["Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)"] +mps_virtualspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] [["Irrep[U₁]"]] -mps_virtualspaces = ["Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)", "Rep[U₁](0 => 2, 1 => 1, -1 => 1)"] +mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] [["Irrep[U₁]"]] -mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] +mps_virtualspaces = ["Rep[U₁](0 => 6, 1 => 4, -1 => 4, 2 => 1, -2 => 1)", "Rep[U₁](0 => 6, 1 => 4, -1 => 4, 2 => 1, -2 => 1)", "Rep[U₁](0 => 6, 1 => 4, -1 => 4, 2 => 1, -2 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] [["Irrep[U₁]"]] -mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] +mps_virtualspaces = ["Rep[U₁](0 => 12, 1 => 10, -1 => 10, 2 => 5, -2 => 5, 3 => 1, -3 => 1)", "Rep[U₁](0 => 12, 1 => 10, -1 => 10, 2 => 5, -2 => 5, 3 => 1, -3 => 1)", "Rep[U₁](0 => 12, 1 => 10, -1 => 10, 2 => 5, -2 => 5, 3 => 1, -3 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] [["Irrep[U₁]"]] -mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2, 2 => 1, -2 => 1)"] +mps_virtualspaces = ["Rep[U₁](0 => 32, 1 => 25, -1 => 25, 2 => 11, -2 => 11, 3 => 2, -3 => 2)", "Rep[U₁](0 => 32, 1 => 25, -1 => 25, 2 => 11, -2 => 11, 3 => 2, -3 => 2)", "Rep[U₁](0 => 32, 1 => 25, -1 => 25, 2 => 11, -2 => 11, 3 => 2, -3 => 2)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] [["Irrep[U₁]"]] -mps_virtualspaces = ["Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)"] +mps_virtualspaces = ["Rep[U₁](0 => 71, 1 => 58, -1 => 58, 2 => 31, -2 => 31, 3 => 10, -3 => 10, 4 => 1, -4 => 1)", "Rep[U₁](0 => 71, 1 => 58, -1 => 58, 2 => 31, -2 => 31, 3 => 10, -3 => 10, 4 => 1, -4 => 1)", "Rep[U₁](0 => 71, 1 => 58, -1 => 58, 2 => 31, -2 => 31, 3 => 10, -3 => 10, 4 => 1, -4 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] [["Irrep[U₁]"]] -mps_virtualspaces = ["Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)", "Rep[U₁](0 => 4, 1 => 3, -1 => 3, 2 => 2, -2 => 2, 3 => 1, -3 => 1)", "Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)"] +mps_virtualspaces = ["Rep[U₁](0 => 153, 1 => 130, -1 => 130, 2 => 79, -2 => 79, 3 => 33, -3 => 33, 4 => 10, -4 => 10, 5 => 2, -5 => 2)", "Rep[U₁](0 => 157, 1 => 133, -1 => 133, 2 => 80, -2 => 80, 3 => 33, -3 => 33, 4 => 8, -4 => 8, 5 => 1, -5 => 1)", "Rep[U₁](0 => 159, 1 => 134, -1 => 134, 2 => 80, -2 => 80, 3 => 32, -3 => 32, 4 => 8, -4 => 8, 5 => 1, -5 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] [["Irrep[U₁]"]] -mps_virtualspaces = ["Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)", "Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)", "Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)"] +mps_virtualspaces = ["Rep[U₁](0 => 307, 1 => 273, -1 => 273, 2 => 194, -2 => 194, 3 => 114, -3 => 114, 4 => 58, -4 => 58, 5 => 24, -5 => 24, 6 => 6, -6 => 6, 7 => 1, -7 => 1)", "Rep[U₁](0 => 317, 1 => 280, -1 => 280, 2 => 194, -2 => 194, 3 => 110, -3 => 110, 4 => 53, -4 => 53, 5 => 20, -5 => 20, 6 => 5, -6 => 5, 7 => 1, -7 => 1)", "Rep[U₁](0 => 313, 1 => 278, -1 => 278, 2 => 196, -2 => 196, 3 => 114, -3 => 114, 4 => 56, -4 => 56, 5 => 20, -5 => 20, 6 => 4, -6 => 4)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] [["Irrep[U₁]"]] -mps_virtualspaces = ["Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)", "Rep[U₁](0 => 6, 1 => 5, -1 => 5, 2 => 4, -2 => 4, 3 => 3, -3 => 3, 4 => 2, -4 => 2, 5 => 1, -5 => 1)", "Rep[U₁](0 => 5, 1 => 4, -1 => 4, 2 => 3, -2 => 3, 3 => 2, -3 => 2, 4 => 1, -4 => 1)"] +mps_virtualspaces = ["Rep[U₁](0 => 987, 1 => 830, -1 => 830, 2 => 432, -2 => 432, 3 => 161, -3 => 161, 4 => 77, -4 => 77, 5 => 28, -5 => 28, 6 => 7, -6 => 7, 7 => 1, -7 => 1)", "Rep[U₁](0 => 701, 1 => 635, -1 => 635, 2 => 478, -2 => 478, 3 => 303, -3 => 303, 4 => 162, -4 => 162, 5 => 70, -5 => 70, 6 => 22, -6 => 22, 7 => 4, -7 => 4)", "Rep[U₁](0 => 987, 1 => 830, -1 => 830, 2 => 431, -2 => 431, 3 => 161, -3 => 161, 4 => 77, -4 => 77, 5 => 28, -5 => 28, 6 => 7, -6 => 7, 7 => 1, -7 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] [["Irrep[SU₂]"]] -mps_virtualspaces = ["Rep[SU₂](0 => 1)", "Rep[SU₂](1 => 1)", "Rep[SU₂](0 => 1)"] +mps_virtualspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](0 => 1)", "Rep[SU₂](1 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] [["Irrep[SU₂]"]] -mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 1)"] +mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 2)", "Rep[SU₂](0 => 1, 1 => 2)", "Rep[SU₂](0 => 1, 1 => 2)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] [["Irrep[SU₂]"]] -mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 1)", "Rep[SU₂](0 => 1, 1 => 2)", "Rep[SU₂](0 => 1, 1 => 1)"] +mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 3, 2 => 1)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 1)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] [["Irrep[SU₂]"]] -mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 2, 2 => 1)", "Rep[SU₂](0 => 1, 1 => 2, 2 => 1)", "Rep[SU₂](0 => 1, 1 => 2, 2 => 1)"] +mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)", "Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)", "Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] [["Irrep[SU₂]"]] -mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 3, 2 => 2)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 2)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 2)"] +mps_virtualspaces = ["Rep[SU₂](0 => 7, 1 => 14, 2 => 9, 3 => 2)", "Rep[SU₂](0 => 7, 1 => 14, 2 => 9, 3 => 2)", "Rep[SU₂](0 => 7, 1 => 14, 2 => 9, 3 => 2)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] [["Irrep[SU₂]"]] -mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 4, 2 => 3)", "Rep[SU₂](0 => 2, 1 => 4, 2 => 2, 3 => 1)", "Rep[SU₂](0 => 2, 1 => 4, 2 => 3)"] +mps_virtualspaces = ["Rep[SU₂](0 => 13, 1 => 27, 2 => 21, 3 => 9, 4 => 1)", "Rep[SU₂](0 => 13, 1 => 27, 2 => 21, 3 => 9, 4 => 1)", "Rep[SU₂](0 => 13, 1 => 27, 2 => 21, 3 => 9, 4 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] [["Irrep[SU₂]"]] -mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 5, 3 => 1)", "Rep[SU₂](0 => 3, 1 => 7, 2 => 5, 3 => 1)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 5, 3 => 1)"] +mps_virtualspaces = ["Rep[SU₂](0 => 23, 1 => 51, 2 => 46, 3 => 23, 4 => 8, 5 => 2)", "Rep[SU₂](0 => 24, 1 => 53, 2 => 47, 3 => 25, 4 => 7, 5 => 1)", "Rep[SU₂](0 => 25, 1 => 54, 2 => 48, 3 => 24, 4 => 7, 5 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] [["Irrep[SU₂]"]] -mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)", "Rep[SU₂](0 => 4, 1 => 10, 2 => 8, 3 => 2)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)"] +mps_virtualspaces = ["Rep[SU₂](0 => 34, 1 => 79, 2 => 80, 3 => 56, 4 => 34, 5 => 18, 6 => 5, 7 => 1)", "Rep[SU₂](0 => 37, 1 => 86, 2 => 84, 3 => 57, 4 => 33, 5 => 15, 6 => 4, 7 => 1)", "Rep[SU₂](0 => 35, 1 => 82, 2 => 82, 3 => 58, 4 => 36, 5 => 16, 6 => 4)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] [["Irrep[SU₂]"]] -mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)", "Rep[SU₂](0 => 6, 1 => 12, 2 => 11, 3 => 6, 4 => 1)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)"] +mps_virtualspaces = ["Rep[SU₂](0 => 157, 1 => 398, 2 => 271, 3 => 84, 4 => 49, 5 => 21, 6 => 6, 7 => 1)", "Rep[SU₂](0 => 66, 1 => 157, 2 => 175, 3 => 141, 4 => 92, 5 => 48, 6 => 18, 7 => 4)", "Rep[SU₂](0 => 157, 1 => 399, 2 => 270, 3 => 84, 4 => 49, 5 => 21, 6 => 6, 7 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] [["Irrep[SU₂]"]] -mps_virtualspaces = ["Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)", "Rep[SU₂](0 => 6, 1 => 15, 2 => 15, 3 => 10, 4 => 4, 5 => 1)", "Rep[SU₂](0 => 3, 1 => 6, 2 => 6, 3 => 3, 4 => 1)"] +mps_virtualspaces = ["Rep[SU₂](0 => 1196, 1 => 1678, 2 => 483, 3 => 84, 4 => 49, 5 => 21, 6 => 6, 7 => 1)", "Rep[SU₂](0 => 603, 1 => 1213, 2 => 280, 3 => 237, 4 => 153, 5 => 76, 6 => 28, 7 => 7, 8 => 1)", "Rep[SU₂](0 => 1198, 1 => 1646, 2 => 502, 3 => 84, 4 => 49, 5 => 21, 6 => 6, 7 => 1)"] nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] diff --git a/benchmark/MPSKitBenchmarks/derivatives/heisenberg_nnn.toml b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_nnn.toml new file mode 100644 index 000000000..1e508e53a --- /dev/null +++ b/benchmark/MPSKitBenchmarks/derivatives/heisenberg_nnn.toml @@ -0,0 +1,132 @@ +[[Trivial]] +mps_virtualspaces = ["ℂ^3", "ℂ^1", "ℂ^3"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^7", "ℂ^7", "ℂ^7"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^16", "ℂ^16", "ℂ^16"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^44", "ℂ^44", "ℂ^44"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^108", "ℂ^108", "ℂ^108"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^271", "ℂ^271", "ℂ^271"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] +[[Trivial]] +mps_virtualspaces = ["ℂ^661", "ℂ^667", "ℂ^669"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)", "(ℂ^1 ⊞ ℂ^3 ⊞ ℂ^1)"] +physicalspaces = ["ℂ^3", "ℂ^3"] + +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 3, 1 => 2, -1 => 2)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2)", "Rep[U₁](0 => 3, 1 => 2, -1 => 2)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 6, 1 => 4, -1 => 4, 2 => 1, -2 => 1)", "Rep[U₁](0 => 6, 1 => 4, -1 => 4, 2 => 1, -2 => 1)", "Rep[U₁](0 => 6, 1 => 4, -1 => 4, 2 => 1, -2 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 12, 1 => 10, -1 => 10, 2 => 5, -2 => 5, 3 => 1, -3 => 1)", "Rep[U₁](0 => 12, 1 => 10, -1 => 10, 2 => 5, -2 => 5, 3 => 1, -3 => 1)", "Rep[U₁](0 => 12, 1 => 10, -1 => 10, 2 => 5, -2 => 5, 3 => 1, -3 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 32, 1 => 25, -1 => 25, 2 => 11, -2 => 11, 3 => 2, -3 => 2)", "Rep[U₁](0 => 32, 1 => 25, -1 => 25, 2 => 11, -2 => 11, 3 => 2, -3 => 2)", "Rep[U₁](0 => 32, 1 => 25, -1 => 25, 2 => 11, -2 => 11, 3 => 2, -3 => 2)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 71, 1 => 58, -1 => 58, 2 => 31, -2 => 31, 3 => 10, -3 => 10, 4 => 1, -4 => 1)", "Rep[U₁](0 => 71, 1 => 58, -1 => 58, 2 => 31, -2 => 31, 3 => 10, -3 => 10, 4 => 1, -4 => 1)", "Rep[U₁](0 => 71, 1 => 58, -1 => 58, 2 => 31, -2 => 31, 3 => 10, -3 => 10, 4 => 1, -4 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 153, 1 => 130, -1 => 130, 2 => 79, -2 => 79, 3 => 33, -3 => 33, 4 => 10, -4 => 10, 5 => 2, -5 => 2)", "Rep[U₁](0 => 157, 1 => 133, -1 => 133, 2 => 80, -2 => 80, 3 => 33, -3 => 33, 4 => 8, -4 => 8, 5 => 1, -5 => 1)", "Rep[U₁](0 => 159, 1 => 134, -1 => 134, 2 => 80, -2 => 80, 3 => 32, -3 => 32, 4 => 8, -4 => 8, 5 => 1, -5 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 307, 1 => 273, -1 => 273, 2 => 194, -2 => 194, 3 => 114, -3 => 114, 4 => 58, -4 => 58, 5 => 24, -5 => 24, 6 => 6, -6 => 6, 7 => 1, -7 => 1)", "Rep[U₁](0 => 317, 1 => 280, -1 => 280, 2 => 194, -2 => 194, 3 => 110, -3 => 110, 4 => 53, -4 => 53, 5 => 20, -5 => 20, 6 => 5, -6 => 5, 7 => 1, -7 => 1)", "Rep[U₁](0 => 313, 1 => 278, -1 => 278, 2 => 196, -2 => 196, 3 => 114, -3 => 114, 4 => 56, -4 => 56, 5 => 20, -5 => 20, 6 => 4, -6 => 4)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] +[["Irrep[U₁]"]] +mps_virtualspaces = ["Rep[U₁](0 => 987, 1 => 830, -1 => 830, 2 => 432, -2 => 432, 3 => 161, -3 => 161, 4 => 77, -4 => 77, 5 => 28, -5 => 28, 6 => 7, -6 => 7, 7 => 1, -7 => 1)", "Rep[U₁](0 => 701, 1 => 635, -1 => 635, 2 => 478, -2 => 478, 3 => 303, -3 => 303, 4 => 162, -4 => 162, 5 => 70, -5 => 70, 6 => 22, -6 => 22, 7 => 4, -7 => 4)", "Rep[U₁](0 => 987, 1 => 830, -1 => 830, 2 => 431, -2 => 431, 3 => 161, -3 => 161, 4 => 77, -4 => 77, 5 => 28, -5 => 28, 6 => 7, -6 => 7, 7 => 1, -7 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))", "(Rep[U₁](0=>1) ⊞ Rep[U₁](0=>1, 1=>1, -1=>1) ⊞ Rep[U₁](0=>1))"] +physicalspaces = ["Rep[U₁](0 => 1, 1 => 1, -1 => 1)", "Rep[U₁](0 => 1, 1 => 1, -1 => 1)"] + +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](0 => 1)", "Rep[SU₂](1 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 1, 1 => 2)", "Rep[SU₂](0 => 1, 1 => 2)", "Rep[SU₂](0 => 1, 1 => 2)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 3, 2 => 1)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 1)", "Rep[SU₂](0 => 2, 1 => 3, 2 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)", "Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)", "Rep[SU₂](0 => 2, 1 => 5, 2 => 4, 3 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 7, 1 => 14, 2 => 9, 3 => 2)", "Rep[SU₂](0 => 7, 1 => 14, 2 => 9, 3 => 2)", "Rep[SU₂](0 => 7, 1 => 14, 2 => 9, 3 => 2)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 13, 1 => 27, 2 => 21, 3 => 9, 4 => 1)", "Rep[SU₂](0 => 13, 1 => 27, 2 => 21, 3 => 9, 4 => 1)", "Rep[SU₂](0 => 13, 1 => 27, 2 => 21, 3 => 9, 4 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 23, 1 => 51, 2 => 46, 3 => 23, 4 => 8, 5 => 2)", "Rep[SU₂](0 => 24, 1 => 53, 2 => 47, 3 => 25, 4 => 7, 5 => 1)", "Rep[SU₂](0 => 25, 1 => 54, 2 => 48, 3 => 24, 4 => 7, 5 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 34, 1 => 79, 2 => 80, 3 => 56, 4 => 34, 5 => 18, 6 => 5, 7 => 1)", "Rep[SU₂](0 => 37, 1 => 86, 2 => 84, 3 => 57, 4 => 33, 5 => 15, 6 => 4, 7 => 1)", "Rep[SU₂](0 => 35, 1 => 82, 2 => 82, 3 => 58, 4 => 36, 5 => 16, 6 => 4)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 157, 1 => 398, 2 => 271, 3 => 84, 4 => 49, 5 => 21, 6 => 6, 7 => 1)", "Rep[SU₂](0 => 66, 1 => 157, 2 => 175, 3 => 141, 4 => 92, 5 => 48, 6 => 18, 7 => 4)", "Rep[SU₂](0 => 157, 1 => 399, 2 => 270, 3 => 84, 4 => 49, 5 => 21, 6 => 6, 7 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] +[["Irrep[SU₂]"]] +mps_virtualspaces = ["Rep[SU₂](0 => 1196, 1 => 1678, 2 => 483, 3 => 84, 4 => 49, 5 => 21, 6 => 6, 7 => 1)", "Rep[SU₂](0 => 603, 1 => 1213, 2 => 280, 3 => 237, 4 => 153, 5 => 76, 6 => 28, 7 => 7, 8 => 1)", "Rep[SU₂](0 => 1198, 1 => 1646, 2 => 502, 3 => 84, 4 => 49, 5 => 21, 6 => 6, 7 => 1)"] +nonzero_keys = [[[1, 1], [3, 3], [2, 3], [1, 2]], [[1, 1], [3, 3], [2, 3], [1, 2]]] +mpo_virtualspaces = ["(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))", "(Rep[SU₂](0=>1) ⊞ Rep[SU₂](1=>1) ⊞ Rep[SU₂](0=>1))"] +physicalspaces = ["Rep[SU₂](1 => 1)", "Rep[SU₂](1 => 1)"] diff --git a/benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl b/benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl index 9842959d5..e1587648e 100644 --- a/benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl +++ b/benchmark/MPSKitBenchmarks/scripts/setup_heisenberg.jl @@ -12,6 +12,9 @@ using .MPSKitBenchmarks using .MPSKitBenchmarks.DerivativesBenchmarks: AC2Spec using .MPSKitBenchmarks.BenchUtils: tomlify +# needed to make parsing correct +BlockTensorKit.SUMSPACE_SHOW_LIMIT[] = typemax(Int) + # Utility functions # ---------------- # setup "product state" -> ⨂^N |↑↓ - ↓↑⟩ @@ -50,9 +53,44 @@ D_steps = 10 D_min = 3 -# FiniteChain -# ----------- -L = 10 +# NN +# -- +L = 100 +lattice = FiniteChain(L) + +symmetry = SU2Irrep +alg = DMRG2(; + maxiter = 10, tol = 1.0e-12, + alg_eigsolve = (; tol = 1.0e-5, dynamic_tols = false, maxiter = 3), + trscheme = truncrank(D_max) +) + +H = heisenberg_XXX(T, symmetry, lattice; spin); +specs_su2 = generate_spaces(H, alg; D_min, D_steps) + +specs_triv = filter!(convert.(AC2Spec{ComplexSpace}, specs_su2)) do spec + dim(spec.mps_virtualspaces[1]) < 1000 +end + +specs_u1 = filter!(convert.(AC2Spec{U1Space}, specs_su2)) do spec + dim(spec.mps_virtualspaces[1]) < 5000 +end + +output_file = joinpath(@__DIR__, "..", "derivatives", "heisenberg_nn.toml") +open(output_file, "w") do io + TOML.print( + io, Dict( + type_repr(Trivial) => tomlify.(specs_triv), + type_repr(U1Irrep) => tomlify.(specs_u1), + type_repr(SU2Irrep) => tomlify.(specs_su2) + ) + ) +end +@info("Spaces written to $output_file") + +# NNN +# --- +L = 100 lattice = FiniteChain(L) symmetry = SU2Irrep @@ -62,6 +100,10 @@ alg = DMRG2(; trscheme = truncrank(D_max) ) +SS = S_exchange(T, symmetry; spin) +H = @mpoham sum(next_nearest_neighbours(lattice)) do (i, j) + return SS{i, j} +end H = heisenberg_XXX(T, symmetry, lattice; spin); specs_su2 = generate_spaces(H, alg; D_min, D_steps) @@ -73,9 +115,86 @@ specs_u1 = filter!(convert.(AC2Spec{U1Space}, specs_su2)) do spec dim(spec.mps_virtualspaces[1]) < 5000 end -specs = vcat(specs_triv, specs_u1, specs_su2) +output_file = joinpath(@__DIR__, "..", "derivatives", "heisenberg_nnn.toml") +open(output_file, "w") do io + TOML.print( + io, Dict( + type_repr(Trivial) => tomlify.(specs_triv), + type_repr(U1Irrep) => tomlify.(specs_u1), + type_repr(SU2Irrep) => tomlify.(specs_su2) + ) + ) +end +@info("Spaces written to $output_file") + +# FiniteCylinder +# -------------- +rows = 6 +cols = 12 +lattice = FiniteCylinder(rows, rows * cols) + +symmetry = SU2Irrep +alg = DMRG2(; + maxiter = 10, tol = 1.0e-12, + alg_eigsolve = (; tol = 1.0e-5, dynamic_tols = false, maxiter = 3), + trscheme = truncrank(D_max) +) + +H = heisenberg_XXX(T, symmetry, lattice; spin); +specs_su2 = generate_spaces(H, alg; D_min, D_steps) + +specs_triv = filter!(convert.(AC2Spec{ComplexSpace}, specs_su2)) do spec + dim(spec.mps_virtualspaces[1]) < 1000 +end + +specs_u1 = filter!(convert.(AC2Spec{U1Space}, specs_su2)) do spec + dim(spec.mps_virtualspaces[1]) < 5000 +end + +output_file = joinpath(@__DIR__, "..", "derivatives", "heisenberg_cylinder.toml") +open(output_file, "w") do io + TOML.print( + io, Dict( + type_repr(Trivial) => tomlify.(specs_triv), + type_repr(U1Irrep) => tomlify.(specs_u1), + type_repr(SU2Irrep) => tomlify.(specs_su2) + ) + ) +end +@info("Spaces written to $output_file") + +# Coulomb +# ------- +L = 30 +symmetry = SU2Irrep +SS = S_exchange(T, symmetry; spin) +lattice = fill(space(SS, 1), L) +terms = [] +for i in 1:(L - 1), j in (i + 1):L + push!(terms, (i, j) => SS / abs(i - j)) +end +H = FiniteMPOHamiltonian(lattice, terms...); +H = changebonds(H, SvdCut(; trscheme = truncrank(500))); + +D_max = 1_000 +symmetry = SU2Irrep +alg = DMRG2(; + maxiter = 10, tol = 1.0e-12, + alg_eigsolve = (; tol = 1.0e-5, dynamic_tols = false, maxiter = 3), + trscheme = truncrank(D_max) +) + +specs_su2 = generate_spaces(H, alg; D_min, D_steps) + +specs_triv = filter!(convert.(AC2Spec{ComplexSpace}, specs_su2)) do spec + dim(spec.mps_virtualspaces[1]) < 500 +end + +specs_u1 = filter!(convert.(AC2Spec{U1Space}, specs_su2)) do spec + dim(spec.mps_virtualspaces[1]) < 500 +end -output_file = joinpath(@__DIR__, "..", "derivatives", "heisenberg_NN.toml") +output_file = joinpath(@__DIR__, "..", "derivatives", "heisenberg_coulomb.toml") open(output_file, "w") do io TOML.print( io, Dict( diff --git a/benchmark/MPSKitBenchmarks/utils/BenchUtils.jl b/benchmark/MPSKitBenchmarks/utils/BenchUtils.jl index c16f28ef1..3db7f8592 100644 --- a/benchmark/MPSKitBenchmarks/utils/BenchUtils.jl +++ b/benchmark/MPSKitBenchmarks/utils/BenchUtils.jl @@ -6,7 +6,7 @@ using TensorKit using BlockTensorKit using TOML -tomlify(x::VectorSpace) = string(x) +tomlify(x::VectorSpace) = sprint(show, x; context = :limited => false) untomlify(::Type{<:VectorSpace}, x) = eval(Meta.parse(x)) @@ -17,7 +17,7 @@ function TensorKit.U1Space(V::SU2Space) dims = TensorKit.SectorDict{U1Irrep, Int}() for c in sectors(V), m in (-c.j):(c.j) u1 = U1Irrep(m) - dims[u1] = get(dims, u1, 0) + 1 + dims[u1] = get(dims, u1, 0) + dim(V, c) end return U1Space(dims; dual = isdual(V)) end From 773c7601b7960d5653f47a892db47d80c1a4a1a3 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Mon, 3 Nov 2025 09:22:09 -0500 Subject: [PATCH 09/37] Precomputed derivatives I --- src/MPSKit.jl | 1 - .../derivatives/hamiltonian_derivatives.jl | 336 ------------------ src/algorithms/derivatives/mpo_derivatives.jl | 51 +++ 3 files changed, 51 insertions(+), 337 deletions(-) delete mode 100644 src/algorithms/derivatives/hamiltonian_derivatives.jl diff --git a/src/MPSKit.jl b/src/MPSKit.jl index 7b18a31c6..20214813d 100644 --- a/src/MPSKit.jl +++ b/src/MPSKit.jl @@ -141,7 +141,6 @@ include("environments/lazylincocache.jl") include("algorithms/fixedpoint.jl") include("algorithms/derivatives/derivatives.jl") include("algorithms/derivatives/mpo_derivatives.jl") -include("algorithms/derivatives/hamiltonian_derivatives.jl") include("algorithms/derivatives/projection_derivatives.jl") include("algorithms/expval.jl") include("algorithms/toolbox.jl") diff --git a/src/algorithms/derivatives/hamiltonian_derivatives.jl b/src/algorithms/derivatives/hamiltonian_derivatives.jl deleted file mode 100644 index 2b4f67235..000000000 --- a/src/algorithms/derivatives/hamiltonian_derivatives.jl +++ /dev/null @@ -1,336 +0,0 @@ -""" - JordanMPO_AC_Hamiltonian{O1,O2,O3} - -Efficient operator for representing the single-site derivative of a `MPOHamiltonian` sandwiched between two MPSs. -In particular, this operator aims to make maximal use of the structure of the `MPOHamiltonian` to reduce the number of operations required to apply the operator to a tensor. -""" -struct JordanMPO_AC_Hamiltonian{O1, O2, O3} <: DerivativeOperator - D::Union{O1, Missing} # onsite - I::Union{O1, Missing} # not started - E::Union{O1, Missing} # finished - C::Union{O2, Missing} # starting - B::Union{O2, Missing} # ending - A::O3 # continuing - function JordanMPO_AC_Hamiltonian( - onsite, not_started, finished, starting, ending, continuing - ) - # obtaining storagetype of environments since these should have already mixed - # the types of the operator and state - gl = continuing[1] - S = spacetype(gl) - M = storagetype(gl) - O1 = tensormaptype(S, 1, 1, M) - O2 = tensormaptype(S, 2, 2, M) - return new{O1, O2, typeof(continuing)}( - onsite, not_started, finished, starting, ending, continuing - ) - end - function JordanMPO_AC_Hamiltonian{O1, O2, O3}( - onsite, not_started, finished, starting, ending, continuing - ) where {O1, O2, O3} - return new{O1, O2, O3}(onsite, not_started, finished, starting, ending, continuing) - end -end - -""" - JordanMPO_AC2_Hamiltonian{O1,O2,O3,O4} - -Efficient operator for representing the single-site derivative of a `MPOHamiltonian` sandwiched between two MPSs. -In particular, this operator aims to make maximal use of the structure of the `MPOHamiltonian` to reduce the number of operations required to apply the operator to a tensor. -""" -struct JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4} <: DerivativeOperator - II::Union{O1, Missing} # not_started - IC::Union{O2, Missing} # starting right - ID::Union{O1, Missing} # onsite right - CB::Union{O2, Missing} # starting left - ending right - CA::Union{O3, Missing} # starting left - continuing right - AB::Union{O3, Missing} # continuing left - ending right - AA::O4 # continuing left - continuing right - BE::Union{O2, Missing} # ending left - DE::Union{O1, Missing} # onsite left - EE::Union{O1, Missing} # finished - function JordanMPO_AC2_Hamiltonian(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) - # obtaining storagetype of environments since these should have already mixed - # the types of the operator and state - gl = AA[1] - S = spacetype(gl) - M = storagetype(gl) - O1 = tensormaptype(S, 1, 1, M) - O2 = tensormaptype(S, 2, 2, M) - O3 = tensormaptype(S, 3, 3, M) - return new{O1, O2, O3, typeof(AA)}(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) - end - function JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4}( - II, IC, ID, CB, CA, AB, AA, BE, DE, EE - ) where {O1, O2, O3, O4} - return new{O1, O2, O3, O4}(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) - end -end - -# Constructors -# ------------ -const _HAM_MPS_TYPES = Union{ - FiniteMPS{<:MPSTensor}, - WindowMPS{<:MPSTensor}, - InfiniteMPS{<:MPSTensor}, -} - -function prepare_operator!!( - O::MPO_AC_Hamiltonian{<:Any, <:JordanMPOTensor, <:Any}, x::MPSTensor, - backend::AbstractBackend, allocator - ) - GL = O.leftenv - W = only(O.operators) - GR = O.rightenv - - # starting - if nonzero_length(W.C) > 0 - GR_2 = GR[2:(end - 1)] - @plansor starting_[-1 -2; -3 -4] ≔ W.C[-1; -3 1] * GR_2[-4 1; -2] - starting = only(starting_) - else - starting = missing - end - - # ending - if nonzero_length(W.B) > 0 - GL_2 = GL[2:(end - 1)] - @plansor ending_[-1 -2; -3 -4] ≔ GL_2[-1 1; -3] * W.B[1 -2; -4] - ending = only(ending_) - else - ending = missing - end - - # onsite - if nonzero_length(W.D) > 0 - if !ismissing(starting) - @plansor starting[-1 -2; -3 -4] += W.D[-1; -3] * removeunit(GR[end], 2)[-4; -2] - onsite = missing - elseif !ismissing(ending) - @plansor ending[-1 -2; -3 -4] += removeunit(GL[1], 2)[-1; -3] * W.D[-2; -4] - onsite = missing - else - onsite = W.D - end - else - onsite = missing - end - - # not_started - if size(W, 4) == 1 - not_started = missing - elseif !ismissing(starting) - I = id(storagetype(GR[1]), physicalspace(W)) - @plansor starting[-1 -2; -3 -4] += I[-1; -3] * removeunit(GR[1], 2)[-4; -2] - not_started = missing - else - not_started = removeunit(GR[1], 2) - end - - # finished - if size(W, 1) == 1 - finished = missing - elseif !ismissing(ending) - I = id(storagetype(GL[end]), physicalspace(W)) - @plansor ending[-1 -2; -3 -4] += removeunit(GL[end], 2)[-1; -3] * I[-2; -4] - finished = missing - else - finished = removeunit(GL[end], 2) - end - - # continuing - A = W.A - continuing = (GL[2:(end - 1)], A, GR[2:(end - 1)]) - - O′ = JordanMPO_AC_Hamiltonian( - onsite, not_started, finished, starting, ending, continuing - ) - - return O′, x -end - -function prepare_operator!!( - O::MPO_AC2_Hamiltonian{<:Any, <:JordanMPOTensor, <:JordanMPOTensor, <:Any}, x::MPOTensor, - backend::AbstractBackend, allocator - ) - GL = O.leftenv - W1, W2 = O.operators - GR = O.rightenv - - # starting left - continuing right - if nonzero_length(W1.C) > 0 && nonzero_length(W2.A) > 0 - @plansor CA_[-1 -2 -3; -4 -5 -6] ≔ W1.C[-1; -4 2] * W2.A[2 -2; -5 1] * - GR[2:(end - 1)][-6 1; -3] - CA = only(CA_) - else - CA = missing - end - - # continuing left - ending right - if nonzero_length(W1.A) > 0 && nonzero_length(W2.B) > 0 - @plansor AB_[-1 -2 -3; -4 -5 -6] ≔ GL[2:(end - 1)][-1 2; -4] * W1.A[2 -2; -5 1] * - W2.B[1 -3; -6] - AB = only(AB_) - else - AB = missing - end - - # middle - if nonzero_length(W1.C) > 0 && nonzero_length(W2.B) > 0 - if !ismissing(CA) - @plansor CA[-1 -2 -3; -4 -5 -6] += W1.C[-1; -4 1] * W2.B[1 -2; -5] * - removeunit(GR[end], 2)[-6; -3] - CB = missing - elseif !ismissing(AB) - @plansor AB[-1 -2 -3; -4 -5 -6] += removeunit(GL[1], 2)[-1; -4] * - W1.C[-2; -5 1] * W2.B[1 -3; -6] - CB = missing - else - @plansor CB_[-1 -2; -3 -4] ≔ W1.C[-1; -3 1] * W2.B[1 -2; -4] - CB = only(CB_) - end - else - CB = missing - end - - # starting right - if nonzero_length(W2.C) > 0 - if !ismissing(CA) - I = id(storagetype(GR[1]), physicalspace(W1)) - @plansor CA[-1 -2 -3; -4 -5 -6] += (I[-1; -4] * W2.C[-2; -5 1]) * - GR[2:(end - 1)][-6 1; -3] - IC = missing - else - @plansor IC[-1 -2; -3 -4] ≔ W2.C[-1; -3 1] * GR[2:(end - 1)][-4 1; -2] - end - else - IC = missing - end - - # ending left - if nonzero_length(W1.B) > 0 - if !ismissing(AB) - I = id(storagetype(GL[end]), physicalspace(W2)) - @plansor AB[-1 -2 -3; -4 -5 -6] += GL[2:(end - 1)][-1 1; -4] * - (W1.B[1 -2; -5] * I[-3; -6]) - BE = missing - else - @plansor BE[-1 -2; -3 -4] ≔ GL[2:(end - 1)][-1 2; -3] * W1.B[2 -2; -4] - end - else - BE = missing - end - - # onsite left - if nonzero_length(W1.D) > 0 - if !ismissing(BE) - @plansor BE[-1 -2; -3 -4] += removeunit(GL[1], 2)[-1; -3] * W1.D[-2; -4] - DE = missing - elseif !ismissing(AB) - I = id(storagetype(GL[end]), physicalspace(W2)) - @plansor AB[-1 -2 -3; -4 -5 -6] += removeunit(GL[1], 2)[-1; -4] * - (W1.D[-2; -5] * I[-3; -6]) - DE = missing - # TODO: could also try in CA? - else - DE = only(W1.D) - end - else - DE = missing - end - - # onsite right - if nonzero_length(W2.D) > 0 - if !ismissing(IC) - @plansor IC[-1 -2; -3 -4] += W2.D[-1; -3] * removeunit(GR[end], 2)[-4; -2] - ID = missing - elseif !ismissing(CA) - I = id(storagetype(GR[1]), physicalspace(W1)) - @plansor CA[-1 -2 -3; -4 -5 -6] += (I[-1; -4] * W2.D[-2; -5]) * - removeunit(GR[end], 2)[-6; -3] - ID = missing - else - ID = only(W2.D) - end - else - ID = missing - end - - # finished - if size(W2, 4) == 1 - II = missing - elseif !ismissing(IC) - I = id(storagetype(GR[1]), physicalspace(W2)) - @plansor IC[-1 -2; -3 -4] += I[-1; -3] * removeunit(GR[1], 2)[-4; -2] - II = missing - elseif !ismissing(CA) - I = id(storagetype(GR[1]), physicalspace(W1) ⊗ physicalspace(W2)) - @plansor CA[-1 -2 -3; -4 -5 -6] += I[-1 -2; -4 -5] * removeunit(GR[1], 2)[-6; -3] - II = missing - else - II = transpose(removeunit(GR[1], 2)) - end - - # unstarted - if size(W1, 1) == 1 - EE = missing - elseif !ismissing(BE) - I = id(storagetype(GL[end]), physicalspace(W1)) - @plansor BE[-1 -2; -3 -4] += removeunit(GL[end], 2)[-1; -3] * I[-2; -4] - EE = missing - elseif !ismissing(AB) - I = id(storagetype(GL[end]), physicalspace(W1) ⊗ physicalspace(W2)) - @plansor AB[-1 -2 -3; -4 -5 -6] += removeunit(GL[end], 2)[-1; -4] * I[-2 -3; -5 -6] - EE = missing - else - EE = removeunit(GL[end], 2) - end - - # continuing - continuing - # TODO: MPODerivativeOperator code reuse + optimization - AA = (GL[2:(end - 1)], W1.A, W2.A, GR[2:(end - 1)]) - - O′ = JordanMPO_AC2_Hamiltonian(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) - return O′, x -end - -# Actions -# ------- -function (H::JordanMPO_AC_Hamiltonian)(x::MPSTensor) - y = zerovector(x) - - ismissing(H.D) || @plansor y[-1 -2; -3] += x[-1 1; -3] * H.D[-2; 1] - ismissing(H.E) || @plansor y[-1 -2; -3] += H.E[-1; 1] * x[1 -2; -3] - ismissing(H.I) || @plansor y[-1 -2; -3] += x[-1 -2; 1] * H.I[1; -3] - ismissing(H.C) || @plansor y[-1 -2; -3] += x[-1 2; 1] * H.C[-2 -3; 2 1] - ismissing(H.B) || @plansor y[-1 -2; -3] += H.B[-1 -2; 1 2] * x[1 2; -3] - - GL, A, GR = H.A - if nonzero_length(A) > 0 - @plansor y[-1 -2; -3] += GL[-1 5; 4] * x[4 2; 1] * A[5 -2; 2 3] * GR[1 3; -3] - end - - return y -end - -function (H::JordanMPO_AC2_Hamiltonian)(x::MPOTensor) - y = zerovector(x) - ismissing(H.II) || @plansor y[-1 -2; -3 -4] += x[-1 -2; 1 -4] * H.II[-3; 1] - ismissing(H.IC) || @plansor y[-1 -2; -3 -4] += x[-1 -2; 1 2] * H.IC[-4 -3; 2 1] - ismissing(H.ID) || @plansor y[-1 -2; -3 -4] += x[-1 -2; -3 1] * H.ID[-4; 1] - ismissing(H.CB) || @plansor y[-1 -2; -3 -4] += x[-1 1; -3 2] * H.CB[-2 -4; 1 2] - ismissing(H.CA) || @plansor y[-1 -2; -3 -4] += x[-1 1; 3 2] * H.CA[-2 -4 -3; 1 2 3] - ismissing(H.AB) || @plansor y[-1 -2; -3 -4] += x[1 2; -3 3] * H.AB[-1 -2 -4; 1 2 3] - ismissing(H.BE) || @plansor y[-1 -2; -3 -4] += x[1 2; -3 -4] * H.BE[-1 -2; 1 2] - ismissing(H.DE) || @plansor y[-1 -2; -3 -4] += x[-1 1; -3 -4] * H.DE[-2; 1] - ismissing(H.EE) || @plansor y[-1 -2; -3 -4] += x[1 -2; -3 -4] * H.EE[-1; 1] - - GL, A1, A2, GR = H.AA - if nonzero_length(A1) > 0 && nonzero_length(A2) > 0 - # TODO: there are too many entries here, this could be further optimized - @plansor y[-1 -2; -3 -4] += GL[-1 7; 6] * x[6 5; 1 3] * A1[7 -2; 5 4] * - A2[4 -4; 3 2] * GR[1 2; -3] - end - - return y -end diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index 0dc62bfc6..201f8f965 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -105,3 +105,54 @@ function (h::MPO_AC2_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPOTensor, <:MPSTen h.operators[2][7 -6; 4 5] * τ[5 -5; 2 3] return y isa AbstractBlockTensorMap ? only(y) : y end + +# prepared operators +# ------------------ +struct PrecomputedDerivative{ + T <: Number, S <: ElementarySpace, N₁, N₂, N₃, N₄, + T1 <: AbstractTensorMap{T, S, N₁, N₂}, T2 <: AbstractTensorMap{T, S, N₃, N₄}, + B <: AbstractBackend, A, + } <: DerivativeOperator + leftenv::T1 + rightenv::T2 + backend::B + allocator::A +end + +const PrecomputedACDerivative{T, S} = PrecomputedDerivative{T, S, 3, 2, 2, 1} +const PrecomputedAC2Derivative{T, S} = PrecomputedDerivative{T, S, 3, 2, 3, 2} + +function prepare_operator!!( + H::MPO_AC_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPSTensor}, + x::MPSTensor, + backend::AbstractBackend, allocator + ) + @plansor backend = backend allocator = allocator begin + GL_O[-1 -2 -3; -4 -5] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] + end + return PrecomputedDerivative(TensorMap(GL_O), TensorMap(H.rightenv), backend, allocator), x +end + +function prepare_operator!!( + H::MPO_AC2_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPOTensor, <:MPSTensor}, + x::MPOTensor, + backend::AbstractBackend, allocator + ) + @plansor backend = backend allocator = allocator begin + GL_O[-1 -2 -3; -4 -5] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] + O_GR[-1 -2 -3; -4 -5] := H.operators[2][-3 -5; -2 1] * H.rightenv[-1 1; -4] + end + return PrecomputedDerivative(TensorMap(GL_O), TensorMap(O_GR), backend, allocator), x +end + +function (H::PrecomputedDerivative)(x::MPSTensor) + return @plansor backend = H.backend allocator = H.allocator begin + y[-1 -2; -3] ≔ H.leftenv[-1 -2 4; 1 2] * x[1 2; 3] * H.rightenv[3 4; -3] + end +end + +function (H::PrecomputedAC2Derivative)(x::MPOTensor) + return @plansor backend = H.backend allocator = H.allocator begin + y[-1 -2; -3 -4] ≔ H.leftenv[-1 -2 5; 1 2] * x[1 2; 3 4] * H.rightenv[3 4 5; -3 -4] + end +end From ee0bc384220d2429aa1b70e86d8393a0221774ff Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Mon, 3 Nov 2025 11:36:56 -0500 Subject: [PATCH 10/37] Precomputed derivatives II --- src/algorithms/derivatives/mpo_derivatives.jl | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index 201f8f965..4974b4cea 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -130,7 +130,12 @@ function prepare_operator!!( @plansor backend = backend allocator = allocator begin GL_O[-1 -2 -3; -4 -5] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] end - return PrecomputedDerivative(TensorMap(GL_O), TensorMap(H.rightenv), backend, allocator), x + leftenv = TensorMap(GL_O) + rightenv = TensorMap(H.rightenv) + BraidingStyle(sectortype(rightenv)) === NoBraiding() || + (rightenv = braid(rightenv, ((2, 1), (3,)), (1, 2, 3))) + + return PrecomputedDerivative(leftenv, rightenv, backend, allocator), x end function prepare_operator!!( @@ -142,17 +147,59 @@ function prepare_operator!!( GL_O[-1 -2 -3; -4 -5] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] O_GR[-1 -2 -3; -4 -5] := H.operators[2][-3 -5; -2 1] * H.rightenv[-1 1; -4] end - return PrecomputedDerivative(TensorMap(GL_O), TensorMap(O_GR), backend, allocator), x + leftenv = TensorMap(GL_O) + rightenv = TensorMap(O_GR) + BraidingStyle(sectortype(rightenv)) === NoBraiding() || + (rightenv = braid(rightenv, ((3, 1, 2), (4, 5)), (1, 2, 3, 4, 5))) + return PrecomputedDerivative(leftenv, rightenv, backend, allocator), x end function (H::PrecomputedDerivative)(x::MPSTensor) - return @plansor backend = H.backend allocator = H.allocator begin - y[-1 -2; -3] ≔ H.leftenv[-1 -2 4; 1 2] * x[1 2; 3] * H.rightenv[3 4; -3] + bstyle = BraidingStyle(sectortype(x)) + return _precontracted_ac_derivative(bstyle, x, H.leftenv, H.rightenv, H.backend, H.allocator) +end + +function _precontracted_ac_derivative(::NoBraiding, x, leftenv, rightenv, backend, allocator) + return @planar backend = backend allocator = allocator begin + y[-1 -2; -3] ≔ leftenv[-1 -2 4; 1 2] * x[1 2; 3] * rightenv[3 4; -3] + end +end +function _precontracted_ac_derivative(::Bosonic, x, leftenv, rightenv, backend, allocator) + return @tensor backend = backend allocator = allocator begin + y[-1 -2; -3] ≔ leftenv[-1 -2 4; 1 2] * x[1 2; 3] * rightenv[4 3; -3] + end +end +function _precontracted_ac_derivative(::BraidingStyle, x, leftenv, rightenv, backend, allocator) + @planar backend = backend allocator = allocator begin + tmp[-1 -2 -3; -4] := leftenv[-1 -2 -3; 1 2] * x[1 2; -4] + end + tmp2 = braid(tmp, ((1, 2), (3, 4)), (1, 2, 4, 3)) + return @planar backend = backend allocator = allocator begin + y[-1 -2; -3] ≔ tmp2[-1 -2; 1 2] * rightenv[1 2; -3] end end function (H::PrecomputedAC2Derivative)(x::MPOTensor) - return @plansor backend = H.backend allocator = H.allocator begin - y[-1 -2; -3 -4] ≔ H.leftenv[-1 -2 5; 1 2] * x[1 2; 3 4] * H.rightenv[3 4 5; -3 -4] + bstyle = BraidingStyle(sectortype(x)) + return _precontracted_ac2_derivative(bstyle, x, H.leftenv, H.rightenv, H.backend, H.allocator) +end + +function _precontracted_ac2_derivative(::NoBraiding, x, leftenv, rightenv, backend, allocator) + return @planar backend = backend allocator = allocator begin + y[-1 -2; -3 -4] ≔ leftenv[-1 -2 5; 1 2] * x[1 2; 3 4] * rightenv[3 4 5; -3 -4] + end +end +function _precontracted_ac2_derivative(::Bosonic, x, leftenv, rightenv, backend, allocator) + return @tensor backend = backend allocator = allocator begin + y[-1 -2; -3 -4] ≔ leftenv[-1 -2 5; 1 2] * x[1 2; 3 4] * rightenv[5 3 4; -3 -4] + end +end +function _precontracted_ac2_derivative(::BraidingStyle, x, leftenv, rightenv, backend, allocator) + @planar backend = backend allocator = allocator begin + tmp[-1 -2 -3; -4 -5] := leftenv[-1 -2 -3; 1 2] * x[1 2; -4 -5] + end + tmp2 = braid(tmp, ((1, 2), (3, 4, 5)), (1, 2, 5, 3, 4)) + return @planar backend = backend allocator = allocator begin + y[-1 -2; -3 -4] := tmp2[-1 -2; 1 2 3] * rightenv[1 2 3; -3 -4] end end From 7fbefdfb1595ed64c38b67dbdf4f26ee26646b56 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Mon, 3 Nov 2025 13:35:29 -0500 Subject: [PATCH 11/37] Precomputed derivatives III --- src/algorithms/derivatives/mpo_derivatives.jl | 107 +++++++++++------- 1 file changed, 66 insertions(+), 41 deletions(-) diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index 4974b4cea..be696a7f8 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -119,23 +119,25 @@ struct PrecomputedDerivative{ allocator::A end -const PrecomputedACDerivative{T, S} = PrecomputedDerivative{T, S, 3, 2, 2, 1} -const PrecomputedAC2Derivative{T, S} = PrecomputedDerivative{T, S, 3, 2, 3, 2} +const PrecomputedACDerivative{T, S} = PrecomputedDerivative{T, S, 2, 1, 2, 1} function prepare_operator!!( H::MPO_AC_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPSTensor}, x::MPSTensor, backend::AbstractBackend, allocator ) - @plansor backend = backend allocator = allocator begin - GL_O[-1 -2 -3; -4 -5] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] - end - leftenv = TensorMap(GL_O) - rightenv = TensorMap(H.rightenv) - BraidingStyle(sectortype(rightenv)) === NoBraiding() || - (rightenv = braid(rightenv, ((2, 1), (3,)), (1, 2, 3))) + F_left = fuser(scalartype(x), codomain(x)...) + x′ = F_left * x + + leftenv = left_precontract_derivative(H.leftenv, H.operators[1], F_left, backend, allocator) + rightenv = right_precontract_derivative(H.rightenv, backend, allocator) + + return PrecomputedDerivative(leftenv, rightenv, backend, allocator), x′ +end - return PrecomputedDerivative(leftenv, rightenv, backend, allocator), x +function unprepare_operator!!(y::MPSBondTensor, ::PrecomputedACDerivative, x::MPSTensor) + F_left = fuser(scalartype(x), codomain(x)...) + return F_left' * y end function prepare_operator!!( @@ -143,63 +145,86 @@ function prepare_operator!!( x::MPOTensor, backend::AbstractBackend, allocator ) - @plansor backend = backend allocator = allocator begin - GL_O[-1 -2 -3; -4 -5] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] - O_GR[-1 -2 -3; -4 -5] := H.operators[2][-3 -5; -2 1] * H.rightenv[-1 1; -4] - end - leftenv = TensorMap(GL_O) - rightenv = TensorMap(O_GR) - BraidingStyle(sectortype(rightenv)) === NoBraiding() || - (rightenv = braid(rightenv, ((3, 1, 2), (4, 5)), (1, 2, 3, 4, 5))) - return PrecomputedDerivative(leftenv, rightenv, backend, allocator), x + F_left = fuser(scalartype(x), codomain(x)...) + F_right = fuser(scalartype(x), domain(x)...) + x′ = F_left * x * F_right' + + leftenv = left_precontract_derivative(H.leftenv, H.operators[1], F_left, backend, allocator) + rightenv = right_precontract_derivative(H.rightenv, H.operators[2], F_right, backend, allocator) + + return PrecomputedDerivative(leftenv, rightenv, backend, allocator), x′ +end + +function unprepare_operator!!(y::MPSBondTensor, ::PrecomputedDerivative, x::MPOTensor) + F_left = fuser(scalartype(x), codomain(x)...) + F_right = fuser(scalartype(x), domain(x)...) + return F_left' * y * F_right end -function (H::PrecomputedDerivative)(x::MPSTensor) +function (H::PrecomputedDerivative)(x::MPSBondTensor) bstyle = BraidingStyle(sectortype(x)) return _precontracted_ac_derivative(bstyle, x, H.leftenv, H.rightenv, H.backend, H.allocator) end -function _precontracted_ac_derivative(::NoBraiding, x, leftenv, rightenv, backend, allocator) - return @planar backend = backend allocator = allocator begin - y[-1 -2; -3] ≔ leftenv[-1 -2 4; 1 2] * x[1 2; 3] * rightenv[3 4; -3] - end -end function _precontracted_ac_derivative(::Bosonic, x, leftenv, rightenv, backend, allocator) return @tensor backend = backend allocator = allocator begin - y[-1 -2; -3] ≔ leftenv[-1 -2 4; 1 2] * x[1 2; 3] * rightenv[4 3; -3] + y[-1; -2] ≔ leftenv[-1 3; 1] * x[1; 2] * rightenv[3 2; -2] end end function _precontracted_ac_derivative(::BraidingStyle, x, leftenv, rightenv, backend, allocator) - @planar backend = backend allocator = allocator begin - tmp[-1 -2 -3; -4] := leftenv[-1 -2 -3; 1 2] * x[1 2; -4] + return @planar backend = backend allocator = allocator begin + y[-1; -2] := leftenv[-1 2; 1] * x[1; 3] * τ'[3 2; 4 5] * rightenv[4 5; -2] end - tmp2 = braid(tmp, ((1, 2), (3, 4)), (1, 2, 4, 3)) +end +function _precontracted_ac_derivative(::NoBraiding, x, leftenv, rightenv, backend, allocator) return @planar backend = backend allocator = allocator begin - y[-1 -2; -3] ≔ tmp2[-1 -2; 1 2] * rightenv[1 2; -3] + y[-1; -2] ≔ leftenv[-1 3; 1] * x[1; 2] * rightenv[2 3; -2] end end -function (H::PrecomputedAC2Derivative)(x::MPOTensor) - bstyle = BraidingStyle(sectortype(x)) - return _precontracted_ac2_derivative(bstyle, x, H.leftenv, H.rightenv, H.backend, H.allocator) +left_precontract_derivative(arg, args...) = _left_precontract_derivative(BraidingStyle(sectortype(arg)), arg, args...) +function _left_precontract_derivative(::BraidingStyle, leftenv, operator, F, backend, allocator) + @planar backend = backend allocator = allocator begin + GL_O[-1 -2 -3; -4 -5] := leftenv[-1 1; -4] * operator[1 -2; -5 -3] + end + return @planar backend = backend allocator = allocator begin + leftenv[-1 -2; -3] := F[-1; 3 4] * TensorMap(GL_O)[3 4 -2; 1 2] * F'[1 2; -3] + end end -function _precontracted_ac2_derivative(::NoBraiding, x, leftenv, rightenv, backend, allocator) +right_precontract_derivative(arg, args...) = _right_precontract_derivative(BraidingStyle(sectortype(arg)), arg, args...) +_right_precontract_derivative(::NoBraiding, rightenv, backend, allocator) = TensorMap(rightenv) +function _right_precontract_derivative(::Bosonic, rightenv, backend, allocator) + return @tensor backend = backend allocator = allocator begin + rightenv[-2 -1; -3] := TensorMap(rightenv)[-1 -2; -3] + end +end +function _right_precontract_derivative(::BraidingStyle, rightenv, backend, allocator) return @planar backend = backend allocator = allocator begin - y[-1 -2; -3 -4] ≔ leftenv[-1 -2 5; 1 2] * x[1 2; 3 4] * rightenv[3 4 5; -3 -4] + rightenv[-1 -2; -3] := τ[-1 -2; 1 2] * TensorMap(rightenv)[1 2; -3] end end -function _precontracted_ac2_derivative(::Bosonic, x, leftenv, rightenv, backend, allocator) +function _right_precontract_derivative(::NoBraiding, rightenv, operator, F, backend, allocator) + @planar backend = backend allocator = allocator begin + O_GR[-1 -2 -3; -4 -5] := operator[-3 -5; -2 1] * rightenv[-1 1; -4] + end + return @planar backend = backend allocator = allocator begin + rightenv[-1 -2; -3] := F[-1; 3 4] * TensorMap(O_GR)[3 4 -2; 1 2] * F'[1 2; -3] + end +end +function _right_precontract_derivative(::Bosonic, rightenv, operator, F, backend, allocator) + @tensor backend = backend allocator = allocator begin + O_GR[-1 -2 -3; -4 -5] := operator[-3 -5; -2 1] * rightenv[-1 1; -4] + end return @tensor backend = backend allocator = allocator begin - y[-1 -2; -3 -4] ≔ leftenv[-1 -2 5; 1 2] * x[1 2; 3 4] * rightenv[5 3 4; -3 -4] + rightenv[-2 -1; -3] := F[-1; 3 4] * TensorMap(O_GR)[3 4 -2; 1 2] * F'[1 2; -3] end end -function _precontracted_ac2_derivative(::BraidingStyle, x, leftenv, rightenv, backend, allocator) +function _right_precontract_derivative(::BraidingStyle, rightenv, operator, F, backend, allocator) @planar backend = backend allocator = allocator begin - tmp[-1 -2 -3; -4 -5] := leftenv[-1 -2 -3; 1 2] * x[1 2; -4 -5] + O_GR[-1 -2 -3; -4 -5] := operator[-3 -5; -2 1] * rightenv[-1 1; -4] end - tmp2 = braid(tmp, ((1, 2), (3, 4, 5)), (1, 2, 5, 3, 4)) return @planar backend = backend allocator = allocator begin - y[-1 -2; -3 -4] := tmp2[-1 -2; 1 2 3] * rightenv[1 2 3; -3 -4] + rightenv[-1 -2; -3] := τ[-1 -2; 5 6] * F[5; 3 4] * TensorMap(O_GR)[3 4 6; 1 2] * F'[1 2; -3] end end From c1301f59ec35ad694c8d1aa40a00121b9cf13e20 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 4 Nov 2025 11:05:23 -0500 Subject: [PATCH 12/37] add plot script --- .gitignore | 1 + benchmark/Project.toml | 2 + benchmark/plot_results.jl | 300 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 303 insertions(+) create mode 100644 benchmark/plot_results.jl diff --git a/.gitignore b/.gitignore index b0acbe33b..8e2b6fec5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ Manifest.toml .vscode .DS_Store **/dev/ +benchmark/results diff --git a/benchmark/Project.toml b/benchmark/Project.toml index 891d982fa..5719a0f6c 100644 --- a/benchmark/Project.toml +++ b/benchmark/Project.toml @@ -2,6 +2,8 @@ BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" BlockTensorKit = "5f87ffc2-9cf1-4a46-8172-465d160bd8cd" CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" MPSKit = "bb1c41ca-d63c-52ed-829e-0820dda26502" MPSKitModels = "ca635005-6f8c-4cd1-b51d-8491250ef2ab" TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" diff --git a/benchmark/plot_results.jl b/benchmark/plot_results.jl new file mode 100644 index 000000000..1fa2af692 --- /dev/null +++ b/benchmark/plot_results.jl @@ -0,0 +1,300 @@ +using JSON +using DataFrames +using CairoMakie +using Statistics + +# Loading in the data +# ------------------- +resultdir = joinpath(@__DIR__, "results") +resultfile(i) = "results_MPSKit@bench$i.json" + +df_contract = let df = DataFrame( + :version => Int[], :model => String[], :symmetry => String[], + :D => Int[], :V => Int[], :memory => Int[], :allocs => Int[], :times => Vector{Int}[] + ) + + for version in 0:3 + result = JSON.parsefile(joinpath(resultdir, resultfile(version))) + for (model, model_res) in result.data.derivatives.data.AC2_contraction.data + for (symmetry, sym_res) in model_res.data + for (DV, bench) in sym_res.data + D, V = eval(Meta.parse(DV))::Tuple{Int, Int} + + push!( + df, + (version, model, symmetry, D, V, bench.memory, bench.allocs, collect(Int, bench.times)) + ) + end + end + end + end + df +end +df_prep = let df = DataFrame( + :version => Int[], :model => String[], :symmetry => String[], + :D => Int[], :V => Int[], :memory => Int[], :allocs => Int[], :times => Vector{Int}[] + ) + + for version in 0:3 + result = JSON.parsefile(joinpath(resultdir, resultfile(version))) + for (model, model_res) in result.data.derivatives.data.AC2_preparation.data + for (symmetry, sym_res) in model_res.data + for (DV, bench) in sym_res.data + D, V = eval(Meta.parse(DV))::Tuple{Int, Int} + + push!( + df, + (version, model, symmetry, D, V, bench.memory, bench.allocs, collect(Int, bench.times)) + ) + end + end + end + end + df +end + +# Plotting the results +# -------------------- +fontsize = 20 +estimator = median + +f_times = let f = Figure(; size = (1400, 1400)) + models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] + symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] + + + df_model = groupby(df_contract, [:model, :symmetry]) + for row in eachindex(models), col in eachindex(symmetries) + df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) + ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "Δt (μs)", yscale = log10) + @assert !isnothing(df_data) + for (k, v) in pairs(groupby(df_data, :version)) + Ds = v[!, :D] + times = estimator.(v[!, :times]) ./ 1.0e3 + I = sortperm(Ds) + scatterlines!(ax, Ds[I], times[I]; label = "v$(k.version)") + end + axislegend(ax, position = :lt) + end + + Label(f[0, 0], "times"; fontsize) + for (row, model) in enumerate(models) + Label(f[row, 0], model; rotation = pi / 2, fontsize, tellheight = false, tellwidth = false) + end + for (col, symmetry) in enumerate(symmetries) + Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) + end + + f +end +save(joinpath(resultdir, "bench_times.png"), f_times) + +f_times_relative = let f = Figure(; size = (1400, 1400)) + models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] + symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] + + + df_model = groupby(df_contract, [:model, :symmetry]) + for row in eachindex(models), col in eachindex(symmetries) + df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) + ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "Δt / Δt₀") + hlines!([1], color = :red) + @assert !isnothing(df_data) + + df_v = groupby(df_data, :version) + + v = get(df_v, (; version = 0), nothing) + Ds = v[!, :D] + times = estimator.(v[!, :times]) + I = sortperm(Ds) + times₀ = times[I] + + for (k, v) in pairs(groupby(df_data, :version)) + k.version == 0 && continue + Ds = v[!, :D] + I = sortperm(Ds) + times = estimator.(v[!, :times])[I] + scatterlines!(ax, Ds[I], times ./ times₀; label = "v$(k.version)") + end + axislegend(ax, position = :lt) + end + + Label(f[0, 0], "times"; fontsize) + for (row, model) in enumerate(models) + Label(f[row, 0], model; rotation = pi / 2, fontsize, tellheight = false, tellwidth = false) + end + for (col, symmetry) in enumerate(symmetries) + Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) + end + + f +end +save(joinpath(resultdir, "bench_times_relative.png"), f_times_relative) + +f_allocs = let f = Figure(; size = (1400, 1400)) + models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] + symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] + + + df_model = groupby(df_contract, [:model, :symmetry]) + for row in eachindex(models), col in eachindex(symmetries) + df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) + ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "allocs", yscale = log10) + @assert !isnothing(df_data) + for (k, v) in pairs(groupby(df_data, :version)) + Ds = v[!, :D] + allocs = estimator.(v[!, :allocs]) + I = sortperm(Ds) + scatterlines!(ax, Ds[I], allocs[I]; label = "v$(k.version)") + end + axislegend(ax, position = :lt) + end + + Label(f[0, 0], "allocs"; fontsize) + for (row, model) in enumerate(models) + Label(f[row, 0], model; rotation = pi / 2, fontsize, tellheight = false, tellwidth = false) + end + for (col, symmetry) in enumerate(symmetries) + Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) + end + + f +end +save(joinpath(resultdir, "bench_allocs.png"), f_allocs) + +f_memory = let f = Figure(; size = (1400, 1400)) + models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] + symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] + + + df_model = groupby(df_contract, [:model, :symmetry]) + for row in eachindex(models), col in eachindex(symmetries) + df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) + ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "memory (KiB)", yscale = log10) + @assert !isnothing(df_data) + for (k, v) in pairs(groupby(df_data, :version)) + Ds = v[!, :D] + memory = estimator.(v[!, :memory]) ./ (2^10) + I = sortperm(Ds) + scatterlines!(ax, Ds[I], memory[I]; label = "v$(k.version)") + end + axislegend(ax, position = :lt) + end + + Label(f[0, 0], "memory"; fontsize) + for (row, model) in enumerate(models) + Label(f[row, 0], model; rotation = pi / 2, fontsize, tellheight = false, tellwidth = false) + end + for (col, symmetry) in enumerate(symmetries) + Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) + end + + f +end +save(joinpath(resultdir, "bench_memory.png"), f_allocs) + +f_memory_relative = let f = Figure(; size = (1400, 1400)) + models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] + symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] + + + df_model = groupby(df_contract, [:model, :symmetry]) + for row in eachindex(models), col in eachindex(symmetries) + df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) + ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "memory / memory₀") + hlines!([1], color = :red) + @assert !isnothing(df_data) + + df_v = groupby(df_data, :version) + + v = get(df_v, (; version = 0), nothing) + Ds = v[!, :D] + times = estimator.(v[!, :memory]) + I = sortperm(Ds) + times₀ = times[I] + + for (k, v) in pairs(groupby(df_data, :version)) + k.version == 0 && continue + Ds = v[!, :D] + I = sortperm(Ds) + times = estimator.(v[!, :memory])[I] + scatterlines!(ax, Ds[I], times ./ times₀; label = "v$(k.version)") + end + axislegend(ax, position = :lt) + end + + Label(f[0, 0], "memory (relative)"; fontsize) + for (row, model) in enumerate(models) + Label(f[row, 0], model; rotation = pi / 2, fontsize, tellheight = false, tellwidth = false) + end + for (col, symmetry) in enumerate(symmetries) + Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) + end + + f +end +save(joinpath(resultdir, "bench_memory_relative.png"), f_memory_relative) + + +# Including preparation times +# --------------------------- +for n_applications in [3, 10, 30] + f_times_relative = let f = Figure(; size = (1400, 1400)) + models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] + symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] + + + df_model = groupby(df_contract, [:model, :symmetry]) + dfp_model = groupby(df_prep, [:model, :symmetry]) + for row in eachindex(models), col in eachindex(symmetries) + df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) + dfp_data = get(dfp_model, (; model = models[row], symmetry = symmetries[col]), nothing) + ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "Δt / Δt₀") + hlines!([1], color = :red) + @assert !isnothing(df_data) && !isnothing(dfp_data) + + df_v = groupby(df_data, :version) + dfp_v = groupby(dfp_data, :version) + + v = get(df_v, (; version = 0), nothing) + Ds = v[!, :D] + times = estimator.(v[!, :times]) + I = sortperm(Ds) + times₀ = n_applications .* times[I] + + vp = get(dfp_v, (; version = 0), nothing) + Ds = vp[!, :D] + times = estimator.(vp[!, :times]) + I = sortperm(Ds) + times₀ .+= times[I] + + df_data_v = groupby(dfp_data, :version) + for (k, v) in pairs(groupby(df_data, :version)) + k.version == 0 && continue + Ds = v[!, :D] + I = sortperm(Ds) + times = n_applications .* estimator.(v[!, :times])[I] + + vp = get(df_data_v, (; k.version), nothing) + @assert !isnothing(vp) + Ds = vp[!, :D] + I = sortperm(Ds) + times .+= estimator.(vp[!, :times][I]) + + scatterlines!(ax, Ds[I], times ./ times₀; label = "v$(k.version)") + end + axislegend(ax, position = :lt) + end + + Label(f[0, 0], "times"; fontsize) + for (row, model) in enumerate(models) + Label(f[row, 0], model; rotation = pi / 2, fontsize, tellheight = false, tellwidth = false) + end + for (col, symmetry) in enumerate(symmetries) + Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) + end + + f + end + save(joinpath(resultdir, "bench_prep_times_relative_n=$n_applications.png"), f_times_relative) +end From 142827387f5e1771f9270db078a7efb4bcca7901 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sun, 14 Dec 2025 08:14:24 -0500 Subject: [PATCH 13/37] Precomputed derivatives IV Revert "Precomputed derivatives III" This reverts commit d704ccf12d6027e30750878527620a1d555259fa. Precomputed derivatives IV Precomputed derivatives V reduce test terminal clutter update plots script playing around with more kernels remove piracy rework jordanmpo small fix --- benchmark/Project.toml | 2 + benchmark/plot_results.jl | 6 +- src/MPSKit.jl | 2 + src/algorithms/derivatives/derivatives.jl | 26 +- .../derivatives/hamiltonian_derivatives.jl | 365 ++++++++++++++++++ src/algorithms/derivatives/mpo_derivatives.jl | 178 +++++---- src/algorithms/fixedpoint.jl | 16 +- src/utility/multiline.jl | 4 +- src/utility/utility.jl | 109 +++++- 9 files changed, 580 insertions(+), 128 deletions(-) create mode 100644 src/algorithms/derivatives/hamiltonian_derivatives.jl diff --git a/benchmark/Project.toml b/benchmark/Project.toml index 5719a0f6c..c1f0ff408 100644 --- a/benchmark/Project.toml +++ b/benchmark/Project.toml @@ -4,7 +4,9 @@ BlockTensorKit = "5f87ffc2-9cf1-4a46-8172-465d160bd8cd" CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +MKL = "33e6dc65-8f57-5167-99aa-e5a354878fb2" MPSKit = "bb1c41ca-d63c-52ed-829e-0820dda26502" MPSKitModels = "ca635005-6f8c-4cd1-b51d-8491250ef2ab" TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" TensorKit = "07d1fe3e-3e46-537d-9eac-e9e13d0d4cec" +TensorKitManifolds = "11fa318c-39cb-4a83-b1ed-cdc7ba1e3684" diff --git a/benchmark/plot_results.jl b/benchmark/plot_results.jl index 1fa2af692..ce3857d62 100644 --- a/benchmark/plot_results.jl +++ b/benchmark/plot_results.jl @@ -8,12 +8,14 @@ using Statistics resultdir = joinpath(@__DIR__, "results") resultfile(i) = "results_MPSKit@bench$i.json" +versions = [0, 1, 2, 3, 5] + df_contract = let df = DataFrame( :version => Int[], :model => String[], :symmetry => String[], :D => Int[], :V => Int[], :memory => Int[], :allocs => Int[], :times => Vector{Int}[] ) - for version in 0:3 + for version in versions result = JSON.parsefile(joinpath(resultdir, resultfile(version))) for (model, model_res) in result.data.derivatives.data.AC2_contraction.data for (symmetry, sym_res) in model_res.data @@ -35,7 +37,7 @@ df_prep = let df = DataFrame( :D => Int[], :V => Int[], :memory => Int[], :allocs => Int[], :times => Vector{Int}[] ) - for version in 0:3 + for version in versions result = JSON.parsefile(joinpath(resultdir, resultfile(version))) for (model, model_res) in result.data.derivatives.data.AC2_preparation.data for (symmetry, sym_res) in model_res.data diff --git a/src/MPSKit.jl b/src/MPSKit.jl index 20214813d..ec9c05ae9 100644 --- a/src/MPSKit.jl +++ b/src/MPSKit.jl @@ -60,6 +60,7 @@ using Compat: @compat # ------- using TensorKit using TensorKit: BraidingTensor +using TensorKit: TupleTools as TT using MatrixAlgebraKit using MatrixAlgebraKit: TruncationStrategy, PolarViaSVD, LAPACK_SVDAlgorithm using BlockTensorKit @@ -141,6 +142,7 @@ include("environments/lazylincocache.jl") include("algorithms/fixedpoint.jl") include("algorithms/derivatives/derivatives.jl") include("algorithms/derivatives/mpo_derivatives.jl") +include("algorithms/derivatives/hamiltonian_derivatives.jl") include("algorithms/derivatives/projection_derivatives.jl") include("algorithms/expval.jl") include("algorithms/toolbox.jl") diff --git a/src/algorithms/derivatives/derivatives.jl b/src/algorithms/derivatives/derivatives.jl index 1e65c3f15..a3008c872 100644 --- a/src/algorithms/derivatives/derivatives.jl +++ b/src/algorithms/derivatives/derivatives.jl @@ -217,27 +217,15 @@ Base.:*(h::LazySum{<:Union{DerivativeOrMultiplied}}, v) = h(v) # Operator preparation # -------------------- """ - prepare_operator!!(O, x, [backend], [allocator]) -> O′, x′ + prepare_operator!!(O, [backend], [allocator]) -> O′ Given an operator and vector, try to construct a more efficient representation of that operator for repeated application. This should always be used in conjunction with [`unprepare_operator!!`](@ref). """ -function prepare_operator!!( - O, x, - backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() - ) - return O, x -end - -""" - unprepare_operator!!(y, O, x, [backend], [allocator]) -> y′ +prepare_operator!!(O, backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator()) = O -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. -This should always be used in conjunction with [`prepare_operator!!`](@ref). -""" -function unprepare_operator!!( - y, O, x, - backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() - ) - return y -end +# to make benchmark scripts run +prepare_operator!!(O, x::AbstractTensorMap, backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator()) = + prepare_operator!!(O, backend, allocator), x +unprepare_operator!!(y, O, x, backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator()) = + y diff --git a/src/algorithms/derivatives/hamiltonian_derivatives.jl b/src/algorithms/derivatives/hamiltonian_derivatives.jl new file mode 100644 index 000000000..534553580 --- /dev/null +++ b/src/algorithms/derivatives/hamiltonian_derivatives.jl @@ -0,0 +1,365 @@ +const _HAM_MPS_TYPES = Union{ + FiniteMPS{<:MPSTensor}, + WindowMPS{<:MPSTensor}, + InfiniteMPS{<:MPSTensor}, +} + +# Single site derivative +# ---------------------- +""" + JordanMPO_AC_Hamiltonian{O1,O2,O3} + +Efficient operator for representing the single-site derivative of a `MPOHamiltonian` sandwiched between two MPSs. +In particular, this operator aims to make maximal use of the structure of the `MPOHamiltonian` to reduce the number of operations required to apply the operator to a tensor. +""" +struct JordanMPO_AC_Hamiltonian{O1, O2, O3} <: DerivativeOperator + D::Union{O1, Missing} # onsite + I::Union{O1, Missing} # not started + E::Union{O1, Missing} # finished + C::Union{O2, Missing} # starting + B::Union{O2, Missing} # ending + A::Union{O3, Missing} # continuing +end + +function AC_hamiltonian( + site::Int, below::_HAM_MPS_TYPES, operator::MPOHamiltonian, above::_HAM_MPS_TYPES, envs + ) + @assert below === above "JordanMPO assumptions break" + GL = leftenv(envs, site, below) + GR = rightenv(envs, site, below) + W = operator[site] + return JordanMPO_AC_Hamiltonian(GL, W, GR) +end + +function JordanMPO_AC_Hamiltonian(GL::MPSTensor, W::JordanMPOTensor, GR::MPSTensor) + # onsite + D = nonzero_length(W.D) > 0 ? only(W.D) : missing + + # not started + I = size(W, 4) == 1 ? missing : removeunit(GR[1], 2) + + # finished + E = size(W, 1) == 1 ? missing : removeunit(GL[end], 2) + + # starting + C = if nonzero_length(W.C) > 0 + GR_2 = GR[2:(end - 1)] + @plansor starting[-1 -2; -3 -4] ≔ W.C[-1; -3 1] * GR_2[-4 1; -2] + only(starting) + else + missing + end + + # ending + B = if nonzero_length(W.B) > 0 + GL_2 = GL[2:(end - 1)] + @plansor ending[-1 -2; -3 -4] ≔ GL_2[-1 1; -3] * W.B[1 -2; -4] + only(ending) + else + missing + end + + # continuing + A = MPO_AC_Hamiltonian(GL[2:(end - 1)], W.A, GR[2:(end - 1)]) + + # obtaining storagetype of environments since these should have already mixed + # the types of the operator and state + S = spacetype(GL) + M = storagetype(GL) + O1 = tensormaptype(S, 1, 1, M) + O2 = tensormaptype(S, 2, 2, M) + O3 = typeof(A) + + # specialization for nearest neighbours + nonzero_length(W.A) == 0 && (A = missing) + + return JordanMPO_AC_Hamiltonian{O1, O2, O3}(D, I, E, C, B, A) +end + +function prepare_operator!!( + H::JordanMPO_AC_Hamiltonian{O1, O2, O3}, backend::AbstractBackend, allocator + ) where {O1, O2, O3} + C = H.C + B = H.B + + # onsite + D = if !ismissing(C) + Id = TensorKit.id(storagetype(W.D), space(C, 2)) + @plansor C[-1 -2; -3 -4] += W.D[-1; -3] * Id[-4; -2] + missing + elseif !ismissing(B) + Id = TensorKit.id(storagetype(W.D), space(B, 1)) + @plansor B[-1 -2; -3 -4] += Id[-1; -3] * W.D[-2; -4] + missing + else + W.D + end + + # not_started + I = if !ismissing(C) + Id = id(storagetype(W.I), space(C, 1)) + @plansor C[-1 -2; -3 -4] += I[-1; -3] * H.I[-4; -2] + missing + else + H.I + end + + # finished + E = if !ismissing(B) + Id = id(storagetype(W.I), space(B, 2)) + @plansor B[-1 -2; -3 -4] += H.E[-1; -3] * Id[-2; -4] + missing + else + H.E + end + + A = ismissing(H.A) ? H.A : prepare_operator!!(H.A, backend, allocator) + + O3′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O3, typeof(backend), typeof(allocator)}) + return JordanMPO_AC_Hamiltonian{O1, O2, O3′}(D, I, E, C, B, A) +end + + +# Two site derivative +# ------------------- +""" + JordanMPO_AC2_Hamiltonian{O1,O2,O3,O4} + +Efficient operator for representing the single-site derivative of a `MPOHamiltonian` sandwiched between two MPSs. +In particular, this operator aims to make maximal use of the structure of the `MPOHamiltonian` to reduce the number of operations required to apply the operator to a tensor. +""" +struct JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4} <: DerivativeOperator + II::Union{O1, Missing} # not_started + IC::Union{O2, Missing} # starting right + ID::Union{O1, Missing} # onsite right + CB::Union{O2, Missing} # starting left - ending right + CA::Union{O3, Missing} # starting left - continuing right + AB::Union{O3, Missing} # continuing left - ending right + AA::Union{O4, Missing} # continuing left - continuing right + BE::Union{O2, Missing} # ending left + DE::Union{O1, Missing} # onsite left + EE::Union{O1, Missing} # finished +end + +function AC2_hamiltonian( + site::Int, below::_HAM_MPS_TYPES, operator::MPOHamiltonian, above::_HAM_MPS_TYPES, envs + ) + @assert below === above "JordanMPO assumptions break" + GL = leftenv(envs, site, below) + GR = rightenv(envs, site + 1, below) + W1, W2 = operator[site], operator[site + 1] + return JordanMPO_AC2_Hamiltonian(GL, W1, W2, GR) +end + +function JordanMPO_AC2_Hamiltonian(GL::MPSTensor, W1::JordanMPOTensor, W2::JordanMPOTensor, GR::MPSTensor) + # not started + II = size(W2, 4) == 1 ? missing : transpose(removeunit(GR[1], 2)) + + # finished + EE = size(W1, 1) == 1 ? missing : removeunit(GL[end], 2) + + # starting right + IC = if nonzero_length(W2.C) > 0 + @plansor IC_[-1 -2; -3 -4] ≔ W2.C[-1; -3 1] * GR[2:(end - 1)][-4 1; -2] + only(IC_) + else + missing + end + + # onsite left + DE = nonzero_length(W1.D) > 0 ? only(W1.D) : missing + + # onsite right + ID = nonzero_length(W2.D) > 0 ? only(W2.D) : missing + + # starting left - ending right + CB = if nonzero_length(W1.C) > 0 && nonzero_length(W2.B) > 0 + @plansor CB_[-1 -2; -3 -4] ≔ W1.C[-1; -3 1] * W2.B[1 -2; -4] + only(CB_) + else + missing + end + + # starting left - continuing right + CA = if nonzero_length(W1.C) > 0 && nonzero_length(W2.A) > 0 + @plansor CA_[-1 -2 -3; -4 -5 -6] ≔ W1.C[-1; -4 2] * W2.A[2 -2; -5 1] * + GR[2:(end - 1)][-6 1; -3] + only(CA_) + else + missing + end + + # continuing left - ending right + AB = if nonzero_length(W1.A) > 0 && nonzero_length(W2.B) > 0 + @plansor AB_[-1 -2 -3; -4 -5 -6] ≔ GL[2:(end - 1)][-1 2; -4] * W1.A[2 -2; -5 1] * + W2.B[1 -3; -6] + only(AB_) + else + missing + end + + # ending left + BE = if nonzero_length(W1.B) > 0 + @plansor BE_[-1 -2; -3 -4] ≔ GL[2:(end - 1)][-1 2; -3] * W1.B[2 -2; -4] + only(BE_) + else + missing + end + + # continuing - continuing + AA = MPO_AC2_Hamiltonian(GL[2:(end - 1)], W1.A, W2.A, GR[2:(end - 1)]) + + S = spacetype(GL) + M = storagetype(GL) + O1 = tensormaptype(S, 1, 1, M) + O2 = tensormaptype(S, 2, 2, M) + O3 = tensormaptype(S, 3, 3, M) + O4 = typeof(AA) + + if nonzero_length(W1.A) == 0 && nonzero_length(W2.A) == 0 + AA = missing + else + mask1 = falses(size(W1.A, 1), size(W1.A, 4)) + for I in nonzero_keys(W1.A) + mask1[I[1], I[4]] = true + end + + mask2 = falses(size(W2.A, 1), size(W2.A, 4)) + for I in nonzero_keys(W2.A) + mask2[I[1], I[4]] = true + end + + mask_left = transpose(mask1) * trues(size(mask1, 1)) + mask_right = mask2 * trues(size(mask2, 2)) + all(iszero, mask_left .* mask_right) && (AA = missing) + end + + return JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4}(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) + +end + +function prepare_operator!!( + H::JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4}, backend::AbstractBackend, allocator + ) where {O1, O2, O3, O4} + + CA = H.CA + AB = H.AB + + CB = if !ismissing(CA) && !ismissing(H.CB) + Id = TensorKit.id(storagetype(H.CB), space(CA, 3)) + @plansor CA[-1 -2 -3; -4 -5 -6] += H.CB[-1 -2; -4 -5] * Id[-3; -6] + missing + elseif !ismissing(AB) && !ismissing(H.CB) + + else + H.CB + end + + # starting right + IC = if !ismissing(CA) && !ismissing(H.IC) + Id = TensorKit.id(storagetype(H.IC), space(CA, 1)) + @plansor CA[-1 -2 -3; -4 -5 -6] += Id[-1; -4] * H.IC[ -2 -3; -5 -6] + missing + else + H.IC + end + + # ending left + BE = if !ismissing(AB) && !ismissing(H.BE) + Id = TensorKit.id(storagetype(H.BE), space(AB, 3)) + @plansor AB[-1 -2 -3; -4 -5 -6] += H.BE[-1 -2; -4 -5] * Id[-3; -6] + missing + else + H.BE + end + + # onsite left + DE = if !ismissing(BE) && !ismissing(H.DE) + Id = TensorKit.id(storagetype(H.DE), space(BE, 1)) + @plansor BE[-1 -2; -3 -4] += Id[-1; -3] * H.DE[-2; -4] + missing + elseif !ismissing(AB) && !ismissing(H.DE) + Id1 = id(storagetype(H.DE), space(AB, 1)) + Id2 = id(storagetype(H.DE), space(AB, 3)) + @plansor AB[-1 -2 -3; -4 -5 -6] += Id1[-1; -4] * H.DE[-2; -5] * Id2[-3; -6] + missing + # TODO: could also try in CA? + else + H.DE + end + + # onsite right + ID = if !ismissing(IC) && !ismissing(H.ID) + Id = TensorKit.id(storagetype(H.ID), space(IC, 2)) + @plansor IC[-1 -2; -3 -4] += H.ID[-1; -3] * Id[-2; -4] + missing + elseif !ismissing(CA) && !ismissing(H.ID) + Id1 = TensorKit.id(storagetype(H.ID), space(CA, 1)) + Id2 = TensorKit.id(storagetype(H.ID), space(CA, 3)) + @plansor CA[-1 -2 -3; -4 -5 -6] += Id1[-1; -4] * H.ID[-2; -5] * Id2[-3; -6] + missing + else + H.ID + end + + # finished + II = if !ismissing(IC) && !ismissing(H.II) + I = id(storagetype(H.II), space(IC, 1)) + @plansor IC[-1 -2; -3 -4] += I[-1; -3] * H.II[-2; -4] + II = missing + elseif !ismissing(CA) && !ismissing(H.II) + I = id(storagetype(H.II), space(CA, 1) ⊗ space(CA, 2)) + @plansor CA[-1 -2 -3; -4 -5 -6] += I[-1 -2; -4 -5] * H.II[-3; -6] + II = missing + else + H.II + end + + # unstarted + EE = if !ismissing(BE) && !ismissing(H.EE) + I = id(storagetype(H.EE), space(BE, 2)) + @plansor BE[-1 -2; -3 -4] += H.EE[-1; -3] * I[-2; -4] + EE = missing + elseif !ismissing(AB) && !ismissing(H.EE) + I = id(storagetype(H.EE), space(AB, 2) ⊗ space(AB, 3)) + @plansor AB[-1 -2 -3; -4 -5 -6] += H.EE[-1; -4] * I[-2 -3; -5 -6] + EE = missing + else + H.EE + end + + O4′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O4, typeof(backend), typeof(allocator)}) + AA = prepare_operator!!(H.AA, backend, allocator) + + return JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4′}(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) +end + +# Actions +# ------- +function (H::JordanMPO_AC_Hamiltonian)(x::MPSTensor) + y = ismissing(H.A) ? zerovector(x) : H.A(x) + + ismissing(H.D) || @plansor y[-1 -2; -3] += x[-1 1; -3] * H.D[-2; 1] + ismissing(H.E) || @plansor y[-1 -2; -3] += H.E[-1; 1] * x[1 -2; -3] + ismissing(H.I) || @plansor y[-1 -2; -3] += x[-1 -2; 1] * H.I[1; -3] + ismissing(H.C) || @plansor y[-1 -2; -3] += x[-1 2; 1] * H.C[-2 -3; 2 1] + ismissing(H.B) || @plansor y[-1 -2; -3] += H.B[-1 -2; 1 2] * x[1 2; -3] + + return y +end + +function (H::JordanMPO_AC2_Hamiltonian)(x::MPOTensor) + y = ismissing(H.AA) ? zerovector(x) : H.AA(x) + + ismissing(H.II) || @plansor y[-1 -2; -3 -4] += x[-1 -2; 1 -4] * H.II[-3; 1] + ismissing(H.IC) || @plansor y[-1 -2; -3 -4] += x[-1 -2; 1 2] * H.IC[-4 -3; 2 1] + ismissing(H.ID) || @plansor y[-1 -2; -3 -4] += x[-1 -2; -3 1] * H.ID[-4; 1] + ismissing(H.CB) || @plansor y[-1 -2; -3 -4] += x[-1 1; -3 2] * H.CB[-2 -4; 1 2] + ismissing(H.CA) || @plansor y[-1 -2; -3 -4] += x[-1 1; 3 2] * H.CA[-2 -4 -3; 1 2 3] + ismissing(H.AB) || @plansor y[-1 -2; -3 -4] += x[1 2; -3 3] * H.AB[-1 -2 -4; 1 2 3] + ismissing(H.BE) || @plansor y[-1 -2; -3 -4] += x[1 2; -3 -4] * H.BE[-1 -2; 1 2] + ismissing(H.DE) || @plansor y[-1 -2; -3 -4] += x[-1 1; -3 -4] * H.DE[-2; 1] + ismissing(H.EE) || @plansor y[-1 -2; -3 -4] += x[1 -2; -3 -4] * H.EE[-1; 1] + + return y +end diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index be696a7f8..105fd5939 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -119,112 +119,108 @@ struct PrecomputedDerivative{ allocator::A end -const PrecomputedACDerivative{T, S} = PrecomputedDerivative{T, S, 2, 1, 2, 1} +const PrecomputedACDerivative{T, S} = PrecomputedDerivative{T, S, 3, 2, 2, 1} +const PrecomputedAC2Derivative{T, S} = PrecomputedDerivative{T, S, 3, 2, 3, 2} function prepare_operator!!( - H::MPO_AC_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPSTensor}, - x::MPSTensor, + H::MPO_C_Hamiltonian{<:MPSTensor, <:MPSTensor}, backend::AbstractBackend, allocator ) - F_left = fuser(scalartype(x), codomain(x)...) - x′ = F_left * x - - leftenv = left_precontract_derivative(H.leftenv, H.operators[1], F_left, backend, allocator) - rightenv = right_precontract_derivative(H.rightenv, backend, allocator) - - return PrecomputedDerivative(leftenv, rightenv, backend, allocator), x′ + leftenv = _transpose_tail(TensorMap(H.leftenv)) + rightenv = TensorMap(H.rightenv) + return PrecomputedDerivative(leftenv, rightenv, backend, allocator) end +function prepare_operator!!( + H::MPO_AC_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPSTensor}, + backend::AbstractBackend, allocator + ) + @plansor backend = backend allocator = allocator begin + GL_O[-1 -2; -4 -5 -3] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] + end + leftenv = fuse_legs(TensorMap(GL_O), 0, 2) + rightenv = TensorMap(H.rightenv) -function unprepare_operator!!(y::MPSBondTensor, ::PrecomputedACDerivative, x::MPSTensor) - F_left = fuser(scalartype(x), codomain(x)...) - return F_left' * y + return PrecomputedDerivative(leftenv, rightenv, backend, allocator) end function prepare_operator!!( H::MPO_AC2_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPOTensor, <:MPSTensor}, - x::MPOTensor, backend::AbstractBackend, allocator ) - F_left = fuser(scalartype(x), codomain(x)...) - F_right = fuser(scalartype(x), domain(x)...) - x′ = F_left * x * F_right' - - leftenv = left_precontract_derivative(H.leftenv, H.operators[1], F_left, backend, allocator) - rightenv = right_precontract_derivative(H.rightenv, H.operators[2], F_right, backend, allocator) - - return PrecomputedDerivative(leftenv, rightenv, backend, allocator), x′ -end - -function unprepare_operator!!(y::MPSBondTensor, ::PrecomputedDerivative, x::MPOTensor) - F_left = fuser(scalartype(x), codomain(x)...) - F_right = fuser(scalartype(x), domain(x)...) - return F_left' * y * F_right -end - -function (H::PrecomputedDerivative)(x::MPSBondTensor) - bstyle = BraidingStyle(sectortype(x)) - return _precontracted_ac_derivative(bstyle, x, H.leftenv, H.rightenv, H.backend, H.allocator) -end - -function _precontracted_ac_derivative(::Bosonic, x, leftenv, rightenv, backend, allocator) - return @tensor backend = backend allocator = allocator begin - y[-1; -2] ≔ leftenv[-1 3; 1] * x[1; 2] * rightenv[3 2; -2] - end -end -function _precontracted_ac_derivative(::BraidingStyle, x, leftenv, rightenv, backend, allocator) - return @planar backend = backend allocator = allocator begin - y[-1; -2] := leftenv[-1 2; 1] * x[1; 3] * τ'[3 2; 4 5] * rightenv[4 5; -2] + @plansor backend = backend allocator = allocator begin + GL_O[-1 -2; -4 -5 -3] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] + O_GR[-1 -2 -3; -4 -5] := H.operators[2][-3 -5; -2 1] * H.rightenv[-1 1; -4] end -end -function _precontracted_ac_derivative(::NoBraiding, x, leftenv, rightenv, backend, allocator) - return @planar backend = backend allocator = allocator begin - y[-1; -2] ≔ leftenv[-1 3; 1] * x[1; 2] * rightenv[2 3; -2] + leftenv = fuse_legs(GL_O isa TensorMap ? GL_O : TensorMap(GL_O), 0, 2) + rightenv = fuse_legs(O_GR isa TensorMap ? O_GR : TensorMap(O_GR), 2, 0) + return PrecomputedDerivative(leftenv, rightenv, backend, allocator) +end + + +function (H::PrecomputedDerivative)(x::AbstractTensorMap) + R_fused = fuse_legs(H.rightenv, 0, 2) + x_fused = fuse_legs(x, numout(x), numin(x)) + + # xR = matrix_contract(R_fused, x_fused, 1, One(), H.backend, H.allocator; transpose = true) + + TC = TensorOperations.promote_contract(scalartype(x_fused), scalartype(R_fused)) + xR = TensorOperations.tensoralloc_contract(TC, x_fused, ((1,), (2,)), false, R_fused, ((1,), (2, 3)), false, ((1, 2), (3,)), Val(true), H.allocator) + + structure_xR = TensorKit.fusionblockstructure(space(xR)) + structure_R = TensorKit.fusionblockstructure(space(R_fused)) + + xblocks = blocks(x_fused) + for ((f₁, f₂), i1) in structure_xR.fusiontreeindices + sz, str, offset = structure_xR.fusiontreestructure[i1] + xr = TensorKit.Strided.StridedView(xR.data, sz, str, offset) + + u = first(f₁.uncoupled) + x = TensorKit.Strided.StridedView(xblocks[u]) + isempty(x) && (zerovector!(xr); continue) + + if haskey(structure_R.fusiontreeindices, (f₁, f₂)) + @inbounds i = structure_R.fusiontreeindices[(f₁, f₂)] + @inbounds sz, str, offset = structure_R.fusiontreestructure[i] + r = TensorKit.Strided.StridedView(R_fused.data, sz, str, offset) + + # if sz[2] < sz[3] + # for k in axes(r, 2) + # C = xr[:, k, :] + # B = r[:, k, :] + # LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) + # end + # else + # for k in axes(r, 3) + # C = xr[:, :, k] + # B = r[:, :, k] + # LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) + # end + # end + + TensorOperations.tensorcontract!( + xr, x, ((1,), (2,)), false, + r, ((1,), (2, 3)), false, ((1, 2), (3,)), One(), Zero(), H.backend, H.allocator + ) + else + zerovector!(xr) + end end -end -left_precontract_derivative(arg, args...) = _left_precontract_derivative(BraidingStyle(sectortype(arg)), arg, args...) -function _left_precontract_derivative(::BraidingStyle, leftenv, operator, F, backend, allocator) - @planar backend = backend allocator = allocator begin - GL_O[-1 -2 -3; -4 -5] := leftenv[-1 1; -4] * operator[1 -2; -5 -3] - end - return @planar backend = backend allocator = allocator begin - leftenv[-1 -2; -3] := F[-1; 3 4] * TensorMap(GL_O)[3 4 -2; 1 2] * F'[1 2; -3] - end + LxR = H.leftenv * xR + return TensorMap{scalartype(LxR)}(LxR.data, codomain(H.leftenv) ← domain(H.rightenv)) end -right_precontract_derivative(arg, args...) = _right_precontract_derivative(BraidingStyle(sectortype(arg)), arg, args...) -_right_precontract_derivative(::NoBraiding, rightenv, backend, allocator) = TensorMap(rightenv) -function _right_precontract_derivative(::Bosonic, rightenv, backend, allocator) - return @tensor backend = backend allocator = allocator begin - rightenv[-2 -1; -3] := TensorMap(rightenv)[-1 -2; -3] - end -end -function _right_precontract_derivative(::BraidingStyle, rightenv, backend, allocator) - return @planar backend = backend allocator = allocator begin - rightenv[-1 -2; -3] := τ[-1 -2; 1 2] * TensorMap(rightenv)[1 2; -3] - end -end -function _right_precontract_derivative(::NoBraiding, rightenv, operator, F, backend, allocator) - @planar backend = backend allocator = allocator begin - O_GR[-1 -2 -3; -4 -5] := operator[-3 -5; -2 1] * rightenv[-1 1; -4] - end - return @planar backend = backend allocator = allocator begin - rightenv[-1 -2; -3] := F[-1; 3 4] * TensorMap(O_GR)[3 4 -2; 1 2] * F'[1 2; -3] - end -end -function _right_precontract_derivative(::Bosonic, rightenv, operator, F, backend, allocator) - @tensor backend = backend allocator = allocator begin - O_GR[-1 -2 -3; -4 -5] := operator[-3 -5; -2 1] * rightenv[-1 1; -4] - end - return @tensor backend = backend allocator = allocator begin - rightenv[-2 -1; -3] := F[-1; 3 4] * TensorMap(O_GR)[3 4 -2; 1 2] * F'[1 2; -3] - end -end -function _right_precontract_derivative(::BraidingStyle, rightenv, operator, F, backend, allocator) - @planar backend = backend allocator = allocator begin - O_GR[-1 -2 -3; -4 -5] := operator[-3 -5; -2 1] * rightenv[-1 1; -4] - end - return @planar backend = backend allocator = allocator begin - rightenv[-1 -2; -3] := τ[-1 -2; 5 6] * F[5; 3 4] * TensorMap(O_GR)[3 4 6; 1 2] * F'[1 2; -3] - end +const _ToPrepare = Union{ + MPO_C_Hamiltonian{<:MPSTensor, <:MPSTensor}, + MPO_AC_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPSTensor}, + MPO_AC2_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPOTensor, <:MPSTensor}, +} + +function prepare_operator!!(H::Multiline{<:_ToPrepare}, backend::AbstractBackend, allocator) + return Multiline(map(x -> prepare_operator!!(x, backend, allocator), parent(H))) end + +fixedpoint(A::Union{_ToPrepare, Multiline{<:_ToPrepare}}, x₀, which::Symbol, alg::Lanczos) = + fixedpoint(prepare_operator!!(A), x₀, which, alg) +fixedpoint(A::Union{_ToPrepare, Multiline{<:_ToPrepare}}, x₀, which::Symbol, alg::Arnoldi) = + fixedpoint(prepare_operator!!(A), x₀, which, alg) diff --git a/src/algorithms/fixedpoint.jl b/src/algorithms/fixedpoint.jl index 9846624e4..2248d416d 100644 --- a/src/algorithms/fixedpoint.jl +++ b/src/algorithms/fixedpoint.jl @@ -8,30 +8,22 @@ Compute the fixed point of a linear operator `A` using the specified eigensolver fixedpoint is assumed to be unique. """ function fixedpoint(A, x₀, which::Symbol, alg::Lanczos) - A′, x₀′ = prepare_operator!!(A, x₀) - vals, vecs, info = eigsolve(A′, x₀′, 1, which, alg) + vals, vecs, info = eigsolve(A, x₀, 1, which, alg) info.converged == 0 && @warnv 1 "fixed point not converged after $(info.numiter) iterations: normres = $(info.normres[1])" - λ = vals[1] - v = unprepare_operator!!(vecs[1], A′, x₀) - - return λ, v + return vals[1], vecs[1] end function fixedpoint(A, x₀, which::Symbol, alg::Arnoldi) - A′, x₀′ = prepare_operator!!(A, x₀) - TT, vecs, vals, info = schursolve(A′, x₀′, 1, which, alg) + TT, vecs, vals, info = schursolve(A, x₀, 1, which, alg) info.converged == 0 && @warnv 1 "fixed point not converged after $(info.numiter) iterations: normres = $(info.normres[1])" size(TT, 2) > 1 && TT[2, 1] != 0 && @warnv 1 "non-unique fixed point detected" - λ = vals[1] - v = unprepare_operator!!(vecs[1], A′, x₀) - - return λ, v + return vals[1], vecs[1] end function fixedpoint(A, x₀, which::Symbol; kwargs...) diff --git a/src/utility/multiline.jl b/src/utility/multiline.jl index a1c861ff1..ebcff438f 100644 --- a/src/utility/multiline.jl +++ b/src/utility/multiline.jl @@ -12,7 +12,7 @@ See also: [`MultilineMPS`](@ref) and [`MultilineMPO`](@ref) struct Multiline{T} data::PeriodicArray{T, 1} function Multiline{T}(data::AbstractVector{T}) where {T} - @assert allequal(length.(data)) "All lines must have the same length" + # @assert allequal(length.(data)) "All lines must have the same length" return new{T}(data) end end @@ -22,7 +22,7 @@ Multiline(data::AbstractVector{T}) where {T} = Multiline{T}(data) # ----------------------- Base.parent(m::Multiline) = m.data Base.size(m::Multiline) = (length(parent(m)), length(parent(m)[1])) -Base.size(m::Multiline, i::Int) = getindex(size(m), i) +Base.size(m::Multiline, i::Int) = i == 1 ? length(parent(m)) : i == 2 ? length(parent(m)[1]) : error() Base.length(m::Multiline) = prod(size(m)) function Base.axes(m::Multiline, i::Int) return i == 1 ? axes(parent(m), 1) : diff --git a/src/utility/utility.jl b/src/utility/utility.jl index 017a0a029..e5a8d4ccd 100644 --- a/src/utility/utility.jl +++ b/src/utility/utility.jl @@ -8,8 +8,8 @@ function _transpose_as(t1::AbstractTensorMap, t2::AbstractTensorMap; copy::Bool return repartition(t1, numout(t2), numin(t2); copy) end -_mul_front(C, A) = _transpose_front(C * _transpose_tail(A)) -_mul_tail(A, C) = A * C +_mul_front(C, A) = matrix_contract(A, C, 1; transpose = true) # _transpose_front(C * _transpose_tail(A)) +_mul_tail(A, C) = matrix_contract(A, C, numind(A)) # A * C function _similar_tail(A::AbstractTensorMap) cod = _firstspace(A) @@ -144,3 +144,108 @@ function check_unambiguous_braiding(V::VectorSpace) return check_unambiguous_braiding(Bool, V) || throw(ArgumentError("cannot unambiguously braid $V")) end + +""" + matrix_contract( + A::AbstractTensorMap, B::AbstractTensorMap{T, S, 1, 1}, i::Int, + α::Number = One(), + backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator(); + transpose::Bool = false + ) + +Compute the tensor contraction `α * A * B`, where the (1, 1) - tensor `B` is attached to index `i` of `A`. +Whenever `transpose = true`, this contraction (lazily) uses `transpose(B)` instead. + +See also [`matrix_contract!`](@ref). +""" +function matrix_contract( + A::AbstractTensorMap, B::AbstractTensorMap{<:Any, <:Any, 1, 1}, i::Int, + α::Number = One(), backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator(); + transpose::Bool = false + ) + if i <= numout(A) + cod = ProductSpace(TT.setindex(codomain(A).spaces, space(B, transpose ? 1 : 2), i)) + dom = domain(A) + else + cod = codomain(A) + dom = ProductSpace(TT.setindex(domain(A).spaces, space(B, transpose ? 1 : 2)', i - numout(A))) + end + T = TensorOperations.promote_contract(scalartype(A), scalartype(B), scalartype(α)) + C = similar(A, T, cod ← dom) + return matrix_contract!(C, A, B, i, α, Zero(), backend, allocator; transpose) +end + +""" + matrix_contract!( + C::AbstractTensorMap, A::AbstractTensorMap, B::AbstractTensorMap{T, S, 1, 1}, i::Int, + α::Number = One(), β::Number = Zero(), + backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator(); + transpose::Bool = false + ) + +Compute the tensor contraction `C ← β * C + α * A * B`, where the (1, 1) - tensor `B` is attached to index `i` of `A`, +and the result is added into `C`. Whenever `transpose = true`, this contraction (lazily) uses `transpose(B)` instead. + +See also [`matrix_contract`](@ref). +""" +function matrix_contract!( + C::AbstractTensorMap, A::AbstractTensorMap, B::AbstractTensorMap{<:Any, <:Any, 1, 1}, i::Int, + α::Number = One(), β::Number = Zero(), + backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator(); + transpose::Bool = false + ) + + @boundscheck for k in 1:numind(C) + numin(C) == numin(A) && numout(C) == numout(A) || throw(ArgumentError("Invalid number of dimensions")) + if k == i + space(C, k) == space(B, transpose ? 1 : 2) || throw(SpaceMismatch()) + space(A, k) == space(B, transpose ? 2 : 1)' || throw(SpaceMismatch()) + else + space(C, k) == space(A, k) || throw(SpaceMismatch()) + end + end + + N, N₁ = numind(C), numout(C) + pA = (TT.deleteat(ntuple(identity, N), i), (i,)) + pB = transpose ? ((2,), (1,)) : ((1,), (2,)) + pAB = TensorKit._canonicalize(TT.insertafter(ntuple(identity, N - 1), i - 1, (N,)), C) + + Bblocks = blocks(B) + for ((f₁, f₂), c) in subblocks(C) + uncoupled_i = i <= N₁ ? f₁.uncoupled[i] : f₂.uncoupled[i - N₁] + transpose && (uncoupled_i = dual(uncoupled_i)) + if TensorKit.hasblock(B, uncoupled_i) + a = A[f₁, f₂] + b = Bblocks[uncoupled_i] + TensorOperations.tensorcontract!(c, a, pA, false, b, pB, false, pAB, α, β, backend, allocator) + else + scale!(c, β) + end + end + + return C +end + +@inline fuse_legs(x::TensorMap, N₁::Int, N₂::Int) = fuse_legs(x, Val(N₁), Val(N₂)) +function fuse_legs(x::TensorMap, ::Val{N₁}, ::Val{N₂}) where {N₁, N₂} + ((0 <= N₁ <= numout(x)) && (0 <= N₂ <= numin(x))) || throw(ArgumentError("invalid fusing scheme")) + init = one(spacetype(x)) + + cod = if N₁ > 1 + cod_spaces = codomain(x).spaces + fuse(prod(TT.getindices(cod_spaces, ntuple(identity, N₁)))) ⊗ + prod(TT.getindices(cod_spaces, ntuple(i -> i + N₁, numout(x) - N₁)); init) + else + codomain(x) + end + + dom = if N₂ > 1 + dom_spaces = domain(x).spaces + dom = fuse(prod(TT.getindices(dom_spaces, ntuple(identity, N₂)); init)) ⊗ + prod(TT.getindices(domain(x).spaces, ntuple(i -> i + N₂, numin(x) - N₂)); init) + else + domain(x) + end + + return TensorMap{scalartype(x)}(x.data, cod ← dom) +end From 2cb10f5db71f47746f7dc1ccf50dd3a6182190cc Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 16 Dec 2025 16:43:21 -0500 Subject: [PATCH 14/37] rework benchmarks --- .../derivatives/AC2_benchmarks.jl | 47 +++++++++++++------ .../derivatives/DerivativesBenchmarks.jl | 6 ++- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl b/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl index f302a0435..b7aeb8e68 100644 --- a/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl +++ b/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl @@ -20,9 +20,10 @@ benchname(spec::AC2Spec) = dim(spec.mps_virtualspaces[1]), dim(spec.mpo_virtuals # Benchmarks # ---------- -function MPSKit.MPO_AC2_Hamiltonian(spec::AC2Spec{S}; T::Type = Float64) where {S} +function MPSKit.AC2_hamiltonian(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 @@ -35,27 +36,45 @@ function MPSKit.MPO_AC2_Hamiltonian(spec::AC2Spec{S}; T::Type = Float64) where { 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) - return MPSKit.MPO_AC2_Hamiltonian(GL, W1, W2, GR) + GLs, GRs = MPSKit.initialize_environments(psi, H, psi) + envs = MPSKit.InfiniteEnvironments(GLs, GRs) + + return MPSKit.AC2_hamiltonian(1, psi, H, psi, envs) end function contraction_benchmark(spec::AC2Spec; T::Type = Float64) - AA = randn(T, spec.mps_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[3] ⊗ spec.physicalspaces[2]') - H_eff = MPSKit.MPO_AC2_Hamiltonian(spec; T) - H_prep, x_prep = MPSKit.prepare_operator!!(H_eff, AA) - init() = randn!(similar(x_prep)) - - return @benchmarkable $H_prep * x setup = (x = $init()) + V = spec.mps_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[3] ⊗ spec.physicalspaces[2]' + H_eff = MPSKit.AC2_hamiltonian(spec; T) + return @benchmarkable $H_eff * x setup = x = randn($T, $V) end function preparation_benchmark(spec::AC2Spec; T::Type = Float64) - init() = randn(T, spec.mps_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[3] ⊗ spec.physicalspaces[2]') - H_eff = MPSKit.MPO_AC2_Hamiltonian(spec; T) + V = spec.mps_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[3] ⊗ spec.physicalspaces[2]' + H_eff = MPSKit.AC2_hamiltonian(spec; T) + return @benchmarkable MPSKit.prepare_operator!!($H_eff) +end - return @benchmarkable begin - O′, x′ = MPSKit.prepare_operator!!($H_eff, x) - y = MPSKit.unprepare_operator!!(x′, O′, x) - end setup = (x = $init()) +function prepared_benchmark(spec::AC2Spec; T::Type = Float64) + V = spec.mps_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[3] ⊗ spec.physicalspaces[2]' + H_eff = MPSKit.AC2_hamiltonian(spec; T) + H_prep = MPSKit.prepare_operator!!(H_eff) + return @benchmarkable $H_prep * x setup = x = randn($T, $V) end # Converters diff --git a/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl index db1cf8ecb..0b423dcf2 100644 --- a/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl +++ b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl @@ -25,18 +25,22 @@ T = Float64 suite_init = addgroup!(SUITE, "AC2_preparation") suite_apply = addgroup!(SUITE, "AC2_contraction") +suite_prepped = addgroup!(SUITE, "AC2_prepared") for (model, params) in allparams g_prep = addgroup!(suite_init, model) + g_prepped = addgroup!(suite_prepped, 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) + g_prepped_sym = addgroup!(g_prepped, symmetry) for spec_dict in specs spec = untomlify(AC2Spec, spec_dict) name = benchname(spec) - g_prep_sym[name] = preparation_benchmark(spec; T) g_contract_sym[name] = contraction_benchmark(spec; T) + g_prep_sym[name] = preparation_benchmark(spec; T) + g_prepped_sym[name] = prepared_benchmark(spec; T) end end end From 13132ab3115f36382073e0efde6611ee35ad11c0 Mon Sep 17 00:00:00 2001 From: lkdvos Date: Tue, 16 Dec 2025 17:00:37 -0500 Subject: [PATCH 15/37] temporary revert --- .../derivatives/hamiltonian_derivatives.jl | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/algorithms/derivatives/hamiltonian_derivatives.jl b/src/algorithms/derivatives/hamiltonian_derivatives.jl index 534553580..80e7650da 100644 --- a/src/algorithms/derivatives/hamiltonian_derivatives.jl +++ b/src/algorithms/derivatives/hamiltonian_derivatives.jl @@ -113,9 +113,11 @@ function prepare_operator!!( H.E end - A = ismissing(H.A) ? H.A : prepare_operator!!(H.A, backend, allocator) + # O3′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O3, typeof(backend), typeof(allocator)}) + # A = ismissing(H.A) ? H.A : prepare_operator!!(H.A, backend, allocator) + O3′ = O3 + A = H.A - O3′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O3, typeof(backend), typeof(allocator)}) return JordanMPO_AC_Hamiltonian{O1, O2, O3′}(D, I, E, C, B, A) end @@ -328,8 +330,10 @@ function prepare_operator!!( H.EE end - O4′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O4, typeof(backend), typeof(allocator)}) - AA = prepare_operator!!(H.AA, backend, allocator) + # O4′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O4, typeof(backend), typeof(allocator)}) + # AA = ismissing(H.AA) ? H.AA : prepare_operator!!(H.AA, backend, allocator) + O4′ = O4 + AA = H.AA return JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4′}(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) end From d0ad7e6f5dd7f73862b30bf2293af3956297c2a6 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 16 Dec 2025 17:08:35 -0500 Subject: [PATCH 16/37] Avoid copy in matrix contract This reverts commit c9db523d604969274255c7e6fac55d12a63bea2b. --- .../derivatives/hamiltonian_derivatives.jl | 12 +++---- src/algorithms/derivatives/mpo_derivatives.jl | 36 +++++++++---------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/algorithms/derivatives/hamiltonian_derivatives.jl b/src/algorithms/derivatives/hamiltonian_derivatives.jl index 80e7650da..5015575e5 100644 --- a/src/algorithms/derivatives/hamiltonian_derivatives.jl +++ b/src/algorithms/derivatives/hamiltonian_derivatives.jl @@ -113,10 +113,8 @@ function prepare_operator!!( H.E end - # O3′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O3, typeof(backend), typeof(allocator)}) - # A = ismissing(H.A) ? H.A : prepare_operator!!(H.A, backend, allocator) - O3′ = O3 - A = H.A + O3′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O3, typeof(backend), typeof(allocator)}) + A = ismissing(H.A) ? H.A : prepare_operator!!(H.A, backend, allocator) return JordanMPO_AC_Hamiltonian{O1, O2, O3′}(D, I, E, C, B, A) end @@ -330,10 +328,8 @@ function prepare_operator!!( H.EE end - # O4′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O4, typeof(backend), typeof(allocator)}) - # AA = ismissing(H.AA) ? H.AA : prepare_operator!!(H.AA, backend, allocator) - O4′ = O4 - AA = H.AA + O4′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O4, typeof(backend), typeof(allocator)}) + AA = prepare_operator!!(H.AA, backend, allocator) return JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4′}(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) end diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index 105fd5939..1b880d6e9 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -183,24 +183,24 @@ function (H::PrecomputedDerivative)(x::AbstractTensorMap) @inbounds sz, str, offset = structure_R.fusiontreestructure[i] r = TensorKit.Strided.StridedView(R_fused.data, sz, str, offset) - # if sz[2] < sz[3] - # for k in axes(r, 2) - # C = xr[:, k, :] - # B = r[:, k, :] - # LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) - # end - # else - # for k in axes(r, 3) - # C = xr[:, :, k] - # B = r[:, :, k] - # LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) - # end - # end - - TensorOperations.tensorcontract!( - xr, x, ((1,), (2,)), false, - r, ((1,), (2, 3)), false, ((1, 2), (3,)), One(), Zero(), H.backend, H.allocator - ) + if TensorOperations.isblascontractable(r, ((1,), (2, 3))) && + TensorOperations.isblasdestination(xr, ((1,), (2, 3))) + C = TensorKit.Strided.sreshape(xr, size(xr, 1), size(xr, 2) * size(xr, 3)) + B = TensorKit.Strided.sreshape(r, size(r, 1), size(r, 2) * size(r, 3)) + LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) + elseif sz[2] < sz[3] + for k in axes(r, 2) + C = xr[:, k, :] + B = r[:, k, :] + LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) + end + else + for k in axes(r, 3) + C = xr[:, :, k] + B = r[:, :, k] + LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) + end + end else zerovector!(xr) end From 3250a6a84b8657bf2a83e7518459dcfc59501b04 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 16 Dec 2025 23:04:51 -0500 Subject: [PATCH 17/37] Add buffer allocator --- src/MPSKit.jl | 1 + src/algorithms/derivatives/derivatives.jl | 6 +- src/algorithms/derivatives/mpo_derivatives.jl | 99 ++++++++++--------- src/utility/allocator.jl | 67 +++++++++++++ 4 files changed, 124 insertions(+), 49 deletions(-) create mode 100644 src/utility/allocator.jl diff --git a/src/MPSKit.jl b/src/MPSKit.jl index ec9c05ae9..96ed23cb4 100644 --- a/src/MPSKit.jl +++ b/src/MPSKit.jl @@ -99,6 +99,7 @@ include("utility/logging.jl") using .IterativeLoggers include("utility/iterativesolvers.jl") +include("utility/allocator.jl") include("utility/styles.jl") include("utility/periodicarray.jl") include("utility/windowarray.jl") diff --git a/src/algorithms/derivatives/derivatives.jl b/src/algorithms/derivatives/derivatives.jl index a3008c872..4eac14c40 100644 --- a/src/algorithms/derivatives/derivatives.jl +++ b/src/algorithms/derivatives/derivatives.jl @@ -222,10 +222,10 @@ Base.:*(h::LazySum{<:Union{DerivativeOrMultiplied}}, v) = h(v) Given an operator and vector, try to construct a more efficient representation of that operator for repeated application. This should always be used in conjunction with [`unprepare_operator!!`](@ref). """ -prepare_operator!!(O, backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator()) = O +prepare_operator!!(O, backend::AbstractBackend = DefaultBackend(), allocator = GrowingBuffer()) = O # to make benchmark scripts run -prepare_operator!!(O, x::AbstractTensorMap, backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator()) = +prepare_operator!!(O, x::AbstractTensorMap, backend::AbstractBackend = DefaultBackend(), allocator = GrowingBuffer()) = prepare_operator!!(O, backend, allocator), x -unprepare_operator!!(y, O, x, backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator()) = +unprepare_operator!!(y, O, x, backend::AbstractBackend = DefaultBackend(), allocator = GrowingBuffer()) = y diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index 1b880d6e9..e8aa1727b 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -134,9 +134,11 @@ function prepare_operator!!( H::MPO_AC_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPSTensor}, backend::AbstractBackend, allocator ) + cp = checkpoint(allocator) @plansor backend = backend allocator = allocator begin GL_O[-1 -2; -4 -5 -3] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] end + reset!(allocator, cp) leftenv = fuse_legs(TensorMap(GL_O), 0, 2) rightenv = TensorMap(H.rightenv) @@ -147,10 +149,13 @@ function prepare_operator!!( H::MPO_AC2_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPOTensor, <:MPSTensor}, backend::AbstractBackend, allocator ) + cp = checkpoint(allocator) @plansor backend = backend allocator = allocator begin GL_O[-1 -2; -4 -5 -3] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] O_GR[-1 -2 -3; -4 -5] := H.operators[2][-3 -5; -2 1] * H.rightenv[-1 1; -4] end + reset!(allocator, cp) + leftenv = fuse_legs(GL_O isa TensorMap ? GL_O : TensorMap(GL_O), 0, 2) rightenv = fuse_legs(O_GR isa TensorMap ? O_GR : TensorMap(O_GR), 2, 0) return PrecomputedDerivative(leftenv, rightenv, backend, allocator) @@ -158,55 +163,62 @@ end function (H::PrecomputedDerivative)(x::AbstractTensorMap) - R_fused = fuse_legs(H.rightenv, 0, 2) + allocator = H.allocator + cp = checkpoint(allocator) + + R_fused = fuse_legs(H.rightenv, 0, numin(x)) x_fused = fuse_legs(x, numout(x), numin(x)) - # xR = matrix_contract(R_fused, x_fused, 1, One(), H.backend, H.allocator; transpose = true) TC = TensorOperations.promote_contract(scalartype(x_fused), scalartype(R_fused)) xR = TensorOperations.tensoralloc_contract(TC, x_fused, ((1,), (2,)), false, R_fused, ((1,), (2, 3)), false, ((1, 2), (3,)), Val(true), H.allocator) - structure_xR = TensorKit.fusionblockstructure(space(xR)) - structure_R = TensorKit.fusionblockstructure(space(R_fused)) - - xblocks = blocks(x_fused) - for ((f₁, f₂), i1) in structure_xR.fusiontreeindices - sz, str, offset = structure_xR.fusiontreestructure[i1] - xr = TensorKit.Strided.StridedView(xR.data, sz, str, offset) - - u = first(f₁.uncoupled) - x = TensorKit.Strided.StridedView(xblocks[u]) - isempty(x) && (zerovector!(xr); continue) - - if haskey(structure_R.fusiontreeindices, (f₁, f₂)) - @inbounds i = structure_R.fusiontreeindices[(f₁, f₂)] - @inbounds sz, str, offset = structure_R.fusiontreestructure[i] - r = TensorKit.Strided.StridedView(R_fused.data, sz, str, offset) - - if TensorOperations.isblascontractable(r, ((1,), (2, 3))) && - TensorOperations.isblasdestination(xr, ((1,), (2, 3))) - C = TensorKit.Strided.sreshape(xr, size(xr, 1), size(xr, 2) * size(xr, 3)) - B = TensorKit.Strided.sreshape(r, size(r, 1), size(r, 2) * size(r, 3)) - LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) - elseif sz[2] < sz[3] - for k in axes(r, 2) - C = xr[:, k, :] - B = r[:, k, :] - LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) - end - else - for k in axes(r, 3) - C = xr[:, :, k] - B = r[:, :, k] - LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) - end - end - else - zerovector!(xr) - end - end + matrix_contract!(xR, R_fused, x_fused, 1, One(), Zero(), H.backend, H.allocator; transpose = true) + + # structure_xR = TensorKit.fusionblockstructure(space(xR)) + # structure_R = TensorKit.fusionblockstructure(space(R_fused)) + + # xblocks = blocks(x_fused) + # for ((f₁, f₂), i1) in structure_xR.fusiontreeindices + # sz, str, offset = structure_xR.fusiontreestructure[i1] + # xr = TensorKit.Strided.StridedView(xR.data, sz, str, offset) + + # u = first(f₁.uncoupled) + # x = TensorKit.Strided.StridedView(xblocks[u]) + # isempty(x) && (zerovector!(xr); continue) + + # if haskey(structure_R.fusiontreeindices, (f₁, f₂)) + # @inbounds i = structure_R.fusiontreeindices[(f₁, f₂)] + # @inbounds sz, str, offset = structure_R.fusiontreestructure[i] + # r = TensorKit.Strided.StridedView(R_fused.data, sz, str, offset) + + # if TensorOperations.isblascontractable(r, ((1,), (2, 3))) && + # TensorOperations.isblasdestination(xr, ((1,), (2, 3))) + # C = TensorKit.Strided.sreshape(xr, size(xr, 1), size(xr, 2) * size(xr, 3)) + # B = TensorKit.Strided.sreshape(r, size(r, 1), size(r, 2) * size(r, 3)) + # LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) + # elseif sz[2] < sz[3] + # for k in axes(r, 2) + # C = xr[:, k, :] + # B = r[:, k, :] + # LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) + # end + # else + # for k in axes(r, 3) + # C = xr[:, :, k] + # B = r[:, :, k] + # LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) + # end + # end + # else + # zerovector!(xr) + # end + # end LxR = H.leftenv * xR + TensorOperations.tensorfree!(xR, H.allocator) + + reset!(allocator, cp) return TensorMap{scalartype(LxR)}(LxR.data, codomain(H.leftenv) ← domain(H.rightenv)) end @@ -219,8 +231,3 @@ const _ToPrepare = Union{ function prepare_operator!!(H::Multiline{<:_ToPrepare}, backend::AbstractBackend, allocator) return Multiline(map(x -> prepare_operator!!(x, backend, allocator), parent(H))) end - -fixedpoint(A::Union{_ToPrepare, Multiline{<:_ToPrepare}}, x₀, which::Symbol, alg::Lanczos) = - fixedpoint(prepare_operator!!(A), x₀, which, alg) -fixedpoint(A::Union{_ToPrepare, Multiline{<:_ToPrepare}}, x₀, which::Symbol, alg::Arnoldi) = - fixedpoint(prepare_operator!!(A), x₀, which, alg) diff --git a/src/utility/allocator.jl b/src/utility/allocator.jl new file mode 100644 index 000000000..f9dc1a482 --- /dev/null +++ b/src/utility/allocator.jl @@ -0,0 +1,67 @@ +@static if isdefined(Core, :Memory) + BufType = Memory{UInt8} +else + BufType = Vector{UInt8} +end + +const DEFAULT_SIZEHINT = 2^20 # 1MB + +mutable struct GrowingBuffer + buffer::BufType + offset::UInt + function GrowingBuffer(; sizehint = DEFAULT_SIZEHINT) + buffer = BufType(undef, sizehint) + return new(buffer, zero(UInt)) + end +end + +Base.length(buffer::GrowingBuffer) = length(buffer.buffer) +Base.pointer(buffer::GrowingBuffer) = pointer(buffer.buffer) + buffer.offset + +function Base.sizehint!(buffer::GrowingBuffer, n::Integer; shrink::Bool = false) + n > 0 || throw(ArgumentError("invalid new buffer size")) + buffer.offset == 0 || error("cannot resize a buffer that is not fully reset") + + n = shrink ? max(n, length(buffer)) : n + n = Int(Base.nextpow(2, n)) + + @static if isdefined(Core, :Memory) + buffer.buffer = BufType(undef, n) + else + sizehint!(buffer.buffer, n) + end + return buffer +end + +checkpoint(buffer) = zero(UInt) +reset!(buffer, checkpoint::UInt = zero(UInt)) = buffer + +checkpoint(buffer::GrowingBuffer) = buffer.offset + +function reset!(buffer::GrowingBuffer, checkpoint::UInt = zero(UInt)) + if iszero(checkpoint) && buffer.offset > length(buffer) + # full reset - check for need to grow + newlength = Base.nextpow(2, buffer.offset) # round to nearest larger power of 2 + buffer.offset = checkpoint + sizehint!(buffer, newlength) + else + buffer.offset = checkpoint + end + return buffer +end + +# Allocating +# ---------- +function TensorOperations.tensoralloc( + ::Type{A}, structure, ::Val{istemp}, buffer::GrowingBuffer + ) where {A <: AbstractArray, istemp} + T = eltype(A) + if istemp + ptr = convert(Ptr{T}, pointer(buffer)) + buffer.offset += prod(structure) * sizeof(T) + buffer.offset < length(buffer) && + return Base.unsafe_wrap(Array, ptr, structure) + end + return A(undef, structure) +end +TensorOperations.tensorfree!(::AbstractArray, ::GrowingBuffer) = nothing From 2b7e4d2fdef5d3fe2501a6a6dd62a7e224558378 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 16 Dec 2025 23:28:54 -0500 Subject: [PATCH 18/37] clean up code --- src/algorithms/derivatives/mpo_derivatives.jl | 42 +------- src/utility/utility.jl | 100 +++++++++++++++++- 2 files changed, 99 insertions(+), 43 deletions(-) diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index e8aa1727b..2d714f342 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -173,47 +173,7 @@ function (H::PrecomputedDerivative)(x::AbstractTensorMap) TC = TensorOperations.promote_contract(scalartype(x_fused), scalartype(R_fused)) xR = TensorOperations.tensoralloc_contract(TC, x_fused, ((1,), (2,)), false, R_fused, ((1,), (2, 3)), false, ((1, 2), (3,)), Val(true), H.allocator) - matrix_contract!(xR, R_fused, x_fused, 1, One(), Zero(), H.backend, H.allocator; transpose = true) - - # structure_xR = TensorKit.fusionblockstructure(space(xR)) - # structure_R = TensorKit.fusionblockstructure(space(R_fused)) - - # xblocks = blocks(x_fused) - # for ((f₁, f₂), i1) in structure_xR.fusiontreeindices - # sz, str, offset = structure_xR.fusiontreestructure[i1] - # xr = TensorKit.Strided.StridedView(xR.data, sz, str, offset) - - # u = first(f₁.uncoupled) - # x = TensorKit.Strided.StridedView(xblocks[u]) - # isempty(x) && (zerovector!(xr); continue) - - # if haskey(structure_R.fusiontreeindices, (f₁, f₂)) - # @inbounds i = structure_R.fusiontreeindices[(f₁, f₂)] - # @inbounds sz, str, offset = structure_R.fusiontreestructure[i] - # r = TensorKit.Strided.StridedView(R_fused.data, sz, str, offset) - - # if TensorOperations.isblascontractable(r, ((1,), (2, 3))) && - # TensorOperations.isblasdestination(xr, ((1,), (2, 3))) - # C = TensorKit.Strided.sreshape(xr, size(xr, 1), size(xr, 2) * size(xr, 3)) - # B = TensorKit.Strided.sreshape(r, size(r, 1), size(r, 2) * size(r, 3)) - # LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) - # elseif sz[2] < sz[3] - # for k in axes(r, 2) - # C = xr[:, k, :] - # B = r[:, k, :] - # LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) - # end - # else - # for k in axes(r, 3) - # C = xr[:, :, k] - # B = r[:, :, k] - # LinearAlgebra.BLAS.gemm!('N', 'N', one(TC), x, B, zero(TC), C) - # end - # end - # else - # zerovector!(xr) - # end - # end + mul_front!(xR, x_fused, R_fused, One(), Zero(), H.backend, H.allocator) LxR = H.leftenv * xR TensorOperations.tensorfree!(xR, H.allocator) diff --git a/src/utility/utility.jl b/src/utility/utility.jl index e5a8d4ccd..cc7685e04 100644 --- a/src/utility/utility.jl +++ b/src/utility/utility.jl @@ -8,8 +8,8 @@ function _transpose_as(t1::AbstractTensorMap, t2::AbstractTensorMap; copy::Bool return repartition(t1, numout(t2), numin(t2); copy) end -_mul_front(C, A) = matrix_contract(A, C, 1; transpose = true) # _transpose_front(C * _transpose_tail(A)) -_mul_tail(A, C) = matrix_contract(A, C, numind(A)) # A * C +_mul_front(C, A) = mul_front(C, A) # _transpose_front(C * _transpose_tail(A)) +_mul_tail(A, C) = mul_tail(A, C) # A * C function _similar_tail(A::AbstractTensorMap) cod = _firstspace(A) @@ -226,6 +226,102 @@ function matrix_contract!( return C end +function mul_front( + A::AbstractTensorMap, B::AbstractTensorMap, + α::Number, + backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() + ) + cod = prod(i -> i == 1 ? space(A, 1) : space(B, i), 1:numout(B)) + dom = domain(B) + T = TensorOperations.promote_contract(scalartype(A), scalartype(B), scalartype(α)) + C = similar(A, T, cod ← dom) + return mul_front!(C, A, B, α, Zero(), backend, allocator) +end + +function mul_front!( + C::AbstractTensorMap, A::AbstractTensorMap, B::AbstractTensorMap, + α::Number, β::Number, + backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() + ) + (numin(C) == numin(B) && numout(C) == numout(B) && numin(A) == numout(A) == 1) || + throw(SpaceMismatch()) + + numout(B) == 1 && return mul!(C, A, B, α, β) + + cp = checkpoint(allocator) + + Ablocks = blocks(A) + Bstructure = TensorKit.fusionblockstructure(space(B)) + for ((f₁, f₂), c) in subblocks(C) + # fetch A block + u = first(f₁.uncoupled) + a = Ablocks[u] + isempty(a) && (scale!(c, β); continue) + + # fetch B block + haskey(Bstructure.fusiontreeindices, (f₁, f₂)) || (scale!(c, β); continue) + b = B[f₁, f₂] + + tensorcontract!( + c, + a, ((1,), (2,)), false, + b, ((1,), ntuple(i -> i + 1, numind(B) - 1)), false, + (ntuple(identity, numout(C)), ntuple(i -> i + numout(C), numin(C))), + α, β, backend, allocator + ) + end + + return reset!(allocator, cp) +end + +function mul_tail( + A::AbstractTensorMap, B::AbstractTensorMap, + α::Number, + backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() + ) + cod = codomain(A) + dom = prod(i -> i == 1 ? domain(B)[1] : domain(A)[i], 1:numin(A)) + T = TensorOperations.promote_contract(scalartype(A), scalartype(B), scalartype(α)) + C = similar(A, T, cod ← dom) + return mul_tail!(C, A, B, α, Zero(), backend, allocator) +end + +function mul_tail!( + C::AbstractTensorMap, A::AbstractTensorMap, B::AbstractTensorMap, + α::Number, β::Number, + backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() + ) + (numin(C) == numin(A) && numout(C) == numout(A) && numin(B) == numout(B) == 1) || + throw(SpaceMismatch()) + + numin(A) == 1 && return mul!(C, A, B, α, β) + + cp = checkpoint(allocator) + + Astructure = TensorKit.fusionblockstructure(space(A)) + Bblocks = blocks(B) + for ((f₁, f₂), c) in subblocks(C) + # fetch B block + u = first(f₂.uncoupled) + b = Bblocks[u] + isempty(b) && (scale!(c, β); continue) + + # fetch A block + haskey(Astructure.fusiontreeindices, (f₁, f₂)) || (scale!(c, β); continue) + a = A[f₁, f₂] + + tensorcontract!( + c, + a, (ntuple(identity, numind(A) - 1), (1,)), false, + b, ((1,), (2,)), false, + (ntuple(identity, numout(C)), ntuple(i -> i + numout(C), numin(C))), + α, β, backend, allocator + ) + end + + return reset!(allocator, cp) +end + @inline fuse_legs(x::TensorMap, N₁::Int, N₂::Int) = fuse_legs(x, Val(N₁), Val(N₂)) function fuse_legs(x::TensorMap, ::Val{N₁}, ::Val{N₂}) where {N₁, N₂} ((0 <= N₁ <= numout(x)) && (0 <= N₂ <= numin(x))) || throw(ArgumentError("invalid fusing scheme")) From 458a9287abab735e82a36639fb7575a61f5722b9 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Wed, 17 Dec 2025 08:44:27 -0500 Subject: [PATCH 19/37] small fixes --- src/algorithms/derivatives/mpo_derivatives.jl | 4 +++- src/utility/utility.jl | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index 2d714f342..a77ab461f 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -171,7 +171,9 @@ function (H::PrecomputedDerivative)(x::AbstractTensorMap) TC = TensorOperations.promote_contract(scalartype(x_fused), scalartype(R_fused)) - xR = TensorOperations.tensoralloc_contract(TC, x_fused, ((1,), (2,)), false, R_fused, ((1,), (2, 3)), false, ((1, 2), (3,)), Val(true), H.allocator) + xR = TensorOperations.tensoralloc_contract( + TC, x_fused, ((1,), (2,)), false, R_fused, ((1,), (2, 3)), false, ((1, 2), (3,)), Val(true), H.allocator + ) mul_front!(xR, x_fused, R_fused, One(), Zero(), H.backend, H.allocator) diff --git a/src/utility/utility.jl b/src/utility/utility.jl index cc7685e04..0355db8c2 100644 --- a/src/utility/utility.jl +++ b/src/utility/utility.jl @@ -228,7 +228,7 @@ end function mul_front( A::AbstractTensorMap, B::AbstractTensorMap, - α::Number, + α::Number = One(), backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() ) cod = prod(i -> i == 1 ? space(A, 1) : space(B, i), 1:numout(B)) @@ -240,7 +240,7 @@ end function mul_front!( C::AbstractTensorMap, A::AbstractTensorMap, B::AbstractTensorMap, - α::Number, β::Number, + α::Number = One(), β::Number = Zero(), backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() ) (numin(C) == numin(B) && numout(C) == numout(B) && numin(A) == numout(A) == 1) || @@ -276,7 +276,7 @@ end function mul_tail( A::AbstractTensorMap, B::AbstractTensorMap, - α::Number, + α::Number = One(), backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() ) cod = codomain(A) @@ -288,7 +288,7 @@ end function mul_tail!( C::AbstractTensorMap, A::AbstractTensorMap, B::AbstractTensorMap, - α::Number, β::Number, + α::Number = One(), β::Number = Zero(), backend::AbstractBackend = DefaultBackend(), allocator = DefaultAllocator() ) (numin(C) == numin(A) && numout(C) == numout(A) && numin(B) == numout(B) == 1) || From cac159389f1a62f4244560328f09fa0e772dceed Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Wed, 17 Dec 2025 21:33:27 -0500 Subject: [PATCH 20/37] some more fixes --- src/algorithms/derivatives/mpo_derivatives.jl | 7 +++---- src/utility/utility.jl | 6 ++++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index a77ab461f..53570205d 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -169,16 +169,15 @@ function (H::PrecomputedDerivative)(x::AbstractTensorMap) R_fused = fuse_legs(H.rightenv, 0, numin(x)) x_fused = fuse_legs(x, numout(x), numin(x)) - TC = TensorOperations.promote_contract(scalartype(x_fused), scalartype(R_fused)) xR = TensorOperations.tensoralloc_contract( - TC, x_fused, ((1,), (2,)), false, R_fused, ((1,), (2, 3)), false, ((1, 2), (3,)), Val(true), H.allocator + TC, x_fused, ((1,), (2,)), false, R_fused, ((1,), (2, 3)), false, ((1, 2), (3,)), Val(true), allocator ) - mul_front!(xR, x_fused, R_fused, One(), Zero(), H.backend, H.allocator) + mul_front!(xR, x_fused, R_fused, One(), Zero(), H.backend, allocator) LxR = H.leftenv * xR - TensorOperations.tensorfree!(xR, H.allocator) + TensorOperations.tensorfree!(xR, allocator) reset!(allocator, cp) return TensorMap{scalartype(LxR)}(LxR.data, codomain(H.leftenv) ← domain(H.rightenv)) diff --git a/src/utility/utility.jl b/src/utility/utility.jl index 0355db8c2..6444d6b89 100644 --- a/src/utility/utility.jl +++ b/src/utility/utility.jl @@ -270,8 +270,9 @@ function mul_front!( α, β, backend, allocator ) end + reset!(allocator, cp) - return reset!(allocator, cp) + return C end function mul_tail( @@ -319,7 +320,8 @@ function mul_tail!( ) end - return reset!(allocator, cp) + reset!(allocator, cp) + return C end @inline fuse_legs(x::TensorMap, N₁::Int, N₂::Int) = fuse_legs(x, Val(N₁), Val(N₂)) From 4e66437d72bc2cd979c0702de61a9a2855e77088 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 2 Jan 2026 09:53:47 +0100 Subject: [PATCH 21/37] avoid unbound type parameters --- .../derivatives/hamiltonian_derivatives.jl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/algorithms/derivatives/hamiltonian_derivatives.jl b/src/algorithms/derivatives/hamiltonian_derivatives.jl index 5015575e5..9b073ef26 100644 --- a/src/algorithms/derivatives/hamiltonian_derivatives.jl +++ b/src/algorithms/derivatives/hamiltonian_derivatives.jl @@ -19,6 +19,13 @@ struct JordanMPO_AC_Hamiltonian{O1, O2, O3} <: DerivativeOperator C::Union{O2, Missing} # starting B::Union{O2, Missing} # ending A::Union{O3, Missing} # continuing + + function JordanMPO_AC_Hamiltonian{O1, O2, O3}( + D::Union{O1, Missing}, I::Union{O1, Missing}, E::Union{O1, Missing}, + C::Union{O2, Missing}, B::Union{O2, Missing}, A::Union{O3, Missing} + ) where {O1, O2, O3} + return new{O1, O2, O3}(D, I, E, C, B, A) + end end function AC_hamiltonian( @@ -139,6 +146,15 @@ struct JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4} <: DerivativeOperator BE::Union{O2, Missing} # ending left DE::Union{O1, Missing} # onsite left EE::Union{O1, Missing} # finished + + function JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4}( + II::Union{O1, Missing}, IC::Union{O2, Missing}, ID::Union{O1, Missing}, + CB::Union{O2, Missing}, CA::Union{O3, Missing}, + AB::Union{O3, Missing}, AA::Union{O4, Missing}, + BE::Union{O2, Missing}, DE::Union{O1, Missing}, EE::Union{O1, Missing} + ) where {O1, O2, O3, O4} + return new{O1, O2, O3, O4}(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) + end end function AC2_hamiltonian( From 6c53e5f9c8cec17361e9df965632f73647873a80 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 2 Jan 2026 09:59:03 +0100 Subject: [PATCH 22/37] remove unused code --- src/algorithms/derivatives/derivatives.jl | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/algorithms/derivatives/derivatives.jl b/src/algorithms/derivatives/derivatives.jl index 4eac14c40..2320f9312 100644 --- a/src/algorithms/derivatives/derivatives.jl +++ b/src/algorithms/derivatives/derivatives.jl @@ -219,13 +219,6 @@ Base.:*(h::LazySum{<:Union{DerivativeOrMultiplied}}, v) = h(v) """ prepare_operator!!(O, [backend], [allocator]) -> O′ -Given an operator and vector, try to construct a more efficient representation of that operator for repeated application. -This should always be used in conjunction with [`unprepare_operator!!`](@ref). +Given an operator, try to construct a more efficient representation of that operator for repeated application. """ prepare_operator!!(O, backend::AbstractBackend = DefaultBackend(), allocator = GrowingBuffer()) = O - -# to make benchmark scripts run -prepare_operator!!(O, x::AbstractTensorMap, backend::AbstractBackend = DefaultBackend(), allocator = GrowingBuffer()) = - prepare_operator!!(O, backend, allocator), x -unprepare_operator!!(y, O, x, backend::AbstractBackend = DefaultBackend(), allocator = GrowingBuffer()) = - y From f127d7662e2fde2ebcc74b92bf8ed5fa067a320c Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 2 Jan 2026 10:16:05 +0100 Subject: [PATCH 23/37] include preparation in algorithms --- src/algorithms/changebonds/vumpssvd.jl | 4 ++-- src/algorithms/groundstate/dmrg.jl | 6 +++--- src/algorithms/groundstate/idmrg.jl | 12 ++++++------ src/algorithms/groundstate/vumps.jl | 8 ++++---- src/algorithms/statmech/idmrg.jl | 12 ++++++------ 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/algorithms/changebonds/vumpssvd.jl b/src/algorithms/changebonds/vumpssvd.jl index c924976ce..36ba6852d 100644 --- a/src/algorithms/changebonds/vumpssvd.jl +++ b/src/algorithms/changebonds/vumpssvd.jl @@ -53,10 +53,10 @@ function changebonds_n(state::InfiniteMPS, H, alg::VUMPSSvdCut, envs = environme for loc in 1:length(state) @plansor AC2[-1 -2; -3 -4] := state.AC[loc][-1 -2; 1] * state.AR[loc + 1][1 -4; -3] - Hac2 = AC2_hamiltonian(loc, state, H, state, envs) + Hac2 = prepare_operator!!(AC2_hamiltonian(loc, state, H, state, envs)) _, nAC2 = fixedpoint(Hac2, AC2, :SR, alg.alg_eigsolve) - Hc = C_hamiltonian(loc + 1, state, H, state, envs) + Hc = prepare_operator!!(C_hamiltonian(loc + 1, state, H, state, envs)) _, nC2 = fixedpoint(Hc, state.C[loc + 1], :SR, alg.alg_eigsolve) #svd ac2, get new AL1 and S,V ---> AC diff --git a/src/algorithms/groundstate/dmrg.jl b/src/algorithms/groundstate/dmrg.jl index bbca5157d..4f7bb8940 100644 --- a/src/algorithms/groundstate/dmrg.jl +++ b/src/algorithms/groundstate/dmrg.jl @@ -44,7 +44,7 @@ function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG, envs = environme zerovector!(ϵs) for pos in [1:(length(ψ) - 1); length(ψ):-1:2] - h = AC_hamiltonian(pos, ψ, H, ψ, envs) + h = prepare_operator!!(AC_hamiltonian(pos, ψ, H, ψ, envs)) _, vec = fixedpoint(h, ψ.AC[pos], :SR, alg_eigsolve) ϵs[pos] = max(ϵs[pos], calc_galerkin(pos, ψ, H, ψ, envs)) ψ.AC[pos] = vec @@ -122,7 +122,7 @@ function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG2, envs = environm # left to right sweep for pos in 1:(length(ψ) - 1) @plansor ac2[-1 -2; -3 -4] := ψ.AC[pos][-1 -2; 1] * ψ.AR[pos + 1][1 -4; -3] - Hac2 = AC2_hamiltonian(pos, ψ, H, ψ, envs) + Hac2 = prepare_operator!!(AC2_hamiltonian(pos, ψ, H, ψ, envs)) _, newA2center = fixedpoint(Hac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(newA2center; trunc = alg.trscheme, alg = alg.alg_svd) @@ -137,7 +137,7 @@ function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG2, envs = environm # right to left sweep for pos in (length(ψ) - 2):-1:1 @plansor ac2[-1 -2; -3 -4] := ψ.AL[pos][-1 -2; 1] * ψ.AC[pos + 1][1 -4; -3] - Hac2 = AC2_hamiltonian(pos, ψ, H, ψ, envs) + Hac2 = prepare_operator!!(AC2_hamiltonian(pos, ψ, H, ψ, envs)) _, newA2center = fixedpoint(Hac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(newA2center; trunc = alg.trscheme, alg = alg.alg_svd) diff --git a/src/algorithms/groundstate/idmrg.jl b/src/algorithms/groundstate/idmrg.jl index fab2c96da..317c5053b 100644 --- a/src/algorithms/groundstate/idmrg.jl +++ b/src/algorithms/groundstate/idmrg.jl @@ -155,7 +155,7 @@ function _localupdate_sweep_idmrg!(ψ, H, envs, alg_eigsolve) C_old = ψ.C[0] # left to right sweep for pos in 1:length(ψ) - h = AC_hamiltonian(pos, ψ, H, ψ, envs) + h = prepare_operator!!(AC_hamiltonian(pos, ψ, H, ψ, envs)) _, ψ.AC[pos] = fixedpoint(h, ψ.AC[pos], :SR, alg_eigsolve) if pos == length(ψ) # AC needed in next sweep @@ -168,7 +168,7 @@ function _localupdate_sweep_idmrg!(ψ, H, envs, alg_eigsolve) # right to left sweep for pos in length(ψ):-1:1 - h = AC_hamiltonian(pos, ψ, H, ψ, envs) + h = prepare_operator!!(AC_hamiltonian(pos, ψ, H, ψ, envs)) E, ψ.AC[pos] = fixedpoint(h, ψ.AC[pos], :SR, alg_eigsolve) ψ.C[pos - 1], temp = right_orth!(_transpose_tail(ψ.AC[pos]; copy = (pos == 1)); positive = true) @@ -184,7 +184,7 @@ function _localupdate_sweep_idmrg2!(ψ, H, envs, alg_eigsolve, alg_trscheme, alg # sweep from left to right for pos in 1:(length(ψ) - 1) ac2 = AC2(ψ, pos; kind = :ACAR) - h_ac2 = AC2_hamiltonian(pos, ψ, H, ψ, envs) + h_ac2 = prepare_operator!!(AC2_hamiltonian(pos, ψ, H, ψ, envs)) _, ac2′ = fixedpoint(h_ac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(ac2′; trunc = alg_trscheme, alg = alg_svd) @@ -203,7 +203,7 @@ function _localupdate_sweep_idmrg2!(ψ, H, envs, alg_eigsolve, alg_trscheme, alg ψ.AL[end] = ψ.AC[end] / ψ.C[end] ψ.AC[1] = _mul_tail(ψ.AL[1], ψ.C[1]) ac2 = AC2(ψ, 0; kind = :ALAC) - h_ac2 = AC2_hamiltonian(0, ψ, H, ψ, envs) + h_ac2 = prepare_operator!!(AC2_hamiltonian(0, ψ, H, ψ, envs)) _, ac2′ = fixedpoint(h_ac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(ac2′; trunc = alg_trscheme, alg = alg_svd) @@ -226,7 +226,7 @@ function _localupdate_sweep_idmrg2!(ψ, H, envs, alg_eigsolve, alg_trscheme, alg # sweep from right to left for pos in (length(ψ) - 1):-1:1 ac2 = AC2(ψ, pos; kind = :ALAC) - h_ac2 = AC2_hamiltonian(pos, ψ, H, ψ, envs) + h_ac2 = prepare_operator!!(AC2_hamiltonian(pos, ψ, H, ψ, envs)) _, ac2′ = fixedpoint(h_ac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(ac2′; trunc = alg_trscheme, alg = alg_svd) @@ -246,7 +246,7 @@ function _localupdate_sweep_idmrg2!(ψ, H, envs, alg_eigsolve, alg_trscheme, alg ψ.AC[end] = _mul_front(ψ.C[end - 1], ψ.AR[end]) ψ.AR[1] = _transpose_front(ψ.C[end] \ _transpose_tail(ψ.AC[1])) ac2 = AC2(ψ, 0; kind = :ACAR) - h_ac2 = AC2_hamiltonian(0, ψ, H, ψ, envs) + h_ac2 = prepare_operator!!(AC2_hamiltonian(0, ψ, H, ψ, envs)) E, ac2′ = fixedpoint(h_ac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(ac2′; trunc = alg_trscheme, alg = alg_svd) normalize!(c) diff --git a/src/algorithms/groundstate/vumps.jl b/src/algorithms/groundstate/vumps.jl index 99da8234c..bc4f6af9b 100644 --- a/src/algorithms/groundstate/vumps.jl +++ b/src/algorithms/groundstate/vumps.jl @@ -130,9 +130,9 @@ function _localupdate_vumps_step!( alg_eigsolve = Defaults.eigsolver, which ) if !parallel - Hac = AC_hamiltonian(site, mps, operator, mps, envs) + Hac = prepare_operator!!(AC_hamiltonian(site, mps, operator, mps, envs)) _, AC = fixedpoint(Hac, AC₀, which, alg_eigsolve) - Hc = C_hamiltonian(site, mps, operator, mps, envs) + Hc = prepare_operator!!(C_hamiltonian(site, mps, operator, mps, envs)) _, C = fixedpoint(Hc, C₀, which, alg_eigsolve) return regauge!(AC, C; alg = alg_orth) end @@ -140,11 +140,11 @@ function _localupdate_vumps_step!( local AC, C @sync begin @spawn begin - Hac = AC_hamiltonian(site, mps, operator, mps, envs) + Hac = prepare_operator!!(AC_hamiltonian(site, mps, operator, mps, envs)) _, AC = fixedpoint(Hac, AC₀, which, alg_eigsolve) end @spawn begin - Hc = C_hamiltonian(site, mps, operator, mps, envs) + Hc = prepare_operator!!(C_hamiltonian(site, mps, operator, mps, envs)) _, C = fixedpoint(Hc, C₀, which, alg_eigsolve) end end diff --git a/src/algorithms/statmech/idmrg.jl b/src/algorithms/statmech/idmrg.jl index 477583bb6..2997347ff 100644 --- a/src/algorithms/statmech/idmrg.jl +++ b/src/algorithms/statmech/idmrg.jl @@ -13,7 +13,7 @@ function leading_boundary( # left to right sweep for col in 1:size(ψ, 2) - Hac = AC_hamiltonian(col, ψ, operator, ψ, envs) + Hac = prepare_operator!!(AC_hamiltonian(col, ψ, operator, ψ, envs)) _, ψ.AC[:, col] = fixedpoint(Hac, ψ.AC[:, col], :LM, alg_eigsolve) for row in 1:size(ψ, 1) @@ -27,7 +27,7 @@ function leading_boundary( # right to left sweep for col in size(ψ, 2):-1:1 - Hac = AC_hamiltonian(col, ψ, operator, ψ, envs) + Hac = prepare_operator!!(AC_hamiltonian(col, ψ, operator, ψ, envs)) _, ψ.AC[:, col] = fixedpoint(Hac, ψ.AC[:, col], :LM, alg_eigsolve) for row in 1:size(ψ, 1) @@ -78,7 +78,7 @@ function leading_boundary( # sweep from left to right for site in 1:(size(ψ, 2) - 1) ac2 = AC2(ψ, site; kind = :ACAR) - h = AC2_hamiltonian(site, ψ, operator, ψ, envs) + h = prepare_operator!!(AC2_hamiltonian(site, ψ, operator, ψ, envs)) _, ac2′ = fixedpoint(h, ac2, :LM, alg_eigsolve) for row in 1:size(ψ, 1) @@ -102,7 +102,7 @@ function leading_boundary( ψ.AL[:, end] .= ψ.AC[:, end] ./ ψ.C[:, end] ψ.AC[:, 1] .= _mul_tail.(ψ.AL[:, 1], ψ.C[:, 1]) ac2 = AC2(ψ, site; kind = :ALAC) - h = AC2_hamiltonian(site, ψ, operator, ψ, envs) + h = prepare_operator!!(AC2_hamiltonian(site, ψ, operator, ψ, envs)) _, ac2′ = fixedpoint(h, ac2, :LM, alg_eigsolve) for row in 1:size(ψ, 1) @@ -127,7 +127,7 @@ function leading_boundary( # sweep from right to left for site in reverse(1:(size(ψ, 2) - 1)) ac2 = AC2(ψ, site; kind = :ALAC) - h = AC2_hamiltonian(site, ψ, operator, ψ, envs) + h = prepare_operator!!(AC2_hamiltonian(site, ψ, operator, ψ, envs)) _, ac2′ = fixedpoint(h, ac2, :LM, alg_eigsolve) for row in 1:size(ψ, 1) @@ -149,7 +149,7 @@ function leading_boundary( ψ.AC[:, end] .= _mul_front.(ψ.C[:, end - 1], ψ.AR[:, end]) ψ.AR[:, 1] .= _transpose_front.(ψ.C[:, end] .\ _transpose_tail.(ψ.AC[:, 1])) ac2 = AC2(ψ, 0; kind = :ACAR) - h = AC2_hamiltonian(0, ψ, operator, ψ, envs) + h = prepare_operator!!(AC2_hamiltonian(0, ψ, operator, ψ, envs)) _, ac2′ = fixedpoint(h, ac2, :LM, alg_eigsolve) for row in 1:size(ψ, 1) From 7c20b5ef721d90873b5dcb6e35c85855a67cc612 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 2 Jan 2026 10:16:10 +0100 Subject: [PATCH 24/37] small fixes --- .../derivatives/hamiltonian_derivatives.jl | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/algorithms/derivatives/hamiltonian_derivatives.jl b/src/algorithms/derivatives/hamiltonian_derivatives.jl index 9b073ef26..6238214f5 100644 --- a/src/algorithms/derivatives/hamiltonian_derivatives.jl +++ b/src/algorithms/derivatives/hamiltonian_derivatives.jl @@ -90,30 +90,36 @@ function prepare_operator!!( B = H.B # onsite - D = if !ismissing(C) - Id = TensorKit.id(storagetype(W.D), space(C, 2)) - @plansor C[-1 -2; -3 -4] += W.D[-1; -3] * Id[-4; -2] + D = if ismissing(H.D) + missing + elseif !ismissing(C) + Id = TensorKit.id(storagetype(C), space(C, 2)) + @plansor C[-1 -2; -3 -4] += H.D[-1; -3] * Id[-2; -4] missing elseif !ismissing(B) - Id = TensorKit.id(storagetype(W.D), space(B, 1)) - @plansor B[-1 -2; -3 -4] += Id[-1; -3] * W.D[-2; -4] + Id = TensorKit.id(storagetype(B), space(B, 1)) + @plansor B[-1 -2; -3 -4] += Id[-1; -3] * H.D[-2; -4] missing else W.D end # not_started - I = if !ismissing(C) - Id = id(storagetype(W.I), space(C, 1)) - @plansor C[-1 -2; -3 -4] += I[-1; -3] * H.I[-4; -2] + I = if ismissing(H.I) + missing + elseif !ismissing(C) + Id = id(storagetype(C), space(C, 1)) + @plansor C[-1 -2; -3 -4] += Id[-1; -3] * H.I[-4; -2] missing else H.I end # finished - E = if !ismissing(B) - Id = id(storagetype(W.I), space(B, 2)) + E = if ismissing(H.E) + missing + elseif !ismissing(B) + Id = id(storagetype(B), space(B, 2)) @plansor B[-1 -2; -3 -4] += H.E[-1; -3] * Id[-2; -4] missing else From b473e5ea08b642d4da788b7ac9d4f682ba0bda30 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 2 Jan 2026 10:36:46 +0100 Subject: [PATCH 25/37] convert to complex if necessary --- src/algorithms/derivatives/hamiltonian_derivatives.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/algorithms/derivatives/hamiltonian_derivatives.jl b/src/algorithms/derivatives/hamiltonian_derivatives.jl index 6238214f5..92d4cc257 100644 --- a/src/algorithms/derivatives/hamiltonian_derivatives.jl +++ b/src/algorithms/derivatives/hamiltonian_derivatives.jl @@ -256,7 +256,13 @@ function JordanMPO_AC2_Hamiltonian(GL::MPSTensor, W1::JordanMPOTensor, W2::Jorda all(iszero, mask_left .* mask_right) && (AA = missing) end - return JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4}(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) + return JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4}( + II, IC, ID, + convert(O2, CB), # might have real eltype + CA, + AB, AA, + BE, DE, EE + ) end From f28c7bdd03adeccb7a5801aaa06a44940ab7fbd6 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 2 Jan 2026 10:37:00 +0100 Subject: [PATCH 26/37] avoid missing converters --- src/algorithms/derivatives/mpo_derivatives.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index 53570205d..40967ca6d 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -126,8 +126,8 @@ function prepare_operator!!( H::MPO_C_Hamiltonian{<:MPSTensor, <:MPSTensor}, backend::AbstractBackend, allocator ) - leftenv = _transpose_tail(TensorMap(H.leftenv)) - rightenv = TensorMap(H.rightenv) + leftenv = _transpose_tail(H.leftenv isa TensorMap ? H.leftenv : TensorMap(H.leftenv)) + rightenv = H.rightenv isa TensorMap ? H.rightenv : TensorMap(H.rightenv) return PrecomputedDerivative(leftenv, rightenv, backend, allocator) end function prepare_operator!!( @@ -139,8 +139,8 @@ function prepare_operator!!( GL_O[-1 -2; -4 -5 -3] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] end reset!(allocator, cp) - leftenv = fuse_legs(TensorMap(GL_O), 0, 2) - rightenv = TensorMap(H.rightenv) + leftenv = fuse_legs(GL_O isa TensorMap ? GL_O : TensorMap(GL_O), 0, 2) + rightenv = H.rightenv isa TensorMap ? H.rightenv : TensorMap(H.rightenv) return PrecomputedDerivative(leftenv, rightenv, backend, allocator) end From 36f0880e56929d332f3405e0f9ce0fb2b3136819 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sat, 3 Jan 2026 00:29:11 +0100 Subject: [PATCH 27/37] more rework of convert to complex --- src/algorithms/derivatives/hamiltonian_derivatives.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/algorithms/derivatives/hamiltonian_derivatives.jl b/src/algorithms/derivatives/hamiltonian_derivatives.jl index 92d4cc257..34f3c6e85 100644 --- a/src/algorithms/derivatives/hamiltonian_derivatives.jl +++ b/src/algorithms/derivatives/hamiltonian_derivatives.jl @@ -197,7 +197,8 @@ function JordanMPO_AC2_Hamiltonian(GL::MPSTensor, W1::JordanMPOTensor, W2::Jorda # starting left - ending right CB = if nonzero_length(W1.C) > 0 && nonzero_length(W2.B) > 0 @plansor CB_[-1 -2; -3 -4] ≔ W1.C[-1; -3 1] * W2.B[1 -2; -4] - only(CB_) + # have to convert to complex if hamiltonian is real but states are complex + scalartype(GL) <: Complex ? complex(only(CB_)) : only(CB_) else missing end @@ -258,8 +259,7 @@ function JordanMPO_AC2_Hamiltonian(GL::MPSTensor, W1::JordanMPOTensor, W2::Jorda return JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4}( II, IC, ID, - convert(O2, CB), # might have real eltype - CA, + CB, CA, AB, AA, BE, DE, EE ) From 2730908057ed3a9b6b955d9b2061de0ec114a828 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sat, 3 Jan 2026 12:01:49 +0100 Subject: [PATCH 28/37] include TDVP for operator prep --- src/algorithms/timestep/tdvp.jl | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/algorithms/timestep/tdvp.jl b/src/algorithms/timestep/tdvp.jl index 2d67f90a1..42791f9da 100644 --- a/src/algorithms/timestep/tdvp.jl +++ b/src/algorithms/timestep/tdvp.jl @@ -41,18 +41,18 @@ function timestep( scheduler = Defaults.scheduler[] if scheduler isa SerialScheduler temp_ACs = tmap!(temp_ACs, 1:length(ψ); scheduler) do loc - Hac = AC_hamiltonian(loc, ψ, H, ψ, envs) + Hac = prepare_operator!!(AC_hamiltonian(loc, ψ, H, ψ, envs)) return integrate(Hac, ψ.AC[loc], t, dt, alg.integrator; imaginary_evolution) end temp_Cs = tmap!(temp_Cs, 1:length(ψ); scheduler) do loc - Hc = C_hamiltonian(loc, ψ, H, ψ, envs) + Hc = prepare_operator!!(C_hamiltonian(loc, ψ, H, ψ, envs)) return integrate(Hc, ψ.C[loc], t, dt, alg.integrator; imaginary_evolution) end else @sync begin Threads.@spawn begin temp_ACs = tmap!(temp_ACs, 1:length(ψ); scheduler) do loc - Hac = AC_hamiltonian(loc, ψ, H, ψ, envs) + Hac = prepare_operator!!(AC_hamiltonian(loc, ψ, H, ψ, envs)) return integrate( Hac, ψ.AC[loc], t, dt, alg.integrator; imaginary_evolution @@ -61,7 +61,7 @@ function timestep( end Threads.@spawn begin temp_Cs = tmap!(temp_Cs, 1:length(ψ); scheduler) do loc - Hc = C_hamiltonian(loc, ψ, H, ψ, envs) + Hc = prepare_operator!!(C_hamiltonian(loc, ψ, H, ψ, envs)) return integrate( Hc, ψ.C[loc], t, dt, alg.integrator; imaginary_evolution @@ -92,10 +92,10 @@ function timestep!( # sweep left to right for i in 1:(length(ψ) - 1) - Hac = AC_hamiltonian(i, ψ, H, ψ, envs) + Hac = prepare_operator!!(AC_hamiltonian(i, ψ, H, ψ, envs)) ψ.AC[i] = integrate(Hac, ψ.AC[i], t, dt / 2, alg.integrator; imaginary_evolution) - Hc = C_hamiltonian(i, ψ, H, ψ, envs) + Hc = prepare_operator!!(C_hamiltonian(i, ψ, H, ψ, envs)) ψ.C[i] = integrate( Hc, ψ.C[i], t + dt / 2, -dt / 2, alg.integrator; imaginary_evolution @@ -103,18 +103,18 @@ function timestep!( end # edge case - Hac = AC_hamiltonian(length(ψ), ψ, H, ψ, envs) + Hac = prepare_operator!!(AC_hamiltonian(length(ψ), ψ, H, ψ, envs)) ψ.AC[end] = integrate(Hac, ψ.AC[end], t, dt / 2, alg.integrator; imaginary_evolution) # sweep right to left for i in length(ψ):-1:2 - Hac = AC_hamiltonian(i, ψ, H, ψ, envs) + Hac = prepare_operator!!(AC_hamiltonian(i, ψ, H, ψ, envs)) ψ.AC[i] = integrate( Hac, ψ.AC[i], t + dt / 2, dt / 2, alg.integrator; imaginary_evolution ) - Hc = C_hamiltonian(i - 1, ψ, H, ψ, envs) + Hc = prepare_operator!!(C_hamiltonian(i - 1, ψ, H, ψ, envs)) ψ.C[i - 1] = integrate( Hc, ψ.C[i - 1], t + dt, -dt / 2, alg.integrator; imaginary_evolution @@ -122,7 +122,7 @@ function timestep!( end # edge case - Hac = AC_hamiltonian(1, ψ, H, ψ, envs) + Hac = prepare_operator!!(AC_hamiltonian(1, ψ, H, ψ, envs)) ψ.AC[1] = integrate( Hac, ψ.AC[1], t + dt / 2, dt / 2, alg.integrator; imaginary_evolution @@ -173,7 +173,7 @@ function timestep!( # sweep left to right for i in 1:(length(ψ) - 1) ac2 = _transpose_front(ψ.AC[i]) * _transpose_tail(ψ.AR[i + 1]) - Hac2 = AC2_hamiltonian(i, ψ, H, ψ, envs) + Hac2 = prepare_operator!!(AC2_hamiltonian(i, ψ, H, ψ, envs)) ac2′ = integrate(Hac2, ac2, t, dt / 2, alg.integrator; imaginary_evolution) nal, nc, nar = svd_trunc!(ac2′; trunc = alg.trscheme, alg = alg.alg_svd) @@ -181,7 +181,7 @@ function timestep!( ψ.AC[i + 1] = (complex(nc), _transpose_front(nar)) if i != (length(ψ) - 1) - Hac = AC_hamiltonian(i + 1, ψ, H, ψ, envs) + Hac = prepare_operator!!(AC_hamiltonian(i + 1, ψ, H, ψ, envs)) ψ.AC[i + 1] = integrate( Hac, ψ.AC[i + 1], t + dt / 2, -dt / 2, alg.integrator; imaginary_evolution @@ -192,7 +192,7 @@ function timestep!( # sweep right to left for i in length(ψ):-1:2 ac2 = _transpose_front(ψ.AL[i - 1]) * _transpose_tail(ψ.AC[i]) - Hac2 = AC2_hamiltonian(i - 1, ψ, H, ψ, envs) + Hac2 = prepare_operator!!(AC2_hamiltonian(i - 1, ψ, H, ψ, envs)) ac2′ = integrate(Hac2, ac2, t + dt / 2, dt / 2, alg.integrator; imaginary_evolution) nal, nc, nar = svd_trunc!(ac2′; trunc = alg.trscheme, alg = alg.alg_svd) @@ -200,7 +200,7 @@ function timestep!( ψ.AC[i] = (complex(nc), _transpose_front(nar)) if i != 2 - Hac = AC_hamiltonian(i - 1, ψ, H, ψ, envs) + Hac = prepare_operator!!(AC_hamiltonian(i - 1, ψ, H, ψ, envs)) ψ.AC[i - 1] = integrate( Hac, ψ.AC[i - 1], t + dt, -dt / 2, alg.integrator; imaginary_evolution From de634e6300cc1bb57a0fa099d5edaa84680e05ee Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sat, 3 Jan 2026 12:01:58 +0100 Subject: [PATCH 29/37] small changes to buffer --- src/utility/allocator.jl | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/utility/allocator.jl b/src/utility/allocator.jl index f9dc1a482..bf5d601ce 100644 --- a/src/utility/allocator.jl +++ b/src/utility/allocator.jl @@ -1,15 +1,14 @@ -@static if isdefined(Core, :Memory) - BufType = Memory{UInt8} -else - BufType = Vector{UInt8} -end +const BufType = @static isdefined(Core, :Memory) ? Memory{UInt8} : Vector{UInt8} -const DEFAULT_SIZEHINT = 2^20 # 1MB +# Note: due to OS memory paging, we are only taking up virtual memory address space +# and not necessarily asking for physical memory here - it should therefore make sense +# to have a somewhat large default value +const DEFAULT_SIZEHINT = Ref(2^30) # 1GB mutable struct GrowingBuffer buffer::BufType offset::UInt - function GrowingBuffer(; sizehint = DEFAULT_SIZEHINT) + function GrowingBuffer(; sizehint = DEFAULT_SIZEHINT[]) buffer = BufType(undef, sizehint) return new(buffer, zero(UInt)) end From bc319cc798c210a1b4f45f786a12aecfe089830b Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Thu, 15 Jan 2026 11:44:55 +0100 Subject: [PATCH 30/37] fix projection for columns --- src/algorithms/derivatives/derivatives.jl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/algorithms/derivatives/derivatives.jl b/src/algorithms/derivatives/derivatives.jl index 2320f9312..b5eb4fa2b 100644 --- a/src/algorithms/derivatives/derivatives.jl +++ b/src/algorithms/derivatives/derivatives.jl @@ -188,11 +188,14 @@ for kind in (:C, :AC, :AC2) end end end + function C_projection(site, below, operator, above, envs) - return C_hamiltonian(site, below, operator, above, envs) * above.C[site] + C = above isa Multiline ? above.C[:, site] : above.C[site] + return C_hamiltonian(site, below, operator, above, envs) * C end function AC_projection(site, below, operator, above, envs) - return AC_hamiltonian(site, below, operator, above, envs) * above.AC[site] + AC = above isa Multiline ? above.AC[:, site] : above.AC[site] + return AC_hamiltonian(site, below, operator, above, envs) * AC end function AC2_projection(site::Int, below, operator, above, envs; kwargs...) return AC2_hamiltonian(site, below, operator, above, envs) * AC2(above, site; kwargs...) From 32ccfb012afaf3ee03200a4a3554a649d45826b3 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Thu, 15 Jan 2026 11:45:25 +0100 Subject: [PATCH 31/37] use projection where applicable, hamiltonian where not --- benchmark/LocalPreferences.toml | 2 + benchmark/Project.toml | 3 + scripts/ITensorsCode.jl | 160 ++++++++++++++++++++ scripts/MPSKitCode.jl | 139 +++++++++++++++++ scripts/Project.toml | 9 ++ scripts/akshay.jl | 132 ++++++++++++++++ scripts/akshay2.jl | 143 +++++++++++++++++ scripts/antonio1.jl | 16 ++ scripts/daniel.jl | 1 + scripts/issue299.jl | 20 +++ scripts/loic.jl | 42 +++++ scripts/profile_vumps.jl | 108 +++++++++++++ scripts/yanmong.jl | 34 +++++ src/algorithms/changebonds/optimalexpand.jl | 9 +- src/algorithms/expval.jl | 3 +- src/algorithms/fidelity_susceptibility.jl | 2 +- src/algorithms/grassmann.jl | 10 +- src/algorithms/groundstate/idmrg.jl | 12 +- src/algorithms/groundstate/vumps.jl | 8 +- src/algorithms/statmech/vomps.jl | 18 +-- src/algorithms/toolbox.jl | 2 +- src/environments/infinite_envs.jl | 3 +- 22 files changed, 839 insertions(+), 37 deletions(-) create mode 100644 benchmark/LocalPreferences.toml create mode 100644 scripts/ITensorsCode.jl create mode 100644 scripts/MPSKitCode.jl create mode 100644 scripts/Project.toml create mode 100644 scripts/akshay.jl create mode 100644 scripts/akshay2.jl create mode 100644 scripts/antonio1.jl create mode 100644 scripts/daniel.jl create mode 100644 scripts/issue299.jl create mode 100644 scripts/loic.jl create mode 100644 scripts/profile_vumps.jl create mode 100644 scripts/yanmong.jl diff --git a/benchmark/LocalPreferences.toml b/benchmark/LocalPreferences.toml new file mode 100644 index 000000000..cdb275e21 --- /dev/null +++ b/benchmark/LocalPreferences.toml @@ -0,0 +1,2 @@ +[TensorOperations] +precompile_workload = true diff --git a/benchmark/Project.toml b/benchmark/Project.toml index c1f0ff408..488e5b964 100644 --- a/benchmark/Project.toml +++ b/benchmark/Project.toml @@ -10,3 +10,6 @@ MPSKitModels = "ca635005-6f8c-4cd1-b51d-8491250ef2ab" TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" TensorKit = "07d1fe3e-3e46-537d-9eac-e9e13d0d4cec" TensorKitManifolds = "11fa318c-39cb-4a83-b1ed-cdc7ba1e3684" + +[sources] +MPSKit = {path = ".."} diff --git a/scripts/ITensorsCode.jl b/scripts/ITensorsCode.jl new file mode 100644 index 000000000..863bc4b1d --- /dev/null +++ b/scripts/ITensorsCode.jl @@ -0,0 +1,160 @@ +mutable struct FiniteCylinder + L::Int + N::Int +end +function linearize_index(lattice::FiniteCylinder, i, j) + row = if isodd(j) + i + else + lattice.L - i + 1 + end + return mod1(row, lattice.L) + lattice.L * (j - 1) +end +function inverse_linearize_index(lattice::FiniteCylinder, idx::Int) + L = lattice.L + j = div(idx - 1, L) + 1 + row = mod1(idx, L) + + i = if isodd(j) + row + else + L - row + 1 + end + + return i, j +end +function Shastry_Sutherland_neighbor(Lx, Ly) + N = Lx * Ly + mat = reshape(collect(1:N), Ly, Lx) + + + for i in 2:2:Lx + mat[:, i] .= reverse(mat[:, i]) + end + + horizontal_neighbors = [(mat[i, j], mat[i, j + 1]) for i in 1:Ly, j in 1:(Lx - 1)] + vertical_neighbors = [(mat[i, j], mat[i < Ly ? i + 1 : 1, j]) for i in 1:Ly, j in 1:Lx] + + return vcat(vec(horizontal_neighbors), vec(vertical_neighbors)) + # return neighbours +end +function Shastry_Sutherland_next_neighbor(Lx, Ly) + N = Lx * Ly + mat = reshape(collect(1:N), Ly, Lx) + + + for i in 2:2:Lx + mat[:, i] .= reverse(mat[:, i]) + end + + neighbors = [] + for i in 1:2:(Lx - 1) + for j in 1:2:Ly + if j < Ly + push!(neighbors, (mat[j, i], mat[j + 1, i + 1])) + else + push!(neighbors, (mat[j, i], mat[1, mod1(i + 1, Lx)])) + end + end + end + for i in 2:2:(Lx - 1) + for j in 1:2:Ly + push!(neighbors, (mat[j, i], mat[mod1(j - 1, Ly), mod1(i + 1, Lx)])) + end + end + return neighbors + # return neighbours +end +function third_neighbor(Lx, Ly) + N = Lx * Ly + mat = reshape(collect(1:N), Ly, Lx) + + + for i in 2:2:Lx + mat[:, i] .= reverse(mat[:, i]) + end + + horizontal_neighbors = [(mat[i, j], mat[i, j + 2]) for i in 1:Ly, j in 1:(Lx - 2)] + vertical_neighbors = [(mat[i, j], mat[mod1(i + 2, Ly), j]) for i in 1:Ly, j in 1:Lx] + return vcat(vec(horizontal_neighbors), vec(vertical_neighbors)) + +end +function hamiltonian(sites, Lx, Ly, Jxy, Jz, Jnx, Jnz, J3nx, J3nz, h) + neighbors = Shastry_Sutherland_neighbor(Lx, Ly) + next_neighbors = Shastry_Sutherland_next_neighbor(Lx, Ly) + third_neighbors = third_neighbor(Lx, Ly) + H = OpSum() + for (i, j) in neighbors + # H += Jxy, "Sx", i, "Sx", j + # H += Jxy, "Sy", i, "Sy", j + H += 0.5 * Jxy, "S+", i, "S-", j + H += 0.5 * Jxy, "S-", i, "S+", j + H += Jz, "Sz", i, "Sz", j + end + for (i, j) in next_neighbors + H += 0.5 * Jnx, "S+", i, "S-", j + H += 0.5 * Jnx, "S-", i, "S+", j + # H += Jnx, "Sx", i, "Sx", j + # H += Jnx, "Sy", i, "Sy", j + H += Jnz, "Sz", i, "Sz", j + end + for (i, j) in third_neighbors + H += 0.5 * J3nx, "S+", i, "S-", j + H += 0.5 * J3nx, "S-", i, "S+", j + # H += J3nx, "Sx", i, "Sx", j + # H += J3nx, "Sy", i, "Sy", j + H += J3nz, "Sz", i, "Sz", j + end + for i in 1:(Lx * Ly) + H += h, "Sz", i + end + + return ITensorMPS.MPO(H, sites) +end +function main(Lx, Ly, Δ, J1z, J2z, J3z, hz, Dcut; inistate = []) + symmetry = true + J1x = J1z + J2x = J2z + J3x = J3z + Lx = Lx + + nsweeps = 10 + if isempty(inistate) + if symmetry == true + sites = siteinds("S=1/2", Lx * Ly, conserve_qns = true) + initialstate = [isodd(n) ? "Up" : "Dn" for n in 1:(Lx * Ly)] + psi0 = random_mps(sites, initialstate; linkdims = Dcut) + else + sites = siteinds("S=1/2", Lx * Ly, conserve_qns = false) + psi0 = random_mps(sites, linkdims = Dcut) + end + maxdim = Int[Dcut + div(i, 2) * (Dcut // 1) for i in 2:(nsweeps + 1)] + else + psi0 = inistate + + sites = siteinds(psi) + D = maximum(linkdims(psi0)) + maxdim = Int[D + div(i, 2) * (Dcut // 1) for i in 2:(nsweeps + 1)] + end + + + # maxdim = vcat(repeat([Dcut], 3), repeat([2*Dcut], 4), repeat([4 *Dcut], 5)) + + cutoff = [1.0e-10] + println("##################################################") + println("Starting DMRG") + println("J1 = $J1x, J2 = $J2x, J3 = $J3x, Lx = $Lx, Ly = $Ly, Dcut = $Dcut, hz = $hz") + + ham = hamiltonian(sites, Lx, Ly, J1x, J1z, J2x, J2z, J3x, J3z, hz) + + energy, psi = dmrg(ham, psi0; nsweeps, maxdim, cutoff, outputlevel = 1) + + + filename = "./rslt/" + magz = expect(psi, "Sz") + + WF_filename = filename * "WF_J1=$(J1z)_J3=$(J3z)_Lx=$(Lx)_Ly=$(Ly)_Dcut=$(Dcut)_hz=$(hz).jld2" + save(WF_filename, "psi", psi, "bond_pl", bond_pl, "bond_dm", bond_dm, "magz", magz, "corr", corr) + GC.gc() + return +end diff --git a/scripts/MPSKitCode.jl b/scripts/MPSKitCode.jl new file mode 100644 index 000000000..2de7b70a7 --- /dev/null +++ b/scripts/MPSKitCode.jl @@ -0,0 +1,139 @@ +using MPSKitModels + +function Shastry_Sutherland_next_neighbor(lattice::InfiniteCylinder) + rows = lattice.L + cols = lattice.N ÷ lattice.L + V = vertices(lattice) + neighbours = Pair{eltype(V), eltype(V)}[] + for i in 1:2:(rows - 1) + for j in 1:2:cols + if i < rows + push!(neighbours, LatticePoint((i, j), lattice) => LatticePoint((i + 1, j + 1), lattice)) + else + push!(neighbours, LatticePoint((i, j), lattice) => LatticePoint((1, mod1(j + 1, rows)), lattice)) + end + end + end + for i in 2:2:cols + for j in 1:2:rows + # push!(neighbors, (mat[j, i], mat[mod1(j - 1, Ly), mod1(i + 1, Lx)])) + push!(neighbours, LatticePoint((j, i), lattice) => LatticePoint((mod1(j - 1, rows), i + 1), lattice)) + end + end + return neighbours + # return neighbours +end +function third_neighbours(lattice::InfiniteCylinder) + V = vertices(lattice) + neighbours = Pair{eltype(V), eltype(V)}[] + for v in V + push!(neighbours, v => v + (0, 2)) + if v.coordinates[1] < lattice.L || + lattice isa InfiniteCylinder || + lattice isa InfiniteHelix + push!(neighbours, v => v + (2, 0)) + end + end + return neighbours +end + +function Shastry_Sutherland_next_neighbor(lattice::FiniteCylinder) + rows = lattice.L + cols = lattice.N ÷ lattice.L + V = vertices(lattice) + neighbours = Pair{eltype(V), eltype(V)}[] + for i in 1:2:(rows - 1) + for j in 1:2:cols + if i < rows + push!(neighbours, LatticePoint((i, j), lattice) => LatticePoint((i + 1, j + 1), lattice)) + else + push!(neighbours, LatticePoint((i, j), lattice) => LatticePoint((1, mod1(j + 1, rows)), lattice)) + end + end + end + for i in 2:2:(cols - 1) + for j in 1:2:rows + # push!(neighbors, (mat[j, i], mat[mod1(j - 1, Ly), mod1(i + 1, Lx)])) + push!(neighbours, LatticePoint((j, i), lattice) => LatticePoint((mod1(j - 1, rows), i + 1), lattice)) + end + end + return neighbours + # return neighbours +end + +function third_neighbours(lattice::FiniteCylinder) + V = vertices(lattice) + neighbours = Pair{eltype(V), eltype(V)}[] + for v in V + if v.coordinates[2] < lattice.N / lattice.L - 1 + push!(neighbours, v => v + (0, 2)) + end + # if v.coordinates[1] < lattice.L + push!(neighbours, v => v + (2, 0)) + # end + end + return neighbours +end + +function inverse_linearize_index(lattice::Union{InfiniteCylinder, FiniteCylinder}, idx::Int) + L = lattice.L + j = div(idx - 1, L) + 1 + row = mod1(idx, L) + + i = if isodd(j) + row + else + L - row + 1 + end + + return i, j +end +function hamiltonian(J, J3, lattice; symmetry = []) + next_neighbours = Shastry_Sutherland_next_neighbor(lattice) + third = third_neighbours(lattice) + if symmetry isa Type + H = @mpoham sum(J * S_exchange(ComplexF64, symmetry){i, j} for (i, j) in nearest_neighbours(lattice)) + + sum(S_exchange(ComplexF64, symmetry){i, j} for (i, j) in next_neighbours) + + sum(J3 * S_exchange(ComplexF64, symmetry){i, j} for (i, j) in third) + else + H = @mpoham sum(J * S_exchange(ComplexF64){i, j} for (i, j) in nearest_neighbours(lattice)) + + sum(S_exchange(ComplexF64){i, j} for (i, j) in next_neighbours) + + sum(J3 * S_exchange(ComplexF64){i, j} for (i, j) in third) + end + + return H +end +function linearize_index(lattice::Union{InfiniteCylinder, FiniteCylinder}, i::Int, j::Int) + row = if isodd(j) + i + else + lattice.L - i + 1 + end + return mod1(row, lattice.L) + lattice.L * (j - 1) +end + + +initial_bond_dim = 10 +symmetry = SU2Irrep +L = 8 +W = 24 + +if symmetry == SU2Irrep + physical_space = SU2Space(1 // 2 => 1) + virtual_space = SU2Space(0 => initial_bond_dim, 1 // 2 => initial_bond_dim, 1 => initial_bond_dim) + state = FiniteMPS(L * W, physical_space, virtual_space) +end; + +J = J2 = J3 = 1.0 +lattice = FiniteCylinder(L, L * W) +H = hamiltonian(J, J3, lattice; symmetry = symmetry) + +Dcut = 400 +groundstate, envs, delta = find_groundstate( + state, H, + DMRG2(; trscheme = truncdim(Dcut), maxiter = 5, tol = 1.0e-6, alg_eigsolve = (; krylovdim = 3, maxiter = 1)) +) + +save(filename, "groundstate", groundstate) + +return groundstate, envs diff --git a/scripts/Project.toml b/scripts/Project.toml new file mode 100644 index 000000000..755749b0c --- /dev/null +++ b/scripts/Project.toml @@ -0,0 +1,9 @@ +[deps] +BlockTensorKit = "5f87ffc2-9cf1-4a46-8172-465d160bd8cd" +MPSKit = "bb1c41ca-d63c-52ed-829e-0820dda26502" +MPSKitModels = "ca635005-6f8c-4cd1-b51d-8491250ef2ab" +TensorKit = "07d1fe3e-3e46-537d-9eac-e9e13d0d4cec" +TensorKitTensors = "41b62e7d-e9d1-4e23-942c-79a97adf954b" + +[sources] +MPSKit = {path = ".."} diff --git a/scripts/akshay.jl b/scripts/akshay.jl new file mode 100644 index 000000000..31c662d42 --- /dev/null +++ b/scripts/akshay.jl @@ -0,0 +1,132 @@ +using MPSKit, TensorKit +using TensorKitTensors.BosonOperators +using Test + +T = Float64 +cutoff = 3 +adag = b_plus(T, Trivial; cutoff) +a = b_min(T, Trivial; cutoff) + + +N = 6 +U = rand(N, N, N, N); +aaaa = FiniteMPO(adag ⊗ adag ⊗ a ⊗ a); +lattice = fill(BosonOperators.boson_space(Trivial; cutoff), N) + + +four_site_terms = Pair{NTuple{4, Int64}, typeof(aaaa)}[] +for l in 1:N, m in 1:N, n in 1:N, o in 1:N + # allunique((l, m, n, o)) || continue + # ((l == m) || (m == n) || (n == o) || (o == l)) && continue + push!(four_site_terms, (l, m, n, o) => U[l, m, n, o] * aaaa) +end + +H = FiniteMPOHamiltonian(lattice, four_site_terms); +@testset "Finite MPOHamiltonian repeated indices" begin + X = adag + Y = adag' + L = 4 + chain = fill(space(X, 1), 4) + + H1 = FiniteMPOHamiltonian(chain, (1,) => (X * X * Y * Y)) + H2 = FiniteMPOHamiltonian(chain, (1, 1, 1, 1) => (X ⊗ X ⊗ Y ⊗ Y)) + @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) + + H1 = FiniteMPOHamiltonian(chain, (1, 2) => ((X * Y) ⊗ (X * Y))) + H2 = FiniteMPOHamiltonian(chain, (1, 2, 1, 2) => (X ⊗ X ⊗ Y ⊗ Y)) + @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) + + H1 = FiniteMPOHamiltonian(chain, (1, 2) => ((X * X * Y) ⊗ Y)) + H2 = FiniteMPOHamiltonian(chain, (1, 1, 1, 2) => (X ⊗ X ⊗ Y ⊗ Y)) + @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) + + H1 = FiniteMPOHamiltonian(chain, (1, 2) => ((X * Y * Y) ⊗ X)) + H2 = FiniteMPOHamiltonian(chain, (1, 2, 1, 1) => (X ⊗ X ⊗ Y ⊗ Y)) + @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) + + H1 = FiniteMPOHamiltonian(chain, (1, 2, 3) => FiniteMPO((X * X) ⊗ Y ⊗ Y)) + H2 = FiniteMPOHamiltonian(chain, (1, 1, 2, 3) => FiniteMPO(X ⊗ X ⊗ Y ⊗ Y)) + @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) + + H1 = FiniteMPOHamiltonian(chain, (1, 2, 3) => FiniteMPO((Y * Y) ⊗ X ⊗ X)) + H2 = FiniteMPOHamiltonian(chain, (2, 3, 1, 1) => FiniteMPO(X ⊗ X ⊗ Y ⊗ Y)) + @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) + + H1 = FiniteMPOHamiltonian(chain, (1, 2, 3) => FiniteMPO(X ⊗ (X * Y) ⊗ Y)) + H2 = FiniteMPOHamiltonian(chain, (1, 2, 2, 3) => FiniteMPO(X ⊗ X ⊗ Y ⊗ Y)) + @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) +end + +function hamiltonian_int(N, cutoff, U) # interaction + adag = a_plus(ComplexF64, Trivial; cutoff = cutoff) + a = a_min(ComplexF64, Trivial; cutoff = cutoff) + + ops = [ + FiniteMPO(adag * adag * a * a), + FiniteMPO((adag * adag) ⊗ (a * a)), + FiniteMPO((adag * a) ⊗ (adag * a)), + FiniteMPO((adag * adag * a) ⊗ a), + FiniteMPO((adag * a * a) ⊗ adag), + FiniteMPO((adag * adag) ⊗ a ⊗ a), # + FiniteMPO((a * a) ⊗ adag ⊗ adag), # + FiniteMPO((adag * a) ⊗ adag ⊗ a), + FiniteMPO(adag ⊗ adag ⊗ a ⊗ a), + ] + + four_site_terms = Pair{NTuple{4, Int64}, FiniteMPO{TensorMap{ComplexF64, ComplexSpace, 2, 2, Vector{ComplexF64}}}}[] + for l in 1:N, m in 1:N, n in 1:N, o in 1:N + ((l == m) || (m == n) || (n == o) || (o == l)) && continue + push!(four_site_terms, (l, m, n, o) => U[l, m, n, o] * ops[9]) + end + + three_site_terms = Pair{NTuple{3, Int64}, FiniteMPO{TensorMap{ComplexF64, ComplexSpace, 2, 2, Vector{ComplexF64}}}}[] + for l in 1:N, m in 1:N, n in 1:N + ((l == m) || (m == n) || (n == l)) && continue + push!( + three_site_terms, + (l, m, n) => ( + (U[l, m, l, n] + U[l, m, n, l] + U[m, l, n, l] + U[m, l, l, n]) * ops[8] + + U[l, l, m, n] * ops[7] + + U[m, n, l, l] * ops[6] + ) + ) + end + + two_site_terms = Pair{NTuple{2, Int64}, FiniteMPO{TensorMap{ComplexF64, ComplexSpace, 2, 2, Vector{ComplexF64}}}}[] + for l in 1:N, m in 1:N + (l == m) && continue + push!( + two_site_terms, + (l, m) => ( + (U[l, m, l, l] + U[m, l, l, l]) * ops[5] + + (U[l, l, l, m] + U[l, l, m, l]) * ops[4] + + (U[l, m, l, m] + U[l, m, m, l]) * ops[3] + + U[l, l, m, m] * ops[2] + ) + ) + end + + one_site_terms = Pair{NTuple{1, Int64}, FiniteMPO{TensorMap{ComplexF64, ComplexSpace, 2, 2, Vector{ComplexF64}}}}[] + + for l in 1:N + push!(one_site_terms, (l,) => U[l, l, l, l] * ops[1]) + end + + return FiniteMPOHamiltonian(fill(ℂ^(cutoff + 1), N), one_site_terms..., two_site_terms..., three_site_terms..., four_site_terms...) +end + + +using TensorKit +using TensorKitTensors.SpinOperators + +Sp = S_plus() +Sm = S_min() +Sx = S_x() +Sy = S_y() +Sz = S_z() + + +H1 = Sx ⊗ Sx - Sy ⊗ Sy + Sz ⊗ Sz +H2 = (Sp ⊗ Sm + Sm ⊗ Sp) / 2 + Sz ⊗ Sz + +H1 ≈ H2 diff --git a/scripts/akshay2.jl b/scripts/akshay2.jl new file mode 100644 index 000000000..e8f233ac2 --- /dev/null +++ b/scripts/akshay2.jl @@ -0,0 +1,143 @@ +using MPSKit, MPSKitModels, TensorKit +using Random +using Test + +Random.seed!(123456) +L = 11 +T = ComplexF64 +chain = FiniteChain(L) +symmetry = Trivial +spin = 1 +J = 1 + +H = heisenberg_XXX(symmetry, chain; J, spin) + +physical_space = ℂ^3 +virtual_space = ℂ^1 +# A = zeros(ComplexF64, virtual_space ⊗ physical_space ← virtual_space) +# A.data .= [1, 0.1, -10.0] +# rand!(A.data) + +psi = FiniteMPS(rand, T, L, physical_space, virtual_space) +# psi = FiniteMPS(fill(A, L)) +gs, envs, delta = find_groundstate(psi, H, DMRG(; verbosity = 0)); + +Sx = S_x(T, symmetry; spin = 1) + +# E_x = map(eachindex(psi)) do i +# expectation_value(psi, i => Sx) +# end +# E_xx = map(eachindex(psi)) do i +# expectation_value(psi, (i,) => Sx^2) +# end +# E_xx2 = map(eachindex(psi)) do i +# Sx_normalized = add(Sx, id(space(Sx, 1)), -E_x[i]) +# expectation_value(psi, i => Sx_normalized^2) +# end + +# E_xx .- E_x .^ 2 +# E_xx2 +# test for random state D = 1 +for i in 1:length(chain) + # i = length(chain) ÷ 2 + E_x = expectation_value(psi, i => Sx) + E_xx = expectation_value(psi, (i,) => Sx^2) + E_xx2 = expectation_value(psi, (i,) => add(Sx, id(space(Sx, 1)), -E_x)^2) + + # @info i E_x E_xx E_xx - E_x^2 E_xx2 + @test E_xx - E_x^2 ≈ E_xx2 +end + +# test for groundstate D = 1 +gs, envs, delta = find_groundstate(psi, H, DMRG(; verbosity = 0)); +for i in 1:length(chain) + # i = length(chain) ÷ 2 + E_x = expectation_value(gs, i => Sx) + E_xx = expectation_value(gs, (i,) => Sx^2) + E_xx2 = expectation_value(gs, (i,) => add(Sx, id(space(Sx, 1)), -E_x)^2) + + # @info i E_x E_xx E_xx - E_x^2 E_xx2 + @test E_xx - E_x^2 ≈ E_xx2 +end + +virtual_space = ℂ^15 +psi = FiniteMPS(rand, T, L, physical_space, virtual_space) +for i in 1:length(chain) + # i = length(chain) ÷ 2 + E_x = expectation_value(psi, i => Sx) + E_xx = expectation_value(psi, (i,) => Sx^2) + E_xx2 = expectation_value(psi, (i,) => add(Sx, id(space(Sx, 1)), -E_x)^2) + + # @info i E_x E_xx E_xx - E_x^2 E_xx2 + @test E_xx - E_x^2 ≈ E_xx2 +end + +gs, envs, delta = find_groundstate(psi, H, DMRG(; verbosity = 0)); +for i in 1:length(chain) + # i = length(chain) ÷ 2 + E_x = expectation_value(gs, i => Sx) + E_xx = expectation_value(gs, (i,) => Sx^2) + E_xx2 = expectation_value(gs, (i,) => add(Sx, id(space(Sx, 1)), -E_x)^2) + + # @info i E_x E_xx E_xx - E_x^2 E_xx2 + @test E_xx - E_x^2 ≈ E_xx2 +end + +println() +#= +┌ Info: 1 +│ E_x = 0.9283027892120569 +│ E_xx = 0.9873406410374899 +│ E_xx - E_x ^ 2 = 0.1255945725786053 +└ E_xx2 = 0.1255945725786054 +┌ Info: 2 +│ E_x = 0.5958931587232229 +│ E_xx = 0.8842424256151229 +│ E_xx - E_x ^ 2 = 0.5291537690019827 +└ E_xx2 = 0.5291537690019827 +┌ Info: 3 +│ E_x = 0.9119512168846627 +│ E_xx = 0.9410385403620483 +│ E_xx - E_x ^ 2 = 0.10938351838463112 +└ E_xx2 = 0.10938351838463076 +┌ Info: 4 +│ E_x = 0.8475876798883178 +│ E_xx = 0.9998527656967889 +│ E_xx - E_x ^ 2 = 0.2814478905983274 +└ E_xx2 = 0.28144789059832703 +┌ Info: 5 +│ E_x = 0.5411573880001049 +│ E_xx = 0.5994538976943021 +│ E_xx - E_x ^ 2 = 0.306602579107206 +└ E_xx2 = 0.306602579107206 +┌ Info: 6 +│ E_x = 0.99952372893415 +│ E_xx = 0.9996661378739403 +│ E_xx - E_x ^ 2 = 0.0006184531715122121 +└ E_xx2 = 0.0006184531715116068 +┌ Info: 7 +│ E_x = 0.7484424712641702 +│ E_xx = 0.7491543238199131 +│ E_xx - E_x ^ 2 = 0.18898819102789488 +└ E_xx2 = 0.18898819102789452 +┌ Info: 8 +│ E_x = 0.9525317843713124 +│ E_xx = 0.9548671515022985 +│ E_xx - E_x ^ 2 = 0.047550351264702195 +└ E_xx2 = 0.04755035126470154 +┌ Info: 9 +│ E_x = 0.5371423149073694 +│ E_xx = 0.728001367170992 +│ E_xx - E_x ^ 2 = 0.43947950070694436 +└ E_xx2 = 0.43947950070694425 +┌ Info: 10 +│ E_x = 0.9289084036689698 +│ E_xx = 0.9917741739555096 +│ E_xx - E_x ^ 2 = 0.12890335154867594 +└ E_xx2 = 0.12890335154867597 +┌ Info: 11 +│ E_x = 0.748255413094344 +│ E_xx = 0.789444809740308 +│ E_xx - E_x ^ 2 = 0.22955864651532065 +└ E_xx2 = 0.2295586465153205 +=# diff --git a/scripts/antonio1.jl b/scripts/antonio1.jl new file mode 100644 index 000000000..6a19c5956 --- /dev/null +++ b/scripts/antonio1.jl @@ -0,0 +1,16 @@ +using TensorKit +using MPSKit +using MPSKitModels + +rows = 4 +cols = 4 + +J = -1 +g = 1 + +lattice = FiniteStrip(rows, rows * cols) +H = transverse_field_ising(lattice; J, g); + +vals, vecs, info = exact_diagonalization(H; num = 10); + +vals diff --git a/scripts/daniel.jl b/scripts/daniel.jl new file mode 100644 index 000000000..85613f3ec --- /dev/null +++ b/scripts/daniel.jl @@ -0,0 +1 @@ +using MPSKit, TensorKit, BlockTensorKit diff --git a/scripts/issue299.jl b/scripts/issue299.jl new file mode 100644 index 000000000..3895e6473 --- /dev/null +++ b/scripts/issue299.jl @@ -0,0 +1,20 @@ +using TensorKit +using MPSKit +using MPSKitModels: FiniteChain, hubbard_model + + +H_u1_su2 = hubbard_model(ComplexF64, U1Irrep, SU2Irrep, FiniteChain(4); U = 8.0, mu = 4.0, t = 1.0); +charges = fill(FermionParity(1) ⊠ U1Irrep(1) ⊠ SU2Irrep(0), 4); +H = MPSKit.add_physical_charge(H_u1_su2, charges); + +ρ₀ = MPSKit.infinite_temperature_density_matrix(H) +ρ_mps = convert(FiniteMPS, ρ₀) +βs = 0.0:0.2:8.0 +for i in 2:length(βs) + global ρ_mps + @info "Computing β = $(βs[i])" + ρ_mps, = timestep( + ρ_mps, H, βs[i - 1] / 2, -im * (βs[i] - βs[i - 1]) / 2, + TDVP2(; trscheme = truncdim(64)) + ) +end diff --git a/scripts/loic.jl b/scripts/loic.jl new file mode 100644 index 000000000..362ba79e4 --- /dev/null +++ b/scripts/loic.jl @@ -0,0 +1,42 @@ +using MPSKit, TensorKit, MPSKitModels + +function rydberg_model( + elt::Type{<:Number} = Float64, + lattice::AbstractLattice = InfiniteChain(1); + Delta = 0.0, Omega = 0.0, V = 1.0, fluctuation = 0 + ) + sz = S_z(elt, Trivial) + Id = id(elt, domain(sz)) + n = 0.5 * Id + sz + #Id = 2 * (n - sz) + sx = S_x(elt, Trivial) + + H = @mpoham begin + sum(vertices(lattice)) do i + return sum(V / j^6 * n{i} * n{i - j} for j in 1:10) + end + + sum(vertices(lattice)) do i + return -Delta * (1 + fluctuation * rand()) * n{i} - Omega * (1 + fluctuation * rand()) * sx{i} - 1 * Id{i} + end + end + return H +end + +L = 20; +x = 4; +y = 4; +Omega = 1 / y^6 +Delta = x * Omega +H0 = rydberg_model(Float64, InfiniteChain(2); Omega, Delta); +H = periodic_boundary_conditions(H0, L); + +# Htrunc = changebonds(H, SvdCut(; trscheme = truncbelow(1.0e-14))) + +mps = FiniteMPS([TensorMap(rand, ComplexF64, ComplexSpace(2) ⊗ ComplexSpace(2), ComplexSpace(2)) for j in 1:L]) +# mps = normalize!(FiniteMPS(rand, ComplexF64, fill(ℂ^2, L), ℂ^2)) + +# alg = DMRG2(; trscheme = truncdim(10), maxiter = 5, verbosity = 3, alg_eigsolve = (; verbosity = 2, dynamic_tols = false, tol = 1.0e-6)) +# gs, envs, delta = find_groundstate(mps, H, alg) + + +mps2 = approximate(mps, (H, mps), DMRG2(trscheme = truncbelow(1.0e-12))) diff --git a/scripts/profile_vumps.jl b/scripts/profile_vumps.jl new file mode 100644 index 000000000..4dbd57cf2 --- /dev/null +++ b/scripts/profile_vumps.jl @@ -0,0 +1,108 @@ +using TensorKit, MPSKit, MPSKitModels +using MPSKit: JordanMPOTensor +using BlockTensorKit +using BenchmarkTools +using MPSKit: DefaultBackend, DefaultAllocator, GrowingBuffer + +symmetry = SU2Irrep +T = Float64 +D = 2048 + +H = heisenberg_XXX(T, symmetry, InfiniteChain(2); spin = 1 // 2); +pspaces = physicalspace(H) +A = rand(oneunit(pspaces[1]) ⊗ pspaces[1] ⊗ pspaces[2] ← oneunit(pspaces[1])) +As = MPSKit.decompose_localmps(A, trunctol(atol = 1.0e-12)) +psi = InfiniteMPS(repeat(As, length(H) ÷ 2)); +psi, envs = find_groundstate(psi, H, IDMRG2(; maxiter = 100, trscheme = truncrank(D))); + +# regular application +function bench_single(psi, H, envs) + Hac2 = MPSKit.AC2_hamiltonian(1, psi, H, psi, envs) + ac2 = MPSKit.AC2(psi, 1; kind = :ACAR) + return @benchmark $Hac2 * $ac2 +end +function bench_prep(psi, H, envs; allocator = DefaultAllocator(), backend = DefaultBackend()) + Hac2 = MPSKit.AC2_hamiltonian(1, psi, H, psi, envs) + return @benchmark MPSKit.prepare_operator!!($Hac2, $backend, $allocator) +end +function bench_prepped(psi, H, envs; allocator = DefaultAllocator(), backend = DefaultBackend()) + Hac2 = MPSKit.prepare_operator!!(MPSKit.AC2_hamiltonian(1, psi, H, psi, envs), backend, allocator) + ac2 = MPSKit.AC2(psi, 1; kind = :ACAR) + return @benchmark $Hac2 * $ac2 +end +function densify(A::AbstractBlockTensorMap) + B = TensorMap(A) + return SparseBlockTensorMap(B, prod(SumSpace, codomain(B)) ← prod(SumSpace, domain(B))) +end +function densify(W::JordanMPOTensor) + A = densify(W.A) + B = densify(W.B) + C = densify(W.C) + D = densify(W.D) + S = spacetype(W) + Vl = oneunit(S) ⊞ left_virtualspace(A) ⊞ oneunit(S) + Vr = oneunit(S) ⊞ right_virtualspace(A) ⊞ oneunit(S) + + return JordanMPOTensor( + Vl ⊗ physicalspace(W) ← physicalspace(W) ⊗ Vr, + A, B, C, D + ) +end + +bench_single(psi, H, envs) +bench_prep(psi, H, envs) +bench_prepped(psi, H, envs) + +SS = MPSKitModels.S_exchange(T, symmetry; spin = 1 // 2); +H_nnn = InfiniteMPOHamiltonian(physicalspace(H), (1, 2) => SS, (1, 3) => SS); +H_larger = InfiniteMPOHamiltonian(physicalspace(H), (1, i) => SS for i in 2:10); +H_largest = InfiniteMPOHamiltonian(map(densify, H_larger)); +H_smallest = InfiniteMPOHamiltonian(map(densify, H)); + +envs_nnn = environments(psi, H_nnn); +envs_larger = environments(psi, H_larger); +envs_largest = environments(psi, H_largest); +envs_smallest = environments(psi, H_smallest); + + +b1 = bench_single(psi, H_nnn, envs_nnn) +b2 = bench_prep(psi, H_nnn, envs_nnn) +b3 = bench_prepped(psi, H_nnn, envs_nnn) + +allocator = GrowingBuffer() +b4 = bench_single(psi, H_larger, envs_larger) +b5 = bench_prep(psi, H_larger, envs_larger) +b5 = bench_prep(psi, H_larger, envs_larger; allocator) +b6 = bench_prepped(psi, H_larger, envs_larger) +@profview b6 = bench_prepped(psi, H_larger, envs_larger; allocator) + +b8 = bench_prep(psi, H_largest, envs_largest) + +allocator = GrowingBuffer() +b7 = bench_single(psi, H_largest, envs_largest) +b9 = bench_prepped(psi, H_largest, envs_largest) +b9 = bench_prepped(psi, H_largest, envs_largest; allocator) + +b10 = bench_single(psi, H_smallest, envs_smallest) +b11 = bench_prep(psi, H_smallest, envs_smallest) +b12 = bench_prepped(psi, H_smallest, envs_smallest) + +println("next-nearest neighbour") +b1 +b2 +b3 + +println("10 sites (sparse)") +b4 +b5 +b6 + +println("10 sites (dense)") +b7 +b8 +b9 + +println("nearest-neighbour (dense)") +b10 +b11 +b12 diff --git a/scripts/yanmong.jl b/scripts/yanmong.jl new file mode 100644 index 000000000..95ef24a61 --- /dev/null +++ b/scripts/yanmong.jl @@ -0,0 +1,34 @@ +using TensorKit +using CategoryData: Object, RepA4 +using MPSKit +using MPSKit.KrylovKit +using LinearAlgebra: eigvals + +I = Object{RepA4} +dim.(values(I)) # => (1, 1, 1, 3) +V = Vect[I](4 => 1) + +H_nn = randn(V ⊗ V ← V ⊗ V); +H_nn += H_nn'; # make it Hermitian + +H = H_nn ⊗ id(V) + id(V) ⊗ H_nn; # two-site Hamiltonian + +E_symm = eigvals(H) +E_dense = eigvals(reshape(convert(Array, H), dim(V)^3, dim(V)^3)) + +H_mpo = InfiniteMPOHamiltonian([V], (1, 2) => H_nn); +H_mpo_finite = open_boundary_conditions(H_mpo, 3); + +energies, states = exact_diagonalization(H_mpo_finite; num = 18); +x0 = rand(V^3); +vals, vecs, info = KrylovKit.eigsolve(x -> H * x, rand(V^3), 18, :SR); + +@info "Eigenvalues for different methods:" sort(energies; by = real) sort(vals; by = real) sort(E_symm[one(I)]; by = real) + +target_sector = I(4) +x0_charged = rand(V^3 ← Vect[I](target_sector => 1)) + +energies, states = exact_diagonalization(H_mpo_finite; num = 18, sector = target_sector); +vals, vecs, info = KrylovKit.eigsolve(x -> H * x, x0_charged, 18, :SR); + +@info "Eigenvalues for different methods:" sort(energies; by = real) sort(vals; by = real) sort(E_symm[target_sector]; by = real) diff --git a/src/algorithms/changebonds/optimalexpand.jl b/src/algorithms/changebonds/optimalexpand.jl index e5f299eeb..c33c358c4 100644 --- a/src/algorithms/changebonds/optimalexpand.jl +++ b/src/algorithms/changebonds/optimalexpand.jl @@ -26,8 +26,7 @@ function changebonds( AR′ = similar(ψ.AR, tensormaptype(spacetype(T), 1, numind(T) - 1, storagetype(T))) for i in 1:length(ψ) # determine optimal expansion spaces around bond i - AC2 = _transpose_front(ψ.AC[i]) * _transpose_tail(ψ.AR[i + 1]) - AC2 = AC2_hamiltonian(i, ψ, H, ψ, envs) * AC2 + AC2 = AC2_projection(i, ψ, H, ψ, envs; kind = :ACAR) # Use the nullspaces and SVD decomposition to determine the optimal expansion space VL = left_null(ψ.AL[i]) @@ -52,8 +51,7 @@ function changebonds(ψ::MultilineMPS, H, alg::OptimalExpand, envs = environment # determine optimal expansion spaces around bond i for i in 1:size(ψ, 1), j in 1:size(ψ, 2) - AC2 = _transpose_front(ψ.AC[i - 1, j]) * _transpose_tail(ψ.AR[i - 1, j + 1]) - AC2 = AC2_hamiltonian(CartesianIndex(i - 1, j), ψ, H, ψ, envs) * AC2 + AC2 = AC2_projection(CartesianIndex(i - 1, j), ψ, H, ψ, envs; kind = :ACAR) # Use the nullspaces and SVD decomposition to determine the optimal expansion space VL = left_null(ψ.AL[i, j]) @@ -81,8 +79,7 @@ function changebonds!(ψ::AbstractFiniteMPS, H, alg::OptimalExpand, envs = envir #so during optimization of site i, you have access to these optimal vectors :) for i in 1:(length(ψ) - 1) - AC2 = _transpose_front(ψ.AC[i]) * _transpose_tail(ψ.AR[i + 1]) - AC2 = AC2_hamiltonian(i, ψ, H, ψ, envs) * AC2 + AC2 = AC2_projection(i, ψ, H, ψ, envs) #Calculate nullspaces for left and right NL = left_null(ψ.AC[i]) diff --git a/src/algorithms/expval.jl b/src/algorithms/expval.jl index a9e25f16d..76f2ce901 100644 --- a/src/algorithms/expval.jl +++ b/src/algorithms/expval.jl @@ -209,8 +209,7 @@ function expectation_value( ) ens = zeros(scalartype(ψ), length(ψ)) for i in 1:length(ψ) - operator = AC_hamiltonian(i, ψ, O, ψ, envs) - ens[i] = dot(ψ.AC[i], operator * ψ.AC[i]) + ens[i] = dot(ψ.AC[i], AC_projection(i, ψ, O, ψ, envs)) end n = norm(ψ.AC[end])^2 return sum(ens) / (n * length(ψ)) diff --git a/src/algorithms/fidelity_susceptibility.jl b/src/algorithms/fidelity_susceptibility.jl index 6743a5d5a..22ef69912 100644 --- a/src/algorithms/fidelity_susceptibility.jl +++ b/src/algorithms/fidelity_susceptibility.jl @@ -22,7 +22,7 @@ function fidelity_susceptibility( Tos = LeftGaugedQP(rand, state) for (i, ac) in enumerate(state.AC) - temp = AC_hamiltonian(i, state, V, state, venvs) * ac + temp = AC_projection(i, state, V, state, venvs) help = fill_data!(similar(ac, auxiliaryspace(Tos)), one) @plansor Tos[i][-1 -2; -3 -4] := temp[-1 -2; -4] * help[-3] end diff --git a/src/algorithms/grassmann.jl b/src/algorithms/grassmann.jl index 58b548c06..939adace3 100644 --- a/src/algorithms/grassmann.jl +++ b/src/algorithms/grassmann.jl @@ -12,7 +12,7 @@ module GrassmannMPS using ..MPSKit using ..MPSKit: AbstractMPSEnvironments, InfiniteEnvironments, MultilineEnvironments, - AC_hamiltonian, recalculate! + AC_projection, recalculate! using TensorKit using OhMyThreads import TensorKitManifolds.Grassmann @@ -148,7 +148,7 @@ function fg( f = expectation_value(state, operator, envs) isapprox(imag(f), 0; atol = eps(abs(f))^(3 / 4)) || @warn "MPO might not be Hermitian: $f" gs = map(1:length(state)) do i - AC′ = AC_hamiltonian(i, state, operator, state, envs) * state.AC[i] + AC′ = AC_projection(i, state, operator, state, envs) g = Grassmann.project(AC′, state.AL[i]) return rmul(g, state.C[i]') end @@ -165,7 +165,7 @@ function fg( A = Core.Compiler.return_type(Grassmann.project, Tuple{eltype(state), eltype(state)}) gs = Vector{A}(undef, length(state)) tmap!(gs, 1:length(state); scheduler = MPSKit.Defaults.scheduler[]) do i - AC′ = AC_hamiltonian(i, state, operator, state, envs) * state.AC[i] + AC′ = AC_projection(i, state, operator, state, envs) g = Grassmann.project(AC′, state.AL[i]) return rmul(g, state.C[i]') end @@ -182,7 +182,7 @@ function fg( A = Core.Compiler.return_type(Grassmann.project, Tuple{eltype(state), eltype(state)}) gs = Vector{A}(undef, length(state)) tmap!(gs, eachindex(state); scheduler = MPSKit.Defaults.scheduler[]) do i - AC′ = AC_hamiltonian(i, state, operator, state, envs) * state.AC[i] + AC′ = AC_projection(i, state, operator, state, envs) g = rmul!(Grassmann.project(AC′, state.AL[i]), -inv(f)) return rmul(g, state.C[i]') end @@ -200,7 +200,7 @@ function fg( A = Core.Compiler.return_type(Grassmann.project, Tuple{eltype(state), eltype(state)}) gs = Matrix{A}(undef, size(state)) tforeach(eachindex(state); scheduler = MPSKit.Defaults.scheduler[]) do i - AC′ = AC_hamiltonian(i, state, operator, state, envs) * state.AC[i] + AC′ = AC_projection(i, state, operator, state, envs) g = rmul!(Grassmann.project(AC′, state.AL[i]), -inv(f)) gs[i] = rmul(g, state.C[i]') return nothing diff --git a/src/algorithms/groundstate/idmrg.jl b/src/algorithms/groundstate/idmrg.jl index 317c5053b..fab2c96da 100644 --- a/src/algorithms/groundstate/idmrg.jl +++ b/src/algorithms/groundstate/idmrg.jl @@ -155,7 +155,7 @@ function _localupdate_sweep_idmrg!(ψ, H, envs, alg_eigsolve) C_old = ψ.C[0] # left to right sweep for pos in 1:length(ψ) - h = prepare_operator!!(AC_hamiltonian(pos, ψ, H, ψ, envs)) + h = AC_hamiltonian(pos, ψ, H, ψ, envs) _, ψ.AC[pos] = fixedpoint(h, ψ.AC[pos], :SR, alg_eigsolve) if pos == length(ψ) # AC needed in next sweep @@ -168,7 +168,7 @@ function _localupdate_sweep_idmrg!(ψ, H, envs, alg_eigsolve) # right to left sweep for pos in length(ψ):-1:1 - h = prepare_operator!!(AC_hamiltonian(pos, ψ, H, ψ, envs)) + h = AC_hamiltonian(pos, ψ, H, ψ, envs) E, ψ.AC[pos] = fixedpoint(h, ψ.AC[pos], :SR, alg_eigsolve) ψ.C[pos - 1], temp = right_orth!(_transpose_tail(ψ.AC[pos]; copy = (pos == 1)); positive = true) @@ -184,7 +184,7 @@ function _localupdate_sweep_idmrg2!(ψ, H, envs, alg_eigsolve, alg_trscheme, alg # sweep from left to right for pos in 1:(length(ψ) - 1) ac2 = AC2(ψ, pos; kind = :ACAR) - h_ac2 = prepare_operator!!(AC2_hamiltonian(pos, ψ, H, ψ, envs)) + h_ac2 = AC2_hamiltonian(pos, ψ, H, ψ, envs) _, ac2′ = fixedpoint(h_ac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(ac2′; trunc = alg_trscheme, alg = alg_svd) @@ -203,7 +203,7 @@ function _localupdate_sweep_idmrg2!(ψ, H, envs, alg_eigsolve, alg_trscheme, alg ψ.AL[end] = ψ.AC[end] / ψ.C[end] ψ.AC[1] = _mul_tail(ψ.AL[1], ψ.C[1]) ac2 = AC2(ψ, 0; kind = :ALAC) - h_ac2 = prepare_operator!!(AC2_hamiltonian(0, ψ, H, ψ, envs)) + h_ac2 = AC2_hamiltonian(0, ψ, H, ψ, envs) _, ac2′ = fixedpoint(h_ac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(ac2′; trunc = alg_trscheme, alg = alg_svd) @@ -226,7 +226,7 @@ function _localupdate_sweep_idmrg2!(ψ, H, envs, alg_eigsolve, alg_trscheme, alg # sweep from right to left for pos in (length(ψ) - 1):-1:1 ac2 = AC2(ψ, pos; kind = :ALAC) - h_ac2 = prepare_operator!!(AC2_hamiltonian(pos, ψ, H, ψ, envs)) + h_ac2 = AC2_hamiltonian(pos, ψ, H, ψ, envs) _, ac2′ = fixedpoint(h_ac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(ac2′; trunc = alg_trscheme, alg = alg_svd) @@ -246,7 +246,7 @@ function _localupdate_sweep_idmrg2!(ψ, H, envs, alg_eigsolve, alg_trscheme, alg ψ.AC[end] = _mul_front(ψ.C[end - 1], ψ.AR[end]) ψ.AR[1] = _transpose_front(ψ.C[end] \ _transpose_tail(ψ.AC[1])) ac2 = AC2(ψ, 0; kind = :ACAR) - h_ac2 = prepare_operator!!(AC2_hamiltonian(0, ψ, H, ψ, envs)) + h_ac2 = AC2_hamiltonian(0, ψ, H, ψ, envs) E, ac2′ = fixedpoint(h_ac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(ac2′; trunc = alg_trscheme, alg = alg_svd) normalize!(c) diff --git a/src/algorithms/groundstate/vumps.jl b/src/algorithms/groundstate/vumps.jl index bc4f6af9b..99da8234c 100644 --- a/src/algorithms/groundstate/vumps.jl +++ b/src/algorithms/groundstate/vumps.jl @@ -130,9 +130,9 @@ function _localupdate_vumps_step!( alg_eigsolve = Defaults.eigsolver, which ) if !parallel - Hac = prepare_operator!!(AC_hamiltonian(site, mps, operator, mps, envs)) + Hac = AC_hamiltonian(site, mps, operator, mps, envs) _, AC = fixedpoint(Hac, AC₀, which, alg_eigsolve) - Hc = prepare_operator!!(C_hamiltonian(site, mps, operator, mps, envs)) + Hc = C_hamiltonian(site, mps, operator, mps, envs) _, C = fixedpoint(Hc, C₀, which, alg_eigsolve) return regauge!(AC, C; alg = alg_orth) end @@ -140,11 +140,11 @@ function _localupdate_vumps_step!( local AC, C @sync begin @spawn begin - Hac = prepare_operator!!(AC_hamiltonian(site, mps, operator, mps, envs)) + Hac = AC_hamiltonian(site, mps, operator, mps, envs) _, AC = fixedpoint(Hac, AC₀, which, alg_eigsolve) end @spawn begin - Hc = prepare_operator!!(C_hamiltonian(site, mps, operator, mps, envs)) + Hc = C_hamiltonian(site, mps, operator, mps, envs) _, C = fixedpoint(Hc, C₀, which, alg_eigsolve) end end diff --git a/src/algorithms/statmech/vomps.jl b/src/algorithms/statmech/vomps.jl index 8849d74da..ed738ebf5 100644 --- a/src/algorithms/statmech/vomps.jl +++ b/src/algorithms/statmech/vomps.jl @@ -104,15 +104,13 @@ function localupdate_step!( ) alg_orth = Defaults.alg_qr() mps = state.mps - src_Cs = mps isa Multiline ? eachcol(mps.C) : mps.C - src_ACs = mps isa Multiline ? eachcol(mps.AC) : mps.AC ACs = similar(mps.AC) dst_ACs = state.mps isa Multiline ? eachcol(ACs) : ACs - tforeach(eachsite(mps), src_ACs, src_Cs; scheduler) do site, AC₀, C₀ + tforeach(eachsite(mps); scheduler) do site dst_ACs[site] = _localupdate_vomps_step!( - site, mps, state.operator, state.envs, - AC₀, C₀; alg_orth, parallel = false + site, mps, state.operator, state.envs; + alg_orth, parallel = false ) return nothing end @@ -121,18 +119,18 @@ function localupdate_step!( end function _localupdate_vomps_step!( - site, mps, operator, envs, AC₀, C₀; parallel::Bool = false, alg_orth = Defaults.alg_qr() + site, mps, operator, envs; parallel::Bool = false, alg_orth = Defaults.alg_qr() ) if !parallel - AC = AC_hamiltonian(site, mps, operator, mps, envs) * AC₀ - C = C_hamiltonian(site, mps, operator, mps, envs) * C₀ + AC = AC_projection(site, mps, operator, mps, envs) + C = C_projection(site, mps, operator, mps, envs) return regauge!(AC, C; alg = alg_orth) end local AC, C @sync begin - @spawn AC = AC_hamiltonian(site, mps, operator, mps, envs) * AC₀ - @spawn C = C_hamiltonian(site, mps, operator, mps, envs) * C₀ + @spawn AC = AC_projection(site, mps, operator, mps, envs) + @spawn C = C_projection(site, mps, operator, mps, envs) end return regauge!(AC, C; alg = alg_orth) end diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index 4f548dada..f24d6230a 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -58,7 +58,7 @@ Concretely, this is the overlap of the current state with the single-site deriva function calc_galerkin( pos::Int, below::Union{InfiniteMPS, FiniteMPS, WindowMPS}, operator, above, envs ) - AC´ = AC_hamiltonian(pos, below, operator, above, envs) * above.AC[pos] + AC´ = AC_projection(pos, below, operator, above, envs) normalize!(AC´) out = mul!(AC´, below.AL[pos], below.AL[pos]' * AC´, -1, +1) return norm(out) diff --git a/src/environments/infinite_envs.jl b/src/environments/infinite_envs.jl index 3cd249ba1..17cf3de07 100644 --- a/src/environments/infinite_envs.jl +++ b/src/environments/infinite_envs.jl @@ -125,8 +125,7 @@ function TensorKit.normalize!( ) for i in 1:length(operator) normalize!(envs.GRs[i]) - Hc = C_hamiltonian(i, below, operator, above, envs) - λ = dot(below.C[i], Hc * above.C[i]) + λ = dot(below.C[i], C_projection(i, below, operator, above, envs)) scale!(envs.GLs[i + 1], inv(λ)) end return envs From 2e38a93207899a5c04c679a8f568d6475e7ae572 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Thu, 26 Feb 2026 15:32:08 -0500 Subject: [PATCH 32/37] replace allocator with TensorOperations implementation --- Project.toml | 2 +- src/MPSKit.jl | 3 +- src/algorithms/derivatives/derivatives.jl | 6 ++- src/utility/allocator.jl | 66 ----------------------- 4 files changed, 6 insertions(+), 71 deletions(-) delete mode 100644 src/utility/allocator.jl diff --git a/Project.toml b/Project.toml index cbd3a1015..d12ad0abf 100644 --- a/Project.toml +++ b/Project.toml @@ -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" diff --git a/src/MPSKit.jl b/src/MPSKit.jl index 96ed23cb4..302552b14 100644 --- a/src/MPSKit.jl +++ b/src/MPSKit.jl @@ -66,7 +66,7 @@ using MatrixAlgebraKit: TruncationStrategy, PolarViaSVD, LAPACK_SVDAlgorithm using BlockTensorKit using BlockTensorKit: TensorMapSumSpace using TensorOperations -using TensorOperations: AbstractBackend, DefaultBackend, DefaultAllocator +using TensorOperations: AbstractBackend, DefaultBackend, DefaultAllocator, BufferAllocator using KrylovKit using KrylovKit: KrylovAlgorithm using OptimKit @@ -99,7 +99,6 @@ include("utility/logging.jl") using .IterativeLoggers include("utility/iterativesolvers.jl") -include("utility/allocator.jl") include("utility/styles.jl") include("utility/periodicarray.jl") include("utility/windowarray.jl") diff --git a/src/algorithms/derivatives/derivatives.jl b/src/algorithms/derivatives/derivatives.jl index b5eb4fa2b..7bd11aef4 100644 --- a/src/algorithms/derivatives/derivatives.jl +++ b/src/algorithms/derivatives/derivatives.jl @@ -222,6 +222,8 @@ Base.:*(h::LazySum{<:Union{DerivativeOrMultiplied}}, v) = h(v) """ prepare_operator!!(O, [backend], [allocator]) -> O′ -Given an operator, try to construct a more efficient representation of that operator for repeated application. +Given an operator, try to construct a more efficient representation of that operator. +This typically consists of precomputing some parts of the application, +and is expected to only pay off for repeated applications. """ -prepare_operator!!(O, backend::AbstractBackend = DefaultBackend(), allocator = GrowingBuffer()) = O +prepare_operator!!(O, backend::AbstractBackend = DefaultBackend(), allocator = BufferAllocator()) = O diff --git a/src/utility/allocator.jl b/src/utility/allocator.jl deleted file mode 100644 index bf5d601ce..000000000 --- a/src/utility/allocator.jl +++ /dev/null @@ -1,66 +0,0 @@ -const BufType = @static isdefined(Core, :Memory) ? Memory{UInt8} : Vector{UInt8} - -# Note: due to OS memory paging, we are only taking up virtual memory address space -# and not necessarily asking for physical memory here - it should therefore make sense -# to have a somewhat large default value -const DEFAULT_SIZEHINT = Ref(2^30) # 1GB - -mutable struct GrowingBuffer - buffer::BufType - offset::UInt - function GrowingBuffer(; sizehint = DEFAULT_SIZEHINT[]) - buffer = BufType(undef, sizehint) - return new(buffer, zero(UInt)) - end -end - -Base.length(buffer::GrowingBuffer) = length(buffer.buffer) -Base.pointer(buffer::GrowingBuffer) = pointer(buffer.buffer) + buffer.offset - -function Base.sizehint!(buffer::GrowingBuffer, n::Integer; shrink::Bool = false) - n > 0 || throw(ArgumentError("invalid new buffer size")) - buffer.offset == 0 || error("cannot resize a buffer that is not fully reset") - - n = shrink ? max(n, length(buffer)) : n - n = Int(Base.nextpow(2, n)) - - @static if isdefined(Core, :Memory) - buffer.buffer = BufType(undef, n) - else - sizehint!(buffer.buffer, n) - end - return buffer -end - -checkpoint(buffer) = zero(UInt) -reset!(buffer, checkpoint::UInt = zero(UInt)) = buffer - -checkpoint(buffer::GrowingBuffer) = buffer.offset - -function reset!(buffer::GrowingBuffer, checkpoint::UInt = zero(UInt)) - if iszero(checkpoint) && buffer.offset > length(buffer) - # full reset - check for need to grow - newlength = Base.nextpow(2, buffer.offset) # round to nearest larger power of 2 - buffer.offset = checkpoint - sizehint!(buffer, newlength) - else - buffer.offset = checkpoint - end - return buffer -end - -# Allocating -# ---------- -function TensorOperations.tensoralloc( - ::Type{A}, structure, ::Val{istemp}, buffer::GrowingBuffer - ) where {A <: AbstractArray, istemp} - T = eltype(A) - if istemp - ptr = convert(Ptr{T}, pointer(buffer)) - buffer.offset += prod(structure) * sizeof(T) - buffer.offset < length(buffer) && - return Base.unsafe_wrap(Array, ptr, structure) - end - return A(undef, structure) -end -TensorOperations.tensorfree!(::AbstractArray, ::GrowingBuffer) = nothing From c06f64df057b4c289bf157941cc9cf52c96bd4de Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 27 Feb 2026 11:43:22 -0500 Subject: [PATCH 33/37] updates, possibly working now? clean up --- scripts/ITensorsCode.jl | 160 ------------------ scripts/MPSKitCode.jl | 139 --------------- scripts/Project.toml | 9 - scripts/akshay.jl | 132 --------------- scripts/akshay2.jl | 143 ---------------- scripts/antonio1.jl | 16 -- scripts/daniel.jl | 1 - scripts/issue299.jl | 20 --- scripts/loic.jl | 42 ----- scripts/profile_vumps.jl | 108 ------------ scripts/yanmong.jl | 34 ---- src/MPSKit.jl | 3 +- src/algorithms/changebonds/vumpssvd.jl | 4 +- src/algorithms/derivatives/derivatives.jl | 29 ++-- .../derivatives/hamiltonian_derivatives.jl | 30 +++- src/algorithms/derivatives/mpo_derivatives.jl | 101 +++++++---- src/algorithms/groundstate/dmrg.jl | 6 +- src/algorithms/statmech/idmrg.jl | 12 +- src/algorithms/timestep/tdvp.jl | 28 +-- src/utility/utility.jl | 16 +- 20 files changed, 152 insertions(+), 881 deletions(-) delete mode 100644 scripts/ITensorsCode.jl delete mode 100644 scripts/MPSKitCode.jl delete mode 100644 scripts/Project.toml delete mode 100644 scripts/akshay.jl delete mode 100644 scripts/akshay2.jl delete mode 100644 scripts/antonio1.jl delete mode 100644 scripts/daniel.jl delete mode 100644 scripts/issue299.jl delete mode 100644 scripts/loic.jl delete mode 100644 scripts/profile_vumps.jl delete mode 100644 scripts/yanmong.jl diff --git a/scripts/ITensorsCode.jl b/scripts/ITensorsCode.jl deleted file mode 100644 index 863bc4b1d..000000000 --- a/scripts/ITensorsCode.jl +++ /dev/null @@ -1,160 +0,0 @@ -mutable struct FiniteCylinder - L::Int - N::Int -end -function linearize_index(lattice::FiniteCylinder, i, j) - row = if isodd(j) - i - else - lattice.L - i + 1 - end - return mod1(row, lattice.L) + lattice.L * (j - 1) -end -function inverse_linearize_index(lattice::FiniteCylinder, idx::Int) - L = lattice.L - j = div(idx - 1, L) + 1 - row = mod1(idx, L) - - i = if isodd(j) - row - else - L - row + 1 - end - - return i, j -end -function Shastry_Sutherland_neighbor(Lx, Ly) - N = Lx * Ly - mat = reshape(collect(1:N), Ly, Lx) - - - for i in 2:2:Lx - mat[:, i] .= reverse(mat[:, i]) - end - - horizontal_neighbors = [(mat[i, j], mat[i, j + 1]) for i in 1:Ly, j in 1:(Lx - 1)] - vertical_neighbors = [(mat[i, j], mat[i < Ly ? i + 1 : 1, j]) for i in 1:Ly, j in 1:Lx] - - return vcat(vec(horizontal_neighbors), vec(vertical_neighbors)) - # return neighbours -end -function Shastry_Sutherland_next_neighbor(Lx, Ly) - N = Lx * Ly - mat = reshape(collect(1:N), Ly, Lx) - - - for i in 2:2:Lx - mat[:, i] .= reverse(mat[:, i]) - end - - neighbors = [] - for i in 1:2:(Lx - 1) - for j in 1:2:Ly - if j < Ly - push!(neighbors, (mat[j, i], mat[j + 1, i + 1])) - else - push!(neighbors, (mat[j, i], mat[1, mod1(i + 1, Lx)])) - end - end - end - for i in 2:2:(Lx - 1) - for j in 1:2:Ly - push!(neighbors, (mat[j, i], mat[mod1(j - 1, Ly), mod1(i + 1, Lx)])) - end - end - return neighbors - # return neighbours -end -function third_neighbor(Lx, Ly) - N = Lx * Ly - mat = reshape(collect(1:N), Ly, Lx) - - - for i in 2:2:Lx - mat[:, i] .= reverse(mat[:, i]) - end - - horizontal_neighbors = [(mat[i, j], mat[i, j + 2]) for i in 1:Ly, j in 1:(Lx - 2)] - vertical_neighbors = [(mat[i, j], mat[mod1(i + 2, Ly), j]) for i in 1:Ly, j in 1:Lx] - return vcat(vec(horizontal_neighbors), vec(vertical_neighbors)) - -end -function hamiltonian(sites, Lx, Ly, Jxy, Jz, Jnx, Jnz, J3nx, J3nz, h) - neighbors = Shastry_Sutherland_neighbor(Lx, Ly) - next_neighbors = Shastry_Sutherland_next_neighbor(Lx, Ly) - third_neighbors = third_neighbor(Lx, Ly) - H = OpSum() - for (i, j) in neighbors - # H += Jxy, "Sx", i, "Sx", j - # H += Jxy, "Sy", i, "Sy", j - H += 0.5 * Jxy, "S+", i, "S-", j - H += 0.5 * Jxy, "S-", i, "S+", j - H += Jz, "Sz", i, "Sz", j - end - for (i, j) in next_neighbors - H += 0.5 * Jnx, "S+", i, "S-", j - H += 0.5 * Jnx, "S-", i, "S+", j - # H += Jnx, "Sx", i, "Sx", j - # H += Jnx, "Sy", i, "Sy", j - H += Jnz, "Sz", i, "Sz", j - end - for (i, j) in third_neighbors - H += 0.5 * J3nx, "S+", i, "S-", j - H += 0.5 * J3nx, "S-", i, "S+", j - # H += J3nx, "Sx", i, "Sx", j - # H += J3nx, "Sy", i, "Sy", j - H += J3nz, "Sz", i, "Sz", j - end - for i in 1:(Lx * Ly) - H += h, "Sz", i - end - - return ITensorMPS.MPO(H, sites) -end -function main(Lx, Ly, Δ, J1z, J2z, J3z, hz, Dcut; inistate = []) - symmetry = true - J1x = J1z - J2x = J2z - J3x = J3z - Lx = Lx - - nsweeps = 10 - if isempty(inistate) - if symmetry == true - sites = siteinds("S=1/2", Lx * Ly, conserve_qns = true) - initialstate = [isodd(n) ? "Up" : "Dn" for n in 1:(Lx * Ly)] - psi0 = random_mps(sites, initialstate; linkdims = Dcut) - else - sites = siteinds("S=1/2", Lx * Ly, conserve_qns = false) - psi0 = random_mps(sites, linkdims = Dcut) - end - maxdim = Int[Dcut + div(i, 2) * (Dcut // 1) for i in 2:(nsweeps + 1)] - else - psi0 = inistate - - sites = siteinds(psi) - D = maximum(linkdims(psi0)) - maxdim = Int[D + div(i, 2) * (Dcut // 1) for i in 2:(nsweeps + 1)] - end - - - # maxdim = vcat(repeat([Dcut], 3), repeat([2*Dcut], 4), repeat([4 *Dcut], 5)) - - cutoff = [1.0e-10] - println("##################################################") - println("Starting DMRG") - println("J1 = $J1x, J2 = $J2x, J3 = $J3x, Lx = $Lx, Ly = $Ly, Dcut = $Dcut, hz = $hz") - - ham = hamiltonian(sites, Lx, Ly, J1x, J1z, J2x, J2z, J3x, J3z, hz) - - energy, psi = dmrg(ham, psi0; nsweeps, maxdim, cutoff, outputlevel = 1) - - - filename = "./rslt/" - magz = expect(psi, "Sz") - - WF_filename = filename * "WF_J1=$(J1z)_J3=$(J3z)_Lx=$(Lx)_Ly=$(Ly)_Dcut=$(Dcut)_hz=$(hz).jld2" - save(WF_filename, "psi", psi, "bond_pl", bond_pl, "bond_dm", bond_dm, "magz", magz, "corr", corr) - GC.gc() - return -end diff --git a/scripts/MPSKitCode.jl b/scripts/MPSKitCode.jl deleted file mode 100644 index 2de7b70a7..000000000 --- a/scripts/MPSKitCode.jl +++ /dev/null @@ -1,139 +0,0 @@ -using MPSKitModels - -function Shastry_Sutherland_next_neighbor(lattice::InfiniteCylinder) - rows = lattice.L - cols = lattice.N ÷ lattice.L - V = vertices(lattice) - neighbours = Pair{eltype(V), eltype(V)}[] - for i in 1:2:(rows - 1) - for j in 1:2:cols - if i < rows - push!(neighbours, LatticePoint((i, j), lattice) => LatticePoint((i + 1, j + 1), lattice)) - else - push!(neighbours, LatticePoint((i, j), lattice) => LatticePoint((1, mod1(j + 1, rows)), lattice)) - end - end - end - for i in 2:2:cols - for j in 1:2:rows - # push!(neighbors, (mat[j, i], mat[mod1(j - 1, Ly), mod1(i + 1, Lx)])) - push!(neighbours, LatticePoint((j, i), lattice) => LatticePoint((mod1(j - 1, rows), i + 1), lattice)) - end - end - return neighbours - # return neighbours -end -function third_neighbours(lattice::InfiniteCylinder) - V = vertices(lattice) - neighbours = Pair{eltype(V), eltype(V)}[] - for v in V - push!(neighbours, v => v + (0, 2)) - if v.coordinates[1] < lattice.L || - lattice isa InfiniteCylinder || - lattice isa InfiniteHelix - push!(neighbours, v => v + (2, 0)) - end - end - return neighbours -end - -function Shastry_Sutherland_next_neighbor(lattice::FiniteCylinder) - rows = lattice.L - cols = lattice.N ÷ lattice.L - V = vertices(lattice) - neighbours = Pair{eltype(V), eltype(V)}[] - for i in 1:2:(rows - 1) - for j in 1:2:cols - if i < rows - push!(neighbours, LatticePoint((i, j), lattice) => LatticePoint((i + 1, j + 1), lattice)) - else - push!(neighbours, LatticePoint((i, j), lattice) => LatticePoint((1, mod1(j + 1, rows)), lattice)) - end - end - end - for i in 2:2:(cols - 1) - for j in 1:2:rows - # push!(neighbors, (mat[j, i], mat[mod1(j - 1, Ly), mod1(i + 1, Lx)])) - push!(neighbours, LatticePoint((j, i), lattice) => LatticePoint((mod1(j - 1, rows), i + 1), lattice)) - end - end - return neighbours - # return neighbours -end - -function third_neighbours(lattice::FiniteCylinder) - V = vertices(lattice) - neighbours = Pair{eltype(V), eltype(V)}[] - for v in V - if v.coordinates[2] < lattice.N / lattice.L - 1 - push!(neighbours, v => v + (0, 2)) - end - # if v.coordinates[1] < lattice.L - push!(neighbours, v => v + (2, 0)) - # end - end - return neighbours -end - -function inverse_linearize_index(lattice::Union{InfiniteCylinder, FiniteCylinder}, idx::Int) - L = lattice.L - j = div(idx - 1, L) + 1 - row = mod1(idx, L) - - i = if isodd(j) - row - else - L - row + 1 - end - - return i, j -end -function hamiltonian(J, J3, lattice; symmetry = []) - next_neighbours = Shastry_Sutherland_next_neighbor(lattice) - third = third_neighbours(lattice) - if symmetry isa Type - H = @mpoham sum(J * S_exchange(ComplexF64, symmetry){i, j} for (i, j) in nearest_neighbours(lattice)) + - sum(S_exchange(ComplexF64, symmetry){i, j} for (i, j) in next_neighbours) + - sum(J3 * S_exchange(ComplexF64, symmetry){i, j} for (i, j) in third) - else - H = @mpoham sum(J * S_exchange(ComplexF64){i, j} for (i, j) in nearest_neighbours(lattice)) + - sum(S_exchange(ComplexF64){i, j} for (i, j) in next_neighbours) + - sum(J3 * S_exchange(ComplexF64){i, j} for (i, j) in third) - end - - return H -end -function linearize_index(lattice::Union{InfiniteCylinder, FiniteCylinder}, i::Int, j::Int) - row = if isodd(j) - i - else - lattice.L - i + 1 - end - return mod1(row, lattice.L) + lattice.L * (j - 1) -end - - -initial_bond_dim = 10 -symmetry = SU2Irrep -L = 8 -W = 24 - -if symmetry == SU2Irrep - physical_space = SU2Space(1 // 2 => 1) - virtual_space = SU2Space(0 => initial_bond_dim, 1 // 2 => initial_bond_dim, 1 => initial_bond_dim) - state = FiniteMPS(L * W, physical_space, virtual_space) -end; - -J = J2 = J3 = 1.0 -lattice = FiniteCylinder(L, L * W) -H = hamiltonian(J, J3, lattice; symmetry = symmetry) - -Dcut = 400 -groundstate, envs, delta = find_groundstate( - state, H, - DMRG2(; trscheme = truncdim(Dcut), maxiter = 5, tol = 1.0e-6, alg_eigsolve = (; krylovdim = 3, maxiter = 1)) -) - -save(filename, "groundstate", groundstate) - -return groundstate, envs diff --git a/scripts/Project.toml b/scripts/Project.toml deleted file mode 100644 index 755749b0c..000000000 --- a/scripts/Project.toml +++ /dev/null @@ -1,9 +0,0 @@ -[deps] -BlockTensorKit = "5f87ffc2-9cf1-4a46-8172-465d160bd8cd" -MPSKit = "bb1c41ca-d63c-52ed-829e-0820dda26502" -MPSKitModels = "ca635005-6f8c-4cd1-b51d-8491250ef2ab" -TensorKit = "07d1fe3e-3e46-537d-9eac-e9e13d0d4cec" -TensorKitTensors = "41b62e7d-e9d1-4e23-942c-79a97adf954b" - -[sources] -MPSKit = {path = ".."} diff --git a/scripts/akshay.jl b/scripts/akshay.jl deleted file mode 100644 index 31c662d42..000000000 --- a/scripts/akshay.jl +++ /dev/null @@ -1,132 +0,0 @@ -using MPSKit, TensorKit -using TensorKitTensors.BosonOperators -using Test - -T = Float64 -cutoff = 3 -adag = b_plus(T, Trivial; cutoff) -a = b_min(T, Trivial; cutoff) - - -N = 6 -U = rand(N, N, N, N); -aaaa = FiniteMPO(adag ⊗ adag ⊗ a ⊗ a); -lattice = fill(BosonOperators.boson_space(Trivial; cutoff), N) - - -four_site_terms = Pair{NTuple{4, Int64}, typeof(aaaa)}[] -for l in 1:N, m in 1:N, n in 1:N, o in 1:N - # allunique((l, m, n, o)) || continue - # ((l == m) || (m == n) || (n == o) || (o == l)) && continue - push!(four_site_terms, (l, m, n, o) => U[l, m, n, o] * aaaa) -end - -H = FiniteMPOHamiltonian(lattice, four_site_terms); -@testset "Finite MPOHamiltonian repeated indices" begin - X = adag - Y = adag' - L = 4 - chain = fill(space(X, 1), 4) - - H1 = FiniteMPOHamiltonian(chain, (1,) => (X * X * Y * Y)) - H2 = FiniteMPOHamiltonian(chain, (1, 1, 1, 1) => (X ⊗ X ⊗ Y ⊗ Y)) - @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) - - H1 = FiniteMPOHamiltonian(chain, (1, 2) => ((X * Y) ⊗ (X * Y))) - H2 = FiniteMPOHamiltonian(chain, (1, 2, 1, 2) => (X ⊗ X ⊗ Y ⊗ Y)) - @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) - - H1 = FiniteMPOHamiltonian(chain, (1, 2) => ((X * X * Y) ⊗ Y)) - H2 = FiniteMPOHamiltonian(chain, (1, 1, 1, 2) => (X ⊗ X ⊗ Y ⊗ Y)) - @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) - - H1 = FiniteMPOHamiltonian(chain, (1, 2) => ((X * Y * Y) ⊗ X)) - H2 = FiniteMPOHamiltonian(chain, (1, 2, 1, 1) => (X ⊗ X ⊗ Y ⊗ Y)) - @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) - - H1 = FiniteMPOHamiltonian(chain, (1, 2, 3) => FiniteMPO((X * X) ⊗ Y ⊗ Y)) - H2 = FiniteMPOHamiltonian(chain, (1, 1, 2, 3) => FiniteMPO(X ⊗ X ⊗ Y ⊗ Y)) - @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) - - H1 = FiniteMPOHamiltonian(chain, (1, 2, 3) => FiniteMPO((Y * Y) ⊗ X ⊗ X)) - H2 = FiniteMPOHamiltonian(chain, (2, 3, 1, 1) => FiniteMPO(X ⊗ X ⊗ Y ⊗ Y)) - @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) - - H1 = FiniteMPOHamiltonian(chain, (1, 2, 3) => FiniteMPO(X ⊗ (X * Y) ⊗ Y)) - H2 = FiniteMPOHamiltonian(chain, (1, 2, 2, 3) => FiniteMPO(X ⊗ X ⊗ Y ⊗ Y)) - @test convert(TensorMap, H1) ≈ convert(TensorMap, H2) -end - -function hamiltonian_int(N, cutoff, U) # interaction - adag = a_plus(ComplexF64, Trivial; cutoff = cutoff) - a = a_min(ComplexF64, Trivial; cutoff = cutoff) - - ops = [ - FiniteMPO(adag * adag * a * a), - FiniteMPO((adag * adag) ⊗ (a * a)), - FiniteMPO((adag * a) ⊗ (adag * a)), - FiniteMPO((adag * adag * a) ⊗ a), - FiniteMPO((adag * a * a) ⊗ adag), - FiniteMPO((adag * adag) ⊗ a ⊗ a), # - FiniteMPO((a * a) ⊗ adag ⊗ adag), # - FiniteMPO((adag * a) ⊗ adag ⊗ a), - FiniteMPO(adag ⊗ adag ⊗ a ⊗ a), - ] - - four_site_terms = Pair{NTuple{4, Int64}, FiniteMPO{TensorMap{ComplexF64, ComplexSpace, 2, 2, Vector{ComplexF64}}}}[] - for l in 1:N, m in 1:N, n in 1:N, o in 1:N - ((l == m) || (m == n) || (n == o) || (o == l)) && continue - push!(four_site_terms, (l, m, n, o) => U[l, m, n, o] * ops[9]) - end - - three_site_terms = Pair{NTuple{3, Int64}, FiniteMPO{TensorMap{ComplexF64, ComplexSpace, 2, 2, Vector{ComplexF64}}}}[] - for l in 1:N, m in 1:N, n in 1:N - ((l == m) || (m == n) || (n == l)) && continue - push!( - three_site_terms, - (l, m, n) => ( - (U[l, m, l, n] + U[l, m, n, l] + U[m, l, n, l] + U[m, l, l, n]) * ops[8] + - U[l, l, m, n] * ops[7] + - U[m, n, l, l] * ops[6] - ) - ) - end - - two_site_terms = Pair{NTuple{2, Int64}, FiniteMPO{TensorMap{ComplexF64, ComplexSpace, 2, 2, Vector{ComplexF64}}}}[] - for l in 1:N, m in 1:N - (l == m) && continue - push!( - two_site_terms, - (l, m) => ( - (U[l, m, l, l] + U[m, l, l, l]) * ops[5] + - (U[l, l, l, m] + U[l, l, m, l]) * ops[4] + - (U[l, m, l, m] + U[l, m, m, l]) * ops[3] + - U[l, l, m, m] * ops[2] - ) - ) - end - - one_site_terms = Pair{NTuple{1, Int64}, FiniteMPO{TensorMap{ComplexF64, ComplexSpace, 2, 2, Vector{ComplexF64}}}}[] - - for l in 1:N - push!(one_site_terms, (l,) => U[l, l, l, l] * ops[1]) - end - - return FiniteMPOHamiltonian(fill(ℂ^(cutoff + 1), N), one_site_terms..., two_site_terms..., three_site_terms..., four_site_terms...) -end - - -using TensorKit -using TensorKitTensors.SpinOperators - -Sp = S_plus() -Sm = S_min() -Sx = S_x() -Sy = S_y() -Sz = S_z() - - -H1 = Sx ⊗ Sx - Sy ⊗ Sy + Sz ⊗ Sz -H2 = (Sp ⊗ Sm + Sm ⊗ Sp) / 2 + Sz ⊗ Sz - -H1 ≈ H2 diff --git a/scripts/akshay2.jl b/scripts/akshay2.jl deleted file mode 100644 index e8f233ac2..000000000 --- a/scripts/akshay2.jl +++ /dev/null @@ -1,143 +0,0 @@ -using MPSKit, MPSKitModels, TensorKit -using Random -using Test - -Random.seed!(123456) -L = 11 -T = ComplexF64 -chain = FiniteChain(L) -symmetry = Trivial -spin = 1 -J = 1 - -H = heisenberg_XXX(symmetry, chain; J, spin) - -physical_space = ℂ^3 -virtual_space = ℂ^1 -# A = zeros(ComplexF64, virtual_space ⊗ physical_space ← virtual_space) -# A.data .= [1, 0.1, -10.0] -# rand!(A.data) - -psi = FiniteMPS(rand, T, L, physical_space, virtual_space) -# psi = FiniteMPS(fill(A, L)) -gs, envs, delta = find_groundstate(psi, H, DMRG(; verbosity = 0)); - -Sx = S_x(T, symmetry; spin = 1) - -# E_x = map(eachindex(psi)) do i -# expectation_value(psi, i => Sx) -# end -# E_xx = map(eachindex(psi)) do i -# expectation_value(psi, (i,) => Sx^2) -# end -# E_xx2 = map(eachindex(psi)) do i -# Sx_normalized = add(Sx, id(space(Sx, 1)), -E_x[i]) -# expectation_value(psi, i => Sx_normalized^2) -# end - -# E_xx .- E_x .^ 2 -# E_xx2 -# test for random state D = 1 -for i in 1:length(chain) - # i = length(chain) ÷ 2 - E_x = expectation_value(psi, i => Sx) - E_xx = expectation_value(psi, (i,) => Sx^2) - E_xx2 = expectation_value(psi, (i,) => add(Sx, id(space(Sx, 1)), -E_x)^2) - - # @info i E_x E_xx E_xx - E_x^2 E_xx2 - @test E_xx - E_x^2 ≈ E_xx2 -end - -# test for groundstate D = 1 -gs, envs, delta = find_groundstate(psi, H, DMRG(; verbosity = 0)); -for i in 1:length(chain) - # i = length(chain) ÷ 2 - E_x = expectation_value(gs, i => Sx) - E_xx = expectation_value(gs, (i,) => Sx^2) - E_xx2 = expectation_value(gs, (i,) => add(Sx, id(space(Sx, 1)), -E_x)^2) - - # @info i E_x E_xx E_xx - E_x^2 E_xx2 - @test E_xx - E_x^2 ≈ E_xx2 -end - -virtual_space = ℂ^15 -psi = FiniteMPS(rand, T, L, physical_space, virtual_space) -for i in 1:length(chain) - # i = length(chain) ÷ 2 - E_x = expectation_value(psi, i => Sx) - E_xx = expectation_value(psi, (i,) => Sx^2) - E_xx2 = expectation_value(psi, (i,) => add(Sx, id(space(Sx, 1)), -E_x)^2) - - # @info i E_x E_xx E_xx - E_x^2 E_xx2 - @test E_xx - E_x^2 ≈ E_xx2 -end - -gs, envs, delta = find_groundstate(psi, H, DMRG(; verbosity = 0)); -for i in 1:length(chain) - # i = length(chain) ÷ 2 - E_x = expectation_value(gs, i => Sx) - E_xx = expectation_value(gs, (i,) => Sx^2) - E_xx2 = expectation_value(gs, (i,) => add(Sx, id(space(Sx, 1)), -E_x)^2) - - # @info i E_x E_xx E_xx - E_x^2 E_xx2 - @test E_xx - E_x^2 ≈ E_xx2 -end - -println() -#= -┌ Info: 1 -│ E_x = 0.9283027892120569 -│ E_xx = 0.9873406410374899 -│ E_xx - E_x ^ 2 = 0.1255945725786053 -└ E_xx2 = 0.1255945725786054 -┌ Info: 2 -│ E_x = 0.5958931587232229 -│ E_xx = 0.8842424256151229 -│ E_xx - E_x ^ 2 = 0.5291537690019827 -└ E_xx2 = 0.5291537690019827 -┌ Info: 3 -│ E_x = 0.9119512168846627 -│ E_xx = 0.9410385403620483 -│ E_xx - E_x ^ 2 = 0.10938351838463112 -└ E_xx2 = 0.10938351838463076 -┌ Info: 4 -│ E_x = 0.8475876798883178 -│ E_xx = 0.9998527656967889 -│ E_xx - E_x ^ 2 = 0.2814478905983274 -└ E_xx2 = 0.28144789059832703 -┌ Info: 5 -│ E_x = 0.5411573880001049 -│ E_xx = 0.5994538976943021 -│ E_xx - E_x ^ 2 = 0.306602579107206 -└ E_xx2 = 0.306602579107206 -┌ Info: 6 -│ E_x = 0.99952372893415 -│ E_xx = 0.9996661378739403 -│ E_xx - E_x ^ 2 = 0.0006184531715122121 -└ E_xx2 = 0.0006184531715116068 -┌ Info: 7 -│ E_x = 0.7484424712641702 -│ E_xx = 0.7491543238199131 -│ E_xx - E_x ^ 2 = 0.18898819102789488 -└ E_xx2 = 0.18898819102789452 -┌ Info: 8 -│ E_x = 0.9525317843713124 -│ E_xx = 0.9548671515022985 -│ E_xx - E_x ^ 2 = 0.047550351264702195 -└ E_xx2 = 0.04755035126470154 -┌ Info: 9 -│ E_x = 0.5371423149073694 -│ E_xx = 0.728001367170992 -│ E_xx - E_x ^ 2 = 0.43947950070694436 -└ E_xx2 = 0.43947950070694425 -┌ Info: 10 -│ E_x = 0.9289084036689698 -│ E_xx = 0.9917741739555096 -│ E_xx - E_x ^ 2 = 0.12890335154867594 -└ E_xx2 = 0.12890335154867597 -┌ Info: 11 -│ E_x = 0.748255413094344 -│ E_xx = 0.789444809740308 -│ E_xx - E_x ^ 2 = 0.22955864651532065 -└ E_xx2 = 0.2295586465153205 -=# diff --git a/scripts/antonio1.jl b/scripts/antonio1.jl deleted file mode 100644 index 6a19c5956..000000000 --- a/scripts/antonio1.jl +++ /dev/null @@ -1,16 +0,0 @@ -using TensorKit -using MPSKit -using MPSKitModels - -rows = 4 -cols = 4 - -J = -1 -g = 1 - -lattice = FiniteStrip(rows, rows * cols) -H = transverse_field_ising(lattice; J, g); - -vals, vecs, info = exact_diagonalization(H; num = 10); - -vals diff --git a/scripts/daniel.jl b/scripts/daniel.jl deleted file mode 100644 index 85613f3ec..000000000 --- a/scripts/daniel.jl +++ /dev/null @@ -1 +0,0 @@ -using MPSKit, TensorKit, BlockTensorKit diff --git a/scripts/issue299.jl b/scripts/issue299.jl deleted file mode 100644 index 3895e6473..000000000 --- a/scripts/issue299.jl +++ /dev/null @@ -1,20 +0,0 @@ -using TensorKit -using MPSKit -using MPSKitModels: FiniteChain, hubbard_model - - -H_u1_su2 = hubbard_model(ComplexF64, U1Irrep, SU2Irrep, FiniteChain(4); U = 8.0, mu = 4.0, t = 1.0); -charges = fill(FermionParity(1) ⊠ U1Irrep(1) ⊠ SU2Irrep(0), 4); -H = MPSKit.add_physical_charge(H_u1_su2, charges); - -ρ₀ = MPSKit.infinite_temperature_density_matrix(H) -ρ_mps = convert(FiniteMPS, ρ₀) -βs = 0.0:0.2:8.0 -for i in 2:length(βs) - global ρ_mps - @info "Computing β = $(βs[i])" - ρ_mps, = timestep( - ρ_mps, H, βs[i - 1] / 2, -im * (βs[i] - βs[i - 1]) / 2, - TDVP2(; trscheme = truncdim(64)) - ) -end diff --git a/scripts/loic.jl b/scripts/loic.jl deleted file mode 100644 index 362ba79e4..000000000 --- a/scripts/loic.jl +++ /dev/null @@ -1,42 +0,0 @@ -using MPSKit, TensorKit, MPSKitModels - -function rydberg_model( - elt::Type{<:Number} = Float64, - lattice::AbstractLattice = InfiniteChain(1); - Delta = 0.0, Omega = 0.0, V = 1.0, fluctuation = 0 - ) - sz = S_z(elt, Trivial) - Id = id(elt, domain(sz)) - n = 0.5 * Id + sz - #Id = 2 * (n - sz) - sx = S_x(elt, Trivial) - - H = @mpoham begin - sum(vertices(lattice)) do i - return sum(V / j^6 * n{i} * n{i - j} for j in 1:10) - end + - sum(vertices(lattice)) do i - return -Delta * (1 + fluctuation * rand()) * n{i} - Omega * (1 + fluctuation * rand()) * sx{i} - 1 * Id{i} - end - end - return H -end - -L = 20; -x = 4; -y = 4; -Omega = 1 / y^6 -Delta = x * Omega -H0 = rydberg_model(Float64, InfiniteChain(2); Omega, Delta); -H = periodic_boundary_conditions(H0, L); - -# Htrunc = changebonds(H, SvdCut(; trscheme = truncbelow(1.0e-14))) - -mps = FiniteMPS([TensorMap(rand, ComplexF64, ComplexSpace(2) ⊗ ComplexSpace(2), ComplexSpace(2)) for j in 1:L]) -# mps = normalize!(FiniteMPS(rand, ComplexF64, fill(ℂ^2, L), ℂ^2)) - -# alg = DMRG2(; trscheme = truncdim(10), maxiter = 5, verbosity = 3, alg_eigsolve = (; verbosity = 2, dynamic_tols = false, tol = 1.0e-6)) -# gs, envs, delta = find_groundstate(mps, H, alg) - - -mps2 = approximate(mps, (H, mps), DMRG2(trscheme = truncbelow(1.0e-12))) diff --git a/scripts/profile_vumps.jl b/scripts/profile_vumps.jl deleted file mode 100644 index 4dbd57cf2..000000000 --- a/scripts/profile_vumps.jl +++ /dev/null @@ -1,108 +0,0 @@ -using TensorKit, MPSKit, MPSKitModels -using MPSKit: JordanMPOTensor -using BlockTensorKit -using BenchmarkTools -using MPSKit: DefaultBackend, DefaultAllocator, GrowingBuffer - -symmetry = SU2Irrep -T = Float64 -D = 2048 - -H = heisenberg_XXX(T, symmetry, InfiniteChain(2); spin = 1 // 2); -pspaces = physicalspace(H) -A = rand(oneunit(pspaces[1]) ⊗ pspaces[1] ⊗ pspaces[2] ← oneunit(pspaces[1])) -As = MPSKit.decompose_localmps(A, trunctol(atol = 1.0e-12)) -psi = InfiniteMPS(repeat(As, length(H) ÷ 2)); -psi, envs = find_groundstate(psi, H, IDMRG2(; maxiter = 100, trscheme = truncrank(D))); - -# regular application -function bench_single(psi, H, envs) - Hac2 = MPSKit.AC2_hamiltonian(1, psi, H, psi, envs) - ac2 = MPSKit.AC2(psi, 1; kind = :ACAR) - return @benchmark $Hac2 * $ac2 -end -function bench_prep(psi, H, envs; allocator = DefaultAllocator(), backend = DefaultBackend()) - Hac2 = MPSKit.AC2_hamiltonian(1, psi, H, psi, envs) - return @benchmark MPSKit.prepare_operator!!($Hac2, $backend, $allocator) -end -function bench_prepped(psi, H, envs; allocator = DefaultAllocator(), backend = DefaultBackend()) - Hac2 = MPSKit.prepare_operator!!(MPSKit.AC2_hamiltonian(1, psi, H, psi, envs), backend, allocator) - ac2 = MPSKit.AC2(psi, 1; kind = :ACAR) - return @benchmark $Hac2 * $ac2 -end -function densify(A::AbstractBlockTensorMap) - B = TensorMap(A) - return SparseBlockTensorMap(B, prod(SumSpace, codomain(B)) ← prod(SumSpace, domain(B))) -end -function densify(W::JordanMPOTensor) - A = densify(W.A) - B = densify(W.B) - C = densify(W.C) - D = densify(W.D) - S = spacetype(W) - Vl = oneunit(S) ⊞ left_virtualspace(A) ⊞ oneunit(S) - Vr = oneunit(S) ⊞ right_virtualspace(A) ⊞ oneunit(S) - - return JordanMPOTensor( - Vl ⊗ physicalspace(W) ← physicalspace(W) ⊗ Vr, - A, B, C, D - ) -end - -bench_single(psi, H, envs) -bench_prep(psi, H, envs) -bench_prepped(psi, H, envs) - -SS = MPSKitModels.S_exchange(T, symmetry; spin = 1 // 2); -H_nnn = InfiniteMPOHamiltonian(physicalspace(H), (1, 2) => SS, (1, 3) => SS); -H_larger = InfiniteMPOHamiltonian(physicalspace(H), (1, i) => SS for i in 2:10); -H_largest = InfiniteMPOHamiltonian(map(densify, H_larger)); -H_smallest = InfiniteMPOHamiltonian(map(densify, H)); - -envs_nnn = environments(psi, H_nnn); -envs_larger = environments(psi, H_larger); -envs_largest = environments(psi, H_largest); -envs_smallest = environments(psi, H_smallest); - - -b1 = bench_single(psi, H_nnn, envs_nnn) -b2 = bench_prep(psi, H_nnn, envs_nnn) -b3 = bench_prepped(psi, H_nnn, envs_nnn) - -allocator = GrowingBuffer() -b4 = bench_single(psi, H_larger, envs_larger) -b5 = bench_prep(psi, H_larger, envs_larger) -b5 = bench_prep(psi, H_larger, envs_larger; allocator) -b6 = bench_prepped(psi, H_larger, envs_larger) -@profview b6 = bench_prepped(psi, H_larger, envs_larger; allocator) - -b8 = bench_prep(psi, H_largest, envs_largest) - -allocator = GrowingBuffer() -b7 = bench_single(psi, H_largest, envs_largest) -b9 = bench_prepped(psi, H_largest, envs_largest) -b9 = bench_prepped(psi, H_largest, envs_largest; allocator) - -b10 = bench_single(psi, H_smallest, envs_smallest) -b11 = bench_prep(psi, H_smallest, envs_smallest) -b12 = bench_prepped(psi, H_smallest, envs_smallest) - -println("next-nearest neighbour") -b1 -b2 -b3 - -println("10 sites (sparse)") -b4 -b5 -b6 - -println("10 sites (dense)") -b7 -b8 -b9 - -println("nearest-neighbour (dense)") -b10 -b11 -b12 diff --git a/scripts/yanmong.jl b/scripts/yanmong.jl deleted file mode 100644 index 95ef24a61..000000000 --- a/scripts/yanmong.jl +++ /dev/null @@ -1,34 +0,0 @@ -using TensorKit -using CategoryData: Object, RepA4 -using MPSKit -using MPSKit.KrylovKit -using LinearAlgebra: eigvals - -I = Object{RepA4} -dim.(values(I)) # => (1, 1, 1, 3) -V = Vect[I](4 => 1) - -H_nn = randn(V ⊗ V ← V ⊗ V); -H_nn += H_nn'; # make it Hermitian - -H = H_nn ⊗ id(V) + id(V) ⊗ H_nn; # two-site Hamiltonian - -E_symm = eigvals(H) -E_dense = eigvals(reshape(convert(Array, H), dim(V)^3, dim(V)^3)) - -H_mpo = InfiniteMPOHamiltonian([V], (1, 2) => H_nn); -H_mpo_finite = open_boundary_conditions(H_mpo, 3); - -energies, states = exact_diagonalization(H_mpo_finite; num = 18); -x0 = rand(V^3); -vals, vecs, info = KrylovKit.eigsolve(x -> H * x, rand(V^3), 18, :SR); - -@info "Eigenvalues for different methods:" sort(energies; by = real) sort(vals; by = real) sort(E_symm[one(I)]; by = real) - -target_sector = I(4) -x0_charged = rand(V^3 ← Vect[I](target_sector => 1)) - -energies, states = exact_diagonalization(H_mpo_finite; num = 18, sector = target_sector); -vals, vecs, info = KrylovKit.eigsolve(x -> H * x, x0_charged, 18, :SR); - -@info "Eigenvalues for different methods:" sort(energies; by = real) sort(vals; by = real) sort(E_symm[target_sector]; by = real) diff --git a/src/MPSKit.jl b/src/MPSKit.jl index 302552b14..30db5aa89 100644 --- a/src/MPSKit.jl +++ b/src/MPSKit.jl @@ -66,7 +66,8 @@ using MatrixAlgebraKit: TruncationStrategy, PolarViaSVD, LAPACK_SVDAlgorithm using BlockTensorKit using BlockTensorKit: TensorMapSumSpace using TensorOperations -using TensorOperations: AbstractBackend, DefaultBackend, DefaultAllocator, BufferAllocator +using TensorOperations: AbstractBackend, DefaultBackend, DefaultAllocator, BufferAllocator, + allocator_checkpoint!, allocator_reset! using KrylovKit using KrylovKit: KrylovAlgorithm using OptimKit diff --git a/src/algorithms/changebonds/vumpssvd.jl b/src/algorithms/changebonds/vumpssvd.jl index 36ba6852d..c924976ce 100644 --- a/src/algorithms/changebonds/vumpssvd.jl +++ b/src/algorithms/changebonds/vumpssvd.jl @@ -53,10 +53,10 @@ function changebonds_n(state::InfiniteMPS, H, alg::VUMPSSvdCut, envs = environme for loc in 1:length(state) @plansor AC2[-1 -2; -3 -4] := state.AC[loc][-1 -2; 1] * state.AR[loc + 1][1 -4; -3] - Hac2 = prepare_operator!!(AC2_hamiltonian(loc, state, H, state, envs)) + Hac2 = AC2_hamiltonian(loc, state, H, state, envs) _, nAC2 = fixedpoint(Hac2, AC2, :SR, alg.alg_eigsolve) - Hc = prepare_operator!!(C_hamiltonian(loc + 1, state, H, state, envs)) + Hc = C_hamiltonian(loc + 1, state, H, state, envs) _, nC2 = fixedpoint(Hc, state.C[loc + 1], :SR, alg.alg_eigsolve) #svd ac2, get new AL1 and S,V ---> AC diff --git a/src/algorithms/derivatives/derivatives.jl b/src/algorithms/derivatives/derivatives.jl index 7bd11aef4..7d5cc677e 100644 --- a/src/algorithms/derivatives/derivatives.jl +++ b/src/algorithms/derivatives/derivatives.jl @@ -70,32 +70,34 @@ See also [`AC2_projection`](@ref). # boilerplate for the derivative operators for hamiltonian in (:C_hamiltonian, :AC_hamiltonian, :AC2_hamiltonian) @eval function $hamiltonian( - site::CartesianIndex{2}, below, operator::MultilineMPO, above, envs + site::CartesianIndex{2}, below, operator::MultilineMPO, above, envs; + kwargs... ) row, col = Tuple(site) - return $hamiltonian(col, below[row + 1], operator[row], above[row], envs[row]) + return $hamiltonian(col, below[row + 1], operator[row], above[row], envs[row]; kwargs...) end - @eval function $hamiltonian(col::Int, below, operator::MultilineMPO, above, envs) + @eval function $hamiltonian(col::Int, below, operator::MultilineMPO, above, envs; kwargs...) Hs = map(1:size(operator, 1)) do row - return $hamiltonian(CartesianIndex(row, col), below, operator, above, envs) + return $hamiltonian(CartesianIndex(row, col), below, operator, above, envs; kwargs...) end return Multiline(Hs) end - @eval function $hamiltonian(site::Int, below, operator::MultipliedOperator, above, envs) - H = $hamiltonian(site, below, operator.op, above, envs) + @eval function $hamiltonian(site::Int, below, operator::MultipliedOperator, above, envs; kwargs...) + H = $hamiltonian(site, below, operator.op, above, envs; kwargs...) return MultipliedOperator(H, operator.f) end - @eval function $hamiltonian(site::Int, below, operator::LinearCombination, above, envs) + @eval function $hamiltonian(site::Int, below, operator::LinearCombination, above, envs; kwargs...) Hs = map(operator.opps, envs.envs) do o, env - return $hamiltonian(site, below, o, above, env) + return $hamiltonian(site, below, o, above, env; kwargs...) end return LinearCombination(Hs, operator.coeffs) end @eval function $hamiltonian( - site::Int, below, operator::LazySum, above, envs::MultipleEnvironments + site::Int, below, operator::LazySum, above, envs::MultipleEnvironments; + kwargs... ) Hs = map(operator.ops, envs.envs) do o, env - return $hamiltonian(site, below, o, above, env) + return $hamiltonian(site, below, o, above, env; kwargs...) end elT = Union{D, MultipliedOperator{D}} where {D <: DerivativeOperator} return LazySum{elT}(Hs) @@ -191,14 +193,15 @@ end function C_projection(site, below, operator, above, envs) C = above isa Multiline ? above.C[:, site] : above.C[site] - return C_hamiltonian(site, below, operator, above, envs) * C + return C_hamiltonian(site, below, operator, above, envs; prepare = false) * C end function AC_projection(site, below, operator, above, envs) AC = above isa Multiline ? above.AC[:, site] : above.AC[site] - return AC_hamiltonian(site, below, operator, above, envs) * AC + return AC_hamiltonian(site, below, operator, above, envs; prepare = false) * AC end function AC2_projection(site::Int, below, operator, above, envs; kwargs...) - return AC2_hamiltonian(site, below, operator, above, envs) * AC2(above, site; kwargs...) + return AC2_hamiltonian(site, below, operator, above, envs; prepare = false) * + AC2(above, site; kwargs...) end # Multiline diff --git a/src/algorithms/derivatives/hamiltonian_derivatives.jl b/src/algorithms/derivatives/hamiltonian_derivatives.jl index 34f3c6e85..f458f564c 100644 --- a/src/algorithms/derivatives/hamiltonian_derivatives.jl +++ b/src/algorithms/derivatives/hamiltonian_derivatives.jl @@ -27,15 +27,24 @@ struct JordanMPO_AC_Hamiltonian{O1, O2, O3} <: DerivativeOperator return new{O1, O2, O3}(D, I, E, C, B, A) end end +function JordanMPO_AC_Hamiltonian{O1, O2, O3}(D, I, E, C, B, A) where {O1, O2, O3} + return JordanMPO_AC_Hamiltonian{O1, O2, O3}( + ismissing(D) ? D : convert(O1, D), ismissing(I) ? I : convert(O1, I), + ismissing(E) ? E : convert(O1, E), ismissing(C) ? C : convert(O2, C), + ismissing(B) ? E : convert(O2, B), ismissing(A) ? A : convert(O3, A) + ) +end function AC_hamiltonian( - site::Int, below::_HAM_MPS_TYPES, operator::MPOHamiltonian, above::_HAM_MPS_TYPES, envs + site::Int, below::_HAM_MPS_TYPES, operator::MPOHamiltonian, above::_HAM_MPS_TYPES, envs; + prepare::Bool = true ) @assert below === above "JordanMPO assumptions break" GL = leftenv(envs, site, below) GR = rightenv(envs, site, below) W = operator[site] - return JordanMPO_AC_Hamiltonian(GL, W, GR) + H_AC = JordanMPO_AC_Hamiltonian(GL, W, GR) + return prepare ? prepare_operator!!(H_AC) : H_AC end function JordanMPO_AC_Hamiltonian(GL::MPSTensor, W::JordanMPOTensor, GR::MPSTensor) @@ -162,15 +171,28 @@ struct JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4} <: DerivativeOperator return new{O1, O2, O3, O4}(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) end end +function JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4}( + II, IC, ID, CB, CA, AB, AA, BE, DE, EE + ) where {O1, O2, O3, O4} + return JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4}( + ismissing(II) ? II : convert(O1, II), ismissing(IC) ? IC : convert(O2, IC), + ismissing(ID) ? ID : convert(O1, ID), ismissing(CB) ? CB : convert(O2, CB), + ismissing(CA) ? CA : convert(O3, CA), ismissing(AB) ? AB : convert(O3, AB), + ismissing(AA) ? AA : convert(O4, AA), ismissing(BE) ? BE : convert(O2, BE), + ismissing(DE) ? DE : convert(O1, DE), ismissing(EE) ? EE : convert(O1, EE) + ) +end function AC2_hamiltonian( - site::Int, below::_HAM_MPS_TYPES, operator::MPOHamiltonian, above::_HAM_MPS_TYPES, envs + site::Int, below::_HAM_MPS_TYPES, operator::MPOHamiltonian, above::_HAM_MPS_TYPES, envs; + prepare::Bool = true ) @assert below === above "JordanMPO assumptions break" GL = leftenv(envs, site, below) GR = rightenv(envs, site + 1, below) W1, W2 = operator[site], operator[site + 1] - return JordanMPO_AC2_Hamiltonian(GL, W1, W2, GR) + H_AC2 = JordanMPO_AC2_Hamiltonian(GL, W1, W2, GR) + return prepare ? prepare_operator!!(H_AC2) : H_AC2 end function JordanMPO_AC2_Hamiltonian(GL::MPSTensor, W1::JordanMPOTensor, W2::JordanMPOTensor, GR::MPSTensor) diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index 40967ca6d..5d5b5a562 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -22,18 +22,21 @@ MPO_AC2_Hamiltonian(GL, O1, O2, GR) = MPODerivativeOperator(GL, (O1, O2), GR) # Constructors # ------------ -function C_hamiltonian(site::Int, below, operator, above, envs) - return MPO_C_Hamiltonian(leftenv(envs, site + 1, below), rightenv(envs, site, below)) +function C_hamiltonian(site::Int, below, operator, above, envs; prepare::Bool = true) + H_C = MPO_C_Hamiltonian(leftenv(envs, site + 1, below), rightenv(envs, site, below)) + return prepare ? prepare_operator!!(H_C) : H_C end -function AC_hamiltonian(site::Int, below, operator, above, envs) +function AC_hamiltonian(site::Int, below, operator, above, envs; prepare::Bool = true) O = isnothing(operator) ? nothing : operator[site] - return MPO_AC_Hamiltonian(leftenv(envs, site, below), O, rightenv(envs, site, below)) + H_AC = MPO_AC_Hamiltonian(leftenv(envs, site, below), O, rightenv(envs, site, below)) + return prepare ? prepare_operator!!(H_AC) : H_AC end -function AC2_hamiltonian(site::Int, below, operator, above, envs) +function AC2_hamiltonian(site::Int, below, operator, above, envs; prepare::Bool = true) O1, O2 = isnothing(operator) ? (nothing, nothing) : (operator[site], operator[site + 1]) - return MPO_AC2_Hamiltonian( + H_AC2 = MPO_AC2_Hamiltonian( leftenv(envs, site, below), O1, O2, rightenv(envs, site + 1, below) ) + return prepare ? prepare_operator!!(H_AC2) : H_AC2 end # Properties @@ -119,8 +122,11 @@ struct PrecomputedDerivative{ allocator::A end -const PrecomputedACDerivative{T, S} = PrecomputedDerivative{T, S, 3, 2, 2, 1} -const PrecomputedAC2Derivative{T, S} = PrecomputedDerivative{T, S, 3, 2, 3, 2} +const PrecomputedCDerivative{T, S} = PrecomputedDerivative{T, S, 1, 2, 2, 1} +const PrecomputedACDerivative{T, S} = PrecomputedDerivative{T, S, 2, 3, 2, 1} +const PrecomputedAC2Derivative{T, S} = PrecomputedDerivative{T, S, 2, 3, 3, 2} + +VectorInterface.scalartype(::Type{<:PrecomputedDerivative{T}}) where {T} = T function prepare_operator!!( H::MPO_C_Hamiltonian{<:MPSTensor, <:MPSTensor}, @@ -134,12 +140,10 @@ function prepare_operator!!( H::MPO_AC_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPSTensor}, backend::AbstractBackend, allocator ) - cp = checkpoint(allocator) @plansor backend = backend allocator = allocator begin GL_O[-1 -2; -4 -5 -3] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] end - reset!(allocator, cp) - leftenv = fuse_legs(GL_O isa TensorMap ? GL_O : TensorMap(GL_O), 0, 2) + leftenv = GL_O isa TensorMap ? GL_O : TensorMap(GL_O) rightenv = H.rightenv isa TensorMap ? H.rightenv : TensorMap(H.rightenv) return PrecomputedDerivative(leftenv, rightenv, backend, allocator) @@ -149,38 +153,77 @@ function prepare_operator!!( H::MPO_AC2_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPOTensor, <:MPSTensor}, backend::AbstractBackend, allocator ) - cp = checkpoint(allocator) @plansor backend = backend allocator = allocator begin GL_O[-1 -2; -4 -5 -3] := H.leftenv[-1 1; -4] * H.operators[1][1 -2; -5 -3] O_GR[-1 -2 -3; -4 -5] := H.operators[2][-3 -5; -2 1] * H.rightenv[-1 1; -4] end - reset!(allocator, cp) - leftenv = fuse_legs(GL_O isa TensorMap ? GL_O : TensorMap(GL_O), 0, 2) - rightenv = fuse_legs(O_GR isa TensorMap ? O_GR : TensorMap(O_GR), 2, 0) + leftenv = GL_O isa TensorMap ? GL_O : TensorMap(GL_O) + rightenv = O_GR isa TensorMap ? O_GR : TensorMap(O_GR) return PrecomputedDerivative(leftenv, rightenv, backend, allocator) end +function (H::PrecomputedCDerivative)(x::MPSBondTensor) + backend, allocator = H.backend, H.allocator + L, R = H.leftenv, H.rightenv + cp = allocator_checkpoint!(allocator) -function (H::PrecomputedDerivative)(x::AbstractTensorMap) - allocator = H.allocator - cp = checkpoint(allocator) - - R_fused = fuse_legs(H.rightenv, 0, numin(x)) - x_fused = fuse_legs(x, numout(x), numin(x)) - - TC = TensorOperations.promote_contract(scalartype(x_fused), scalartype(R_fused)) + TC = TensorOperations.promote_contract(scalartype(x), scalartype(H)) xR = TensorOperations.tensoralloc_contract( - TC, x_fused, ((1,), (2,)), false, R_fused, ((1,), (2, 3)), false, ((1, 2), (3,)), Val(true), allocator + TC, x, ((1,), (2,)), false, R, ((1,), (2, 3)), false, ((1, 2), (3,)), Val(true), allocator ) + mul_front!(xR, x, R, One(), Zero(), backend, allocator) + LxR = L * xR - mul_front!(xR, x_fused, R_fused, One(), Zero(), H.backend, allocator) - - LxR = H.leftenv * xR TensorOperations.tensorfree!(xR, allocator) + allocator_reset!(allocator, cp) + + return LxR +end +function (H::PrecomputedACDerivative)(x::MPSTensor) + backend, allocator = H.backend, H.allocator + L, R = H.leftenv, H.rightenv + + L_fused = fuse_legs(L, 2, 2) + x_fused = fuse_legs(x, 2, 1) + LxR_fused = PrecomputedDerivative(L_fused, R, backend, allocator)(x_fused) + + return TensorMap{scalartype(LxR_fused)}(LxR_fused.data, codomain(L) ← domain(R)) +end +function (H::PrecomputedAC2Derivative)(x::MPOTensor) + backend, allocator = H.backend, H.allocator + L, R = H.leftenv, H.rightenv + + L_fused = fuse_legs(L, 2, 2) + x_fused = fuse_legs(x, 2, 2) + R_fused = fuse_legs(R, 2, 2) + LxR_fused = PrecomputedDerivative(L_fused, R_fused, backend, allocator)(x_fused) - reset!(allocator, cp) - return TensorMap{scalartype(LxR)}(LxR.data, codomain(H.leftenv) ← domain(H.rightenv)) + return TensorMap{scalartype(LxR_fused)}(LxR_fused.data, codomain(L) ← domain(R)) +end + +# TODO: these contractions are annoying and could be better if the input structure was different +# TODO: allocator things +function (H::PrecomputedACDerivative)(x::AbstractTensorMap{<:Any, <:Any, 3, 1}) + backend, allocator = H.backend, H.allocator + L, R = H.leftenv, H.rightenv + + @plansor backend = backend allocator = allocator begin + y[-1 -2 -3; -4] ≔ + L[-1 -2; 4 5 2] * x[4 5 3; 1] * τ[2 -3; 3 6] * R[1 6; -4] + end + return y +end +function (H::PrecomputedAC2Derivative)(x::AbstractTensorMap{<:Any, <:Any, 3, 3}) + backend, allocator = H.backend, H.allocator + L, R = H.leftenv, H.rightenv + + x_braided = braid(x, ((5, 3, 1, 2), (4, 6)), (1, 2, 3, 4, 5, 6)) + @plansor backend = backend allocator = allocator begin + y_braided[-5 -3 -1 -2; -4 -6] ≔ + L[-1 -2; 3 4 5] * x_braided[-5 -3 3 4; 1 2] * R[1 2 5; -4 -6] + end + return braid(y_braided, ((3, 4, 2), (5, 1, 6)), (5, 3, 1, 2, 4, 6)) end const _ToPrepare = Union{ diff --git a/src/algorithms/groundstate/dmrg.jl b/src/algorithms/groundstate/dmrg.jl index 4f7bb8940..bbca5157d 100644 --- a/src/algorithms/groundstate/dmrg.jl +++ b/src/algorithms/groundstate/dmrg.jl @@ -44,7 +44,7 @@ function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG, envs = environme zerovector!(ϵs) for pos in [1:(length(ψ) - 1); length(ψ):-1:2] - h = prepare_operator!!(AC_hamiltonian(pos, ψ, H, ψ, envs)) + h = AC_hamiltonian(pos, ψ, H, ψ, envs) _, vec = fixedpoint(h, ψ.AC[pos], :SR, alg_eigsolve) ϵs[pos] = max(ϵs[pos], calc_galerkin(pos, ψ, H, ψ, envs)) ψ.AC[pos] = vec @@ -122,7 +122,7 @@ function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG2, envs = environm # left to right sweep for pos in 1:(length(ψ) - 1) @plansor ac2[-1 -2; -3 -4] := ψ.AC[pos][-1 -2; 1] * ψ.AR[pos + 1][1 -4; -3] - Hac2 = prepare_operator!!(AC2_hamiltonian(pos, ψ, H, ψ, envs)) + Hac2 = AC2_hamiltonian(pos, ψ, H, ψ, envs) _, newA2center = fixedpoint(Hac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(newA2center; trunc = alg.trscheme, alg = alg.alg_svd) @@ -137,7 +137,7 @@ function find_groundstate!(ψ::AbstractFiniteMPS, H, alg::DMRG2, envs = environm # right to left sweep for pos in (length(ψ) - 2):-1:1 @plansor ac2[-1 -2; -3 -4] := ψ.AL[pos][-1 -2; 1] * ψ.AC[pos + 1][1 -4; -3] - Hac2 = prepare_operator!!(AC2_hamiltonian(pos, ψ, H, ψ, envs)) + Hac2 = AC2_hamiltonian(pos, ψ, H, ψ, envs) _, newA2center = fixedpoint(Hac2, ac2, :SR, alg_eigsolve) al, c, ar = svd_trunc!(newA2center; trunc = alg.trscheme, alg = alg.alg_svd) diff --git a/src/algorithms/statmech/idmrg.jl b/src/algorithms/statmech/idmrg.jl index 2997347ff..477583bb6 100644 --- a/src/algorithms/statmech/idmrg.jl +++ b/src/algorithms/statmech/idmrg.jl @@ -13,7 +13,7 @@ function leading_boundary( # left to right sweep for col in 1:size(ψ, 2) - Hac = prepare_operator!!(AC_hamiltonian(col, ψ, operator, ψ, envs)) + Hac = AC_hamiltonian(col, ψ, operator, ψ, envs) _, ψ.AC[:, col] = fixedpoint(Hac, ψ.AC[:, col], :LM, alg_eigsolve) for row in 1:size(ψ, 1) @@ -27,7 +27,7 @@ function leading_boundary( # right to left sweep for col in size(ψ, 2):-1:1 - Hac = prepare_operator!!(AC_hamiltonian(col, ψ, operator, ψ, envs)) + Hac = AC_hamiltonian(col, ψ, operator, ψ, envs) _, ψ.AC[:, col] = fixedpoint(Hac, ψ.AC[:, col], :LM, alg_eigsolve) for row in 1:size(ψ, 1) @@ -78,7 +78,7 @@ function leading_boundary( # sweep from left to right for site in 1:(size(ψ, 2) - 1) ac2 = AC2(ψ, site; kind = :ACAR) - h = prepare_operator!!(AC2_hamiltonian(site, ψ, operator, ψ, envs)) + h = AC2_hamiltonian(site, ψ, operator, ψ, envs) _, ac2′ = fixedpoint(h, ac2, :LM, alg_eigsolve) for row in 1:size(ψ, 1) @@ -102,7 +102,7 @@ function leading_boundary( ψ.AL[:, end] .= ψ.AC[:, end] ./ ψ.C[:, end] ψ.AC[:, 1] .= _mul_tail.(ψ.AL[:, 1], ψ.C[:, 1]) ac2 = AC2(ψ, site; kind = :ALAC) - h = prepare_operator!!(AC2_hamiltonian(site, ψ, operator, ψ, envs)) + h = AC2_hamiltonian(site, ψ, operator, ψ, envs) _, ac2′ = fixedpoint(h, ac2, :LM, alg_eigsolve) for row in 1:size(ψ, 1) @@ -127,7 +127,7 @@ function leading_boundary( # sweep from right to left for site in reverse(1:(size(ψ, 2) - 1)) ac2 = AC2(ψ, site; kind = :ALAC) - h = prepare_operator!!(AC2_hamiltonian(site, ψ, operator, ψ, envs)) + h = AC2_hamiltonian(site, ψ, operator, ψ, envs) _, ac2′ = fixedpoint(h, ac2, :LM, alg_eigsolve) for row in 1:size(ψ, 1) @@ -149,7 +149,7 @@ function leading_boundary( ψ.AC[:, end] .= _mul_front.(ψ.C[:, end - 1], ψ.AR[:, end]) ψ.AR[:, 1] .= _transpose_front.(ψ.C[:, end] .\ _transpose_tail.(ψ.AC[:, 1])) ac2 = AC2(ψ, 0; kind = :ACAR) - h = prepare_operator!!(AC2_hamiltonian(0, ψ, operator, ψ, envs)) + h = AC2_hamiltonian(0, ψ, operator, ψ, envs) _, ac2′ = fixedpoint(h, ac2, :LM, alg_eigsolve) for row in 1:size(ψ, 1) diff --git a/src/algorithms/timestep/tdvp.jl b/src/algorithms/timestep/tdvp.jl index 42791f9da..2d67f90a1 100644 --- a/src/algorithms/timestep/tdvp.jl +++ b/src/algorithms/timestep/tdvp.jl @@ -41,18 +41,18 @@ function timestep( scheduler = Defaults.scheduler[] if scheduler isa SerialScheduler temp_ACs = tmap!(temp_ACs, 1:length(ψ); scheduler) do loc - Hac = prepare_operator!!(AC_hamiltonian(loc, ψ, H, ψ, envs)) + Hac = AC_hamiltonian(loc, ψ, H, ψ, envs) return integrate(Hac, ψ.AC[loc], t, dt, alg.integrator; imaginary_evolution) end temp_Cs = tmap!(temp_Cs, 1:length(ψ); scheduler) do loc - Hc = prepare_operator!!(C_hamiltonian(loc, ψ, H, ψ, envs)) + Hc = C_hamiltonian(loc, ψ, H, ψ, envs) return integrate(Hc, ψ.C[loc], t, dt, alg.integrator; imaginary_evolution) end else @sync begin Threads.@spawn begin temp_ACs = tmap!(temp_ACs, 1:length(ψ); scheduler) do loc - Hac = prepare_operator!!(AC_hamiltonian(loc, ψ, H, ψ, envs)) + Hac = AC_hamiltonian(loc, ψ, H, ψ, envs) return integrate( Hac, ψ.AC[loc], t, dt, alg.integrator; imaginary_evolution @@ -61,7 +61,7 @@ function timestep( end Threads.@spawn begin temp_Cs = tmap!(temp_Cs, 1:length(ψ); scheduler) do loc - Hc = prepare_operator!!(C_hamiltonian(loc, ψ, H, ψ, envs)) + Hc = C_hamiltonian(loc, ψ, H, ψ, envs) return integrate( Hc, ψ.C[loc], t, dt, alg.integrator; imaginary_evolution @@ -92,10 +92,10 @@ function timestep!( # sweep left to right for i in 1:(length(ψ) - 1) - Hac = prepare_operator!!(AC_hamiltonian(i, ψ, H, ψ, envs)) + Hac = AC_hamiltonian(i, ψ, H, ψ, envs) ψ.AC[i] = integrate(Hac, ψ.AC[i], t, dt / 2, alg.integrator; imaginary_evolution) - Hc = prepare_operator!!(C_hamiltonian(i, ψ, H, ψ, envs)) + Hc = C_hamiltonian(i, ψ, H, ψ, envs) ψ.C[i] = integrate( Hc, ψ.C[i], t + dt / 2, -dt / 2, alg.integrator; imaginary_evolution @@ -103,18 +103,18 @@ function timestep!( end # edge case - Hac = prepare_operator!!(AC_hamiltonian(length(ψ), ψ, H, ψ, envs)) + Hac = AC_hamiltonian(length(ψ), ψ, H, ψ, envs) ψ.AC[end] = integrate(Hac, ψ.AC[end], t, dt / 2, alg.integrator; imaginary_evolution) # sweep right to left for i in length(ψ):-1:2 - Hac = prepare_operator!!(AC_hamiltonian(i, ψ, H, ψ, envs)) + Hac = AC_hamiltonian(i, ψ, H, ψ, envs) ψ.AC[i] = integrate( Hac, ψ.AC[i], t + dt / 2, dt / 2, alg.integrator; imaginary_evolution ) - Hc = prepare_operator!!(C_hamiltonian(i - 1, ψ, H, ψ, envs)) + Hc = C_hamiltonian(i - 1, ψ, H, ψ, envs) ψ.C[i - 1] = integrate( Hc, ψ.C[i - 1], t + dt, -dt / 2, alg.integrator; imaginary_evolution @@ -122,7 +122,7 @@ function timestep!( end # edge case - Hac = prepare_operator!!(AC_hamiltonian(1, ψ, H, ψ, envs)) + Hac = AC_hamiltonian(1, ψ, H, ψ, envs) ψ.AC[1] = integrate( Hac, ψ.AC[1], t + dt / 2, dt / 2, alg.integrator; imaginary_evolution @@ -173,7 +173,7 @@ function timestep!( # sweep left to right for i in 1:(length(ψ) - 1) ac2 = _transpose_front(ψ.AC[i]) * _transpose_tail(ψ.AR[i + 1]) - Hac2 = prepare_operator!!(AC2_hamiltonian(i, ψ, H, ψ, envs)) + Hac2 = AC2_hamiltonian(i, ψ, H, ψ, envs) ac2′ = integrate(Hac2, ac2, t, dt / 2, alg.integrator; imaginary_evolution) nal, nc, nar = svd_trunc!(ac2′; trunc = alg.trscheme, alg = alg.alg_svd) @@ -181,7 +181,7 @@ function timestep!( ψ.AC[i + 1] = (complex(nc), _transpose_front(nar)) if i != (length(ψ) - 1) - Hac = prepare_operator!!(AC_hamiltonian(i + 1, ψ, H, ψ, envs)) + Hac = AC_hamiltonian(i + 1, ψ, H, ψ, envs) ψ.AC[i + 1] = integrate( Hac, ψ.AC[i + 1], t + dt / 2, -dt / 2, alg.integrator; imaginary_evolution @@ -192,7 +192,7 @@ function timestep!( # sweep right to left for i in length(ψ):-1:2 ac2 = _transpose_front(ψ.AL[i - 1]) * _transpose_tail(ψ.AC[i]) - Hac2 = prepare_operator!!(AC2_hamiltonian(i - 1, ψ, H, ψ, envs)) + Hac2 = AC2_hamiltonian(i - 1, ψ, H, ψ, envs) ac2′ = integrate(Hac2, ac2, t + dt / 2, dt / 2, alg.integrator; imaginary_evolution) nal, nc, nar = svd_trunc!(ac2′; trunc = alg.trscheme, alg = alg.alg_svd) @@ -200,7 +200,7 @@ function timestep!( ψ.AC[i] = (complex(nc), _transpose_front(nar)) if i != 2 - Hac = prepare_operator!!(AC_hamiltonian(i - 1, ψ, H, ψ, envs)) + Hac = AC_hamiltonian(i - 1, ψ, H, ψ, envs) ψ.AC[i - 1] = integrate( Hac, ψ.AC[i - 1], t + dt, -dt / 2, alg.integrator; imaginary_evolution diff --git a/src/utility/utility.jl b/src/utility/utility.jl index 6444d6b89..fa755def8 100644 --- a/src/utility/utility.jl +++ b/src/utility/utility.jl @@ -248,7 +248,7 @@ function mul_front!( numout(B) == 1 && return mul!(C, A, B, α, β) - cp = checkpoint(allocator) + cp = allocator_checkpoint!(allocator) Ablocks = blocks(A) Bstructure = TensorKit.fusionblockstructure(space(B)) @@ -270,7 +270,7 @@ function mul_front!( α, β, backend, allocator ) end - reset!(allocator, cp) + allocator_reset!(allocator, cp) return C end @@ -297,7 +297,7 @@ function mul_tail!( numin(A) == 1 && return mul!(C, A, B, α, β) - cp = checkpoint(allocator) + cp = allocator_checkpoint!(allocator) Astructure = TensorKit.fusionblockstructure(space(A)) Bblocks = blocks(B) @@ -320,13 +320,14 @@ function mul_tail!( ) end - reset!(allocator, cp) + allocator_reset!(allocator, cp) return C end @inline fuse_legs(x::TensorMap, N₁::Int, N₂::Int) = fuse_legs(x, Val(N₁), Val(N₂)) function fuse_legs(x::TensorMap, ::Val{N₁}, ::Val{N₂}) where {N₁, N₂} - ((0 <= N₁ <= numout(x)) && (0 <= N₂ <= numin(x))) || throw(ArgumentError("invalid fusing scheme")) + ((0 <= N₁ <= numout(x)) && (0 <= N₂ <= numin(x))) || + throw(ArgumentError("invalid fusing scheme: ($N₁, $N₂) for $(typeof(x))")) init = one(spacetype(x)) cod = if N₁ > 1 @@ -347,3 +348,8 @@ function fuse_legs(x::TensorMap, ::Val{N₁}, ::Val{N₂}) where {N₁, N₂} return TensorMap{scalartype(x)}(x.data, cod ← dom) end + +# piracy until fixed + +TensorOperations.allocation_size(::Type{T}, n::Int) where {T} = + TensorOperations.allocation_size(T, (n,)) From 44745a2c7187afd02cff921652442cab426f3c49 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 27 Feb 2026 12:53:47 -0500 Subject: [PATCH 34/37] fix projection operators --- .../derivatives/projection_derivatives.jl | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/algorithms/derivatives/projection_derivatives.jl b/src/algorithms/derivatives/projection_derivatives.jl index 85232f862..b3a21fb39 100644 --- a/src/algorithms/derivatives/projection_derivatives.jl +++ b/src/algorithms/derivatives/projection_derivatives.jl @@ -12,16 +12,20 @@ Projection_AC2_Hamiltonian(GL, A1, A2, GR) = ProjectionDerivativeOperator(GL, (A # Constructors # ------------ -function AC_hamiltonian(site::Int, below, operator::ProjectionOperator, above, envs) - return Projection_AC_Hamiltonian( - leftenv(envs, site, below), operator.ket.AC[site], rightenv(envs, site, below) +function AC_hamiltonian( + site::Int, below, operator::ProjectionOperator, above, envs; + prepare::Bool = true ) + GL = leftenv(envs, site, below) + GR = rightenv(envs, site, below) + H_AC = Projection_AC_Hamiltonian(GL, operator.ket.AC[site], GR) + return prepare ? prepare_operator!!(H_AC) : H_AC end -function AC2_hamiltonian(site::Int, below, operator::ProjectionOperator, above, envs) - return Projection_AC2_Hamiltonian( - leftenv(envs, site, below), operator.ket.AC[site], - operator.ket.AR[site + 1], rightenv(envs, site + 1, below) - ) +function AC2_hamiltonian(site::Int, below, operator::ProjectionOperator, above, envs; prepare::Bool = true) + GL = leftenv(envs, site, below) + GR = rightenv(envs, site + 1, below) + H_AC2 = Projection_AC2_Hamiltonian(GL, operator.ket.AC[site], operator.ket.AR[site + 1], GR) + return prepare ? prepare_operator!!(H_AC2) : H_AC2 end # Actions From 53081249180b04d88716c2ff6a386e083a5257c5 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 27 Feb 2026 13:15:53 -0500 Subject: [PATCH 35/37] update benchmarks --- .../derivatives/AC2_benchmarks.jl | 20 +- .../derivatives/DerivativesBenchmarks.jl | 4 - benchmark/plot_results.jl | 273 +++--------------- 3 files changed, 49 insertions(+), 248 deletions(-) diff --git a/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl b/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl index b7aeb8e68..096c17eb1 100644 --- a/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl +++ b/benchmark/MPSKitBenchmarks/derivatives/AC2_benchmarks.jl @@ -20,7 +20,8 @@ benchname(spec::AC2Spec) = dim(spec.mps_virtualspaces[1]), dim(spec.mpo_virtuals # Benchmarks # ---------- -function MPSKit.AC2_hamiltonian(spec::AC2Spec{S}; T::Type = Float64) where {S} + +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]) @@ -55,26 +56,19 @@ function MPSKit.AC2_hamiltonian(spec::AC2Spec{S}; T::Type = Float64) where {S} GLs, GRs = MPSKit.initialize_environments(psi, H, psi) envs = MPSKit.InfiniteEnvironments(GLs, GRs) - return MPSKit.AC2_hamiltonian(1, psi, H, psi, envs) + 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]' - H_eff = MPSKit.AC2_hamiltonian(spec; T) return @benchmarkable $H_eff * x setup = x = randn($T, $V) end function preparation_benchmark(spec::AC2Spec; T::Type = Float64) - V = spec.mps_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[3] ⊗ spec.physicalspaces[2]' - H_eff = MPSKit.AC2_hamiltonian(spec; T) - return @benchmarkable MPSKit.prepare_operator!!($H_eff) -end - -function prepared_benchmark(spec::AC2Spec; T::Type = Float64) - V = spec.mps_virtualspaces[1] ⊗ spec.physicalspaces[1] ← spec.mps_virtualspaces[3] ⊗ spec.physicalspaces[2]' - H_eff = MPSKit.AC2_hamiltonian(spec; T) - H_prep = MPSKit.prepare_operator!!(H_eff) - return @benchmarkable $H_prep * x setup = x = randn($T, $V) + psi, H, envs = prepare_state(spec; T) + return @benchmarkable MPSKit.AC2_hamiltonian(1, $psi, $H, $psi, $envs) end # Converters diff --git a/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl index 0b423dcf2..48fbdc98d 100644 --- a/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl +++ b/benchmark/MPSKitBenchmarks/derivatives/DerivativesBenchmarks.jl @@ -25,22 +25,18 @@ T = Float64 suite_init = addgroup!(SUITE, "AC2_preparation") suite_apply = addgroup!(SUITE, "AC2_contraction") -suite_prepped = addgroup!(SUITE, "AC2_prepared") for (model, params) in allparams g_prep = addgroup!(suite_init, model) - g_prepped = addgroup!(suite_prepped, 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) - g_prepped_sym = addgroup!(g_prepped, 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) - g_prepped_sym[name] = prepared_benchmark(spec; T) end end end diff --git a/benchmark/plot_results.jl b/benchmark/plot_results.jl index ce3857d62..1273874cf 100644 --- a/benchmark/plot_results.jl +++ b/benchmark/plot_results.jl @@ -6,25 +6,32 @@ using Statistics # Loading in the data # ------------------- resultdir = joinpath(@__DIR__, "results") -resultfile(i) = "results_MPSKit@bench$i.json" -versions = [0, 1, 2, 3, 5] +result_files = Dict( + "main" => joinpath(resultdir, "results_MPSKit@main.json"), + "dirty" => joinpath(resultdir, "results_MPSKit@dirty.json") +) -df_contract = let df = DataFrame( - :version => Int[], :model => String[], :symmetry => String[], - :D => Int[], :V => Int[], :memory => Int[], :allocs => Int[], :times => Vector{Int}[] - ) - for version in versions - result = JSON.parsefile(joinpath(resultdir, resultfile(version))) +df = let df = DataFrame( + :version => String[], :model => String[], :symmetry => String[], + :D => Int[], :V => Int[], :memory => Tuple{Int, Int}[], :allocs => Tuple{Int, Int}[], :times => Tuple{Vector{Int}, Vector{Int}}[] + ) + for (version, result_file) in pairs(result_files) + result = JSON.parsefile(result_file) for (model, model_res) in result.data.derivatives.data.AC2_contraction.data for (symmetry, sym_res) in model_res.data - for (DV, bench) in sym_res.data + for (DV, contract_bench) in sym_res.data + prep_bench = result.data.derivatives.data.AC2_preparation.data[model].data[symmetry].data[DV] D, V = eval(Meta.parse(DV))::Tuple{Int, Int} - push!( df, - (version, model, symmetry, D, V, bench.memory, bench.allocs, collect(Int, bench.times)) + ( + version, model, symmetry, D, V, + (prep_bench.memory, contract_bench.memory), + (prep_bench.allocs, contract_bench.allocs), + (collect(Int, prep_bench.times), collect(Int, contract_bench.times)), + ) ) end end @@ -32,13 +39,13 @@ df_contract = let df = DataFrame( end df end + df_prep = let df = DataFrame( - :version => Int[], :model => String[], :symmetry => String[], + :version => String[], :model => String[], :symmetry => String[], :D => Int[], :V => Int[], :memory => Int[], :allocs => Int[], :times => Vector{Int}[] ) - - for version in versions - result = JSON.parsefile(joinpath(resultdir, resultfile(version))) + for (version, result_file) in pairs(result_files) + result = JSON.parsefile(result_file) for (model, model_res) in result.data.derivatives.data.AC2_preparation.data for (symmetry, sym_res) in model_res.data for (DV, bench) in sym_res.data @@ -60,63 +67,31 @@ end fontsize = 20 estimator = median -f_times = let f = Figure(; size = (1400, 1400)) - models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] - symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] - - - df_model = groupby(df_contract, [:model, :symmetry]) - for row in eachindex(models), col in eachindex(symmetries) - df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) - ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "Δt (μs)", yscale = log10) - @assert !isnothing(df_data) - for (k, v) in pairs(groupby(df_data, :version)) - Ds = v[!, :D] - times = estimator.(v[!, :times]) ./ 1.0e3 - I = sortperm(Ds) - scatterlines!(ax, Ds[I], times[I]; label = "v$(k.version)") - end - axislegend(ax, position = :lt) - end - - Label(f[0, 0], "times"; fontsize) - for (row, model) in enumerate(models) - Label(f[row, 0], model; rotation = pi / 2, fontsize, tellheight = false, tellwidth = false) - end - for (col, symmetry) in enumerate(symmetries) - Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) - end - - f -end -save(joinpath(resultdir, "bench_times.png"), f_times) - -f_times_relative = let f = Figure(; size = (1400, 1400)) +function plot_result(df, num_applications, choice = :times) + f = Figure(; size = (1400, 1400)) models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] - df_model = groupby(df_contract, [:model, :symmetry]) + df_model = groupby(df, [:model, :symmetry]) for row in eachindex(models), col in eachindex(symmetries) df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) - ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "Δt / Δt₀") - hlines!([1], color = :red) + ylabel_ = choice === :times ? "Δt (μs)" : string(choice) + ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = ylabel_, yscale = log10) @assert !isnothing(df_data) - - df_v = groupby(df_data, :version) - - v = get(df_v, (; version = 0), nothing) - Ds = v[!, :D] - times = estimator.(v[!, :times]) - I = sortperm(Ds) - times₀ = times[I] - for (k, v) in pairs(groupby(df_data, :version)) - k.version == 0 && continue Ds = v[!, :D] + if choice === :times + times_prep = estimator.(first.(v[!, :times])) ./ 1.0e3 + times_contract = estimator.(last.(v[!, :times])) ./ 1.0e3 + data = times_prep .+ (num_applications .* times_contract) + else + allocs_prep = first.(v[!, choice]) ./ 1.0e3 + allocs_contract = last.(v[!, choice]) ./ 1.0e3 + data = allocs_prep .+ (num_applications .* allocs_contract) + end I = sortperm(Ds) - times = estimator.(v[!, :times])[I] - scatterlines!(ax, Ds[I], times ./ times₀; label = "v$(k.version)") + scatterlines!(ax, Ds[I], data[I]; label = "$(k.version)") end axislegend(ax, position = :lt) end @@ -129,174 +104,10 @@ f_times_relative = let f = Figure(; size = (1400, 1400)) Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) end - f -end -save(joinpath(resultdir, "bench_times_relative.png"), f_times_relative) - -f_allocs = let f = Figure(; size = (1400, 1400)) - models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] - symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] - - - df_model = groupby(df_contract, [:model, :symmetry]) - for row in eachindex(models), col in eachindex(symmetries) - df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) - ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "allocs", yscale = log10) - @assert !isnothing(df_data) - for (k, v) in pairs(groupby(df_data, :version)) - Ds = v[!, :D] - allocs = estimator.(v[!, :allocs]) - I = sortperm(Ds) - scatterlines!(ax, Ds[I], allocs[I]; label = "v$(k.version)") - end - axislegend(ax, position = :lt) - end - - Label(f[0, 0], "allocs"; fontsize) - for (row, model) in enumerate(models) - Label(f[row, 0], model; rotation = pi / 2, fontsize, tellheight = false, tellwidth = false) - end - for (col, symmetry) in enumerate(symmetries) - Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) - end - - f -end -save(joinpath(resultdir, "bench_allocs.png"), f_allocs) - -f_memory = let f = Figure(; size = (1400, 1400)) - models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] - symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] - - - df_model = groupby(df_contract, [:model, :symmetry]) - for row in eachindex(models), col in eachindex(symmetries) - df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) - ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "memory (KiB)", yscale = log10) - @assert !isnothing(df_data) - for (k, v) in pairs(groupby(df_data, :version)) - Ds = v[!, :D] - memory = estimator.(v[!, :memory]) ./ (2^10) - I = sortperm(Ds) - scatterlines!(ax, Ds[I], memory[I]; label = "v$(k.version)") - end - axislegend(ax, position = :lt) - end - - Label(f[0, 0], "memory"; fontsize) - for (row, model) in enumerate(models) - Label(f[row, 0], model; rotation = pi / 2, fontsize, tellheight = false, tellwidth = false) - end - for (col, symmetry) in enumerate(symmetries) - Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) - end - - f -end -save(joinpath(resultdir, "bench_memory.png"), f_allocs) - -f_memory_relative = let f = Figure(; size = (1400, 1400)) - models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] - symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] - - - df_model = groupby(df_contract, [:model, :symmetry]) - for row in eachindex(models), col in eachindex(symmetries) - df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) - ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "memory / memory₀") - hlines!([1], color = :red) - @assert !isnothing(df_data) - - df_v = groupby(df_data, :version) - - v = get(df_v, (; version = 0), nothing) - Ds = v[!, :D] - times = estimator.(v[!, :memory]) - I = sortperm(Ds) - times₀ = times[I] - - for (k, v) in pairs(groupby(df_data, :version)) - k.version == 0 && continue - Ds = v[!, :D] - I = sortperm(Ds) - times = estimator.(v[!, :memory])[I] - scatterlines!(ax, Ds[I], times ./ times₀; label = "v$(k.version)") - end - axislegend(ax, position = :lt) - end - - Label(f[0, 0], "memory (relative)"; fontsize) - for (row, model) in enumerate(models) - Label(f[row, 0], model; rotation = pi / 2, fontsize, tellheight = false, tellwidth = false) - end - for (col, symmetry) in enumerate(symmetries) - Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) - end - - f + return f end -save(joinpath(resultdir, "bench_memory_relative.png"), f_memory_relative) - - -# Including preparation times -# --------------------------- -for n_applications in [3, 10, 30] - f_times_relative = let f = Figure(; size = (1400, 1400)) - models = ["heisenberg_nn", "heisenberg_nnn", "heisenberg_cylinder", "heisenberg_coulomb"] - symmetries = ["Trivial", "Irrep[U₁]", "Irrep[SU₂]"] - - - df_model = groupby(df_contract, [:model, :symmetry]) - dfp_model = groupby(df_prep, [:model, :symmetry]) - for row in eachindex(models), col in eachindex(symmetries) - df_data = get(df_model, (; model = models[row], symmetry = symmetries[col]), nothing) - dfp_data = get(dfp_model, (; model = models[row], symmetry = symmetries[col]), nothing) - ax = Axis(f[row, col], xscale = log10, xlabel = "D", ylabel = "Δt / Δt₀") - hlines!([1], color = :red) - @assert !isnothing(df_data) && !isnothing(dfp_data) - - df_v = groupby(df_data, :version) - dfp_v = groupby(dfp_data, :version) - - v = get(df_v, (; version = 0), nothing) - Ds = v[!, :D] - times = estimator.(v[!, :times]) - I = sortperm(Ds) - times₀ = n_applications .* times[I] - - vp = get(dfp_v, (; version = 0), nothing) - Ds = vp[!, :D] - times = estimator.(vp[!, :times]) - I = sortperm(Ds) - times₀ .+= times[I] - - df_data_v = groupby(dfp_data, :version) - for (k, v) in pairs(groupby(df_data, :version)) - k.version == 0 && continue - Ds = v[!, :D] - I = sortperm(Ds) - times = n_applications .* estimator.(v[!, :times])[I] - - vp = get(df_data_v, (; k.version), nothing) - @assert !isnothing(vp) - Ds = vp[!, :D] - I = sortperm(Ds) - times .+= estimator.(vp[!, :times][I]) - - scatterlines!(ax, Ds[I], times ./ times₀; label = "v$(k.version)") - end - axislegend(ax, position = :lt) - end - - Label(f[0, 0], "times"; fontsize) - for (row, model) in enumerate(models) - Label(f[row, 0], model; rotation = pi / 2, fontsize, tellheight = false, tellwidth = false) - end - for (col, symmetry) in enumerate(symmetries) - Label(f[0, col], symmetry; fontsize, tellheight = false, tellwidth = false) - end - - f - end - save(joinpath(resultdir, "bench_prep_times_relative_n=$n_applications.png"), f_times_relative) +for choice in (:allocs, :memory, :times), n in [1, 3, 10] + f = plot_result(df, n, choice) + save(joinpath(resultdir, "bench_$(choice)_$n.png"), f) + save(joinpath(resultdir, "bench_$(choice)_$n.svg"), f) end From f9c43c241025a8c143f02db0d2d11f6be321f3fe Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sun, 1 Mar 2026 13:08:35 -0500 Subject: [PATCH 36/37] fixes for type stability --- .../derivatives/hamiltonian_derivatives.jl | 40 +++++++------ src/algorithms/derivatives/mpo_derivatives.jl | 59 +++++++++++++++---- 2 files changed, 69 insertions(+), 30 deletions(-) diff --git a/src/algorithms/derivatives/hamiltonian_derivatives.jl b/src/algorithms/derivatives/hamiltonian_derivatives.jl index f458f564c..d1c64f38c 100644 --- a/src/algorithms/derivatives/hamiltonian_derivatives.jl +++ b/src/algorithms/derivatives/hamiltonian_derivatives.jl @@ -95,11 +95,11 @@ end function prepare_operator!!( H::JordanMPO_AC_Hamiltonian{O1, O2, O3}, backend::AbstractBackend, allocator ) where {O1, O2, O3} - C = H.C - B = H.B + C::Union{Missing, O2} = H.C + B::Union{Missing, O2} = H.B # onsite - D = if ismissing(H.D) + D::Union{Missing, O1} = if ismissing(H.D) missing elseif !ismissing(C) Id = TensorKit.id(storagetype(C), space(C, 2)) @@ -110,11 +110,11 @@ function prepare_operator!!( @plansor B[-1 -2; -3 -4] += Id[-1; -3] * H.D[-2; -4] missing else - W.D + H.D end # not_started - I = if ismissing(H.I) + I::Union{Missing, O1} = if ismissing(H.I) missing elseif !ismissing(C) Id = id(storagetype(C), space(C, 1)) @@ -125,7 +125,7 @@ function prepare_operator!!( end # finished - E = if ismissing(H.E) + E::Union{Missing, O1} = if ismissing(H.E) missing elseif !ismissing(B) Id = id(storagetype(B), space(B, 2)) @@ -135,10 +135,10 @@ function prepare_operator!!( H.E end - O3′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O3, typeof(backend), typeof(allocator)}) + O3′ = prepared_operator_type(O3, typeof(backend), typeof(allocator)) A = ismissing(H.A) ? H.A : prepare_operator!!(H.A, backend, allocator) - return JordanMPO_AC_Hamiltonian{O1, O2, O3′}(D, I, E, C, B, A) + return JordanMPO_AC_Hamiltonian{O1, O2, O3′}(D, I, E, C, B, A)::JordanMPO_AC_Hamiltonian{O1, O2, O3′} end @@ -292,21 +292,23 @@ function prepare_operator!!( H::JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4}, backend::AbstractBackend, allocator ) where {O1, O2, O3, O4} - CA = H.CA - AB = H.AB + CA::Union{Missing, O3} = H.CA + AB::Union{Missing, O3} = H.AB - CB = if !ismissing(CA) && !ismissing(H.CB) + CB::Union{Missing, O2} = if !ismissing(CA) && !ismissing(H.CB) Id = TensorKit.id(storagetype(H.CB), space(CA, 3)) @plansor CA[-1 -2 -3; -4 -5 -6] += H.CB[-1 -2; -4 -5] * Id[-3; -6] missing elseif !ismissing(AB) && !ismissing(H.CB) - + Id = TensorKit.id(storagetype(H.CB), space(AB, 3)) + @plansor CA[-1 -2 -3; -4 -5 -6] += H.CB[-2 -3; -5 -6] * Id[-1; -4] + missing else H.CB end # starting right - IC = if !ismissing(CA) && !ismissing(H.IC) + IC::Union{Missing, O2} = if !ismissing(CA) && !ismissing(H.IC) Id = TensorKit.id(storagetype(H.IC), space(CA, 1)) @plansor CA[-1 -2 -3; -4 -5 -6] += Id[-1; -4] * H.IC[ -2 -3; -5 -6] missing @@ -315,7 +317,7 @@ function prepare_operator!!( end # ending left - BE = if !ismissing(AB) && !ismissing(H.BE) + BE::Union{Missing, O2} = if !ismissing(AB) && !ismissing(H.BE) Id = TensorKit.id(storagetype(H.BE), space(AB, 3)) @plansor AB[-1 -2 -3; -4 -5 -6] += H.BE[-1 -2; -4 -5] * Id[-3; -6] missing @@ -324,7 +326,7 @@ function prepare_operator!!( end # onsite left - DE = if !ismissing(BE) && !ismissing(H.DE) + DE::Union{Missing, O1} = if !ismissing(BE) && !ismissing(H.DE) Id = TensorKit.id(storagetype(H.DE), space(BE, 1)) @plansor BE[-1 -2; -3 -4] += Id[-1; -3] * H.DE[-2; -4] missing @@ -339,7 +341,7 @@ function prepare_operator!!( end # onsite right - ID = if !ismissing(IC) && !ismissing(H.ID) + ID::Union{Missing, O1} = if !ismissing(IC) && !ismissing(H.ID) Id = TensorKit.id(storagetype(H.ID), space(IC, 2)) @plansor IC[-1 -2; -3 -4] += H.ID[-1; -3] * Id[-2; -4] missing @@ -353,7 +355,7 @@ function prepare_operator!!( end # finished - II = if !ismissing(IC) && !ismissing(H.II) + II::Union{Missing, O1} = if !ismissing(IC) && !ismissing(H.II) I = id(storagetype(H.II), space(IC, 1)) @plansor IC[-1 -2; -3 -4] += I[-1; -3] * H.II[-2; -4] II = missing @@ -366,7 +368,7 @@ function prepare_operator!!( end # unstarted - EE = if !ismissing(BE) && !ismissing(H.EE) + EE::Union{Missing, O1} = if !ismissing(BE) && !ismissing(H.EE) I = id(storagetype(H.EE), space(BE, 2)) @plansor BE[-1 -2; -3 -4] += H.EE[-1; -3] * I[-2; -4] EE = missing @@ -378,7 +380,7 @@ function prepare_operator!!( H.EE end - O4′ = Core.Compiler.return_type(prepare_operator!!, Tuple{O4, typeof(backend), typeof(allocator)}) + O4′ = prepared_operator_type(O4, typeof(backend), typeof(allocator)) AA = prepare_operator!!(H.AA, backend, allocator) return JordanMPO_AC2_Hamiltonian{O1, O2, O3, O4′}(II, IC, ID, CB, CA, AB, AA, BE, DE, EE) diff --git a/src/algorithms/derivatives/mpo_derivatives.jl b/src/algorithms/derivatives/mpo_derivatives.jl index 5d5b5a562..1eae41f54 100644 --- a/src/algorithms/derivatives/mpo_derivatives.jl +++ b/src/algorithms/derivatives/mpo_derivatives.jl @@ -112,21 +112,52 @@ end # prepared operators # ------------------ struct PrecomputedDerivative{ - T <: Number, S <: ElementarySpace, N₁, N₂, N₃, N₄, - T1 <: AbstractTensorMap{T, S, N₁, N₂}, T2 <: AbstractTensorMap{T, S, N₃, N₄}, - B <: AbstractBackend, A, + T <: Number, S <: ElementarySpace, M <: DenseVector{T}, + N₁, N₂, N₃, N₄, B <: AbstractBackend, A, } <: DerivativeOperator - leftenv::T1 - rightenv::T2 + leftenv::TensorMap{T, S, N₁, N₂, M} + rightenv::TensorMap{T, S, N₃, N₄, M} backend::B allocator::A end +function PrecomputedDerivative(L::AbstractTensorMap, R::AbstractTensorMap, backend, allocator) + S = TensorKit.check_spacetype(L, R) + T = TensorOperations.promote_contract(scalartype(L), scalartype(R)) + M = TensorKit.promote_storagetype(T, L, R) + return PrecomputedDerivative{T, S, M, numout(L), numin(L), numout(R), numin(R), typeof(backend), typeof(allocator)}(L, R, backend, allocator) +end -const PrecomputedCDerivative{T, S} = PrecomputedDerivative{T, S, 1, 2, 2, 1} -const PrecomputedACDerivative{T, S} = PrecomputedDerivative{T, S, 2, 3, 2, 1} -const PrecomputedAC2Derivative{T, S} = PrecomputedDerivative{T, S, 2, 3, 3, 2} +const PrecomputedCDerivative{T, S, M, B, A} = PrecomputedDerivative{T, S, M, 1, 2, 2, 1, B, A} +const PrecomputedACDerivative{T, S, M, B, A} = PrecomputedDerivative{T, S, M, 2, 3, 2, 1, B, A} +const PrecomputedAC2Derivative{T, S, M, B, A} = PrecomputedDerivative{T, S, M, 2, 3, 3, 2, B, A} VectorInterface.scalartype(::Type{<:PrecomputedDerivative{T}}) where {T} = T +TensorKit.storagetype(::Type{<:PrecomputedDerivative{T, S, M}}) where {T, S, M} = M + +Base.@assume_effects :foldable function prepared_operator_type( + ::Type{MPO_C_Hamiltonian{L, R}}, ::Type{B}, ::Type{A} + ) where {L, R, B, A} + T = TensorOperations.promote_contract(scalartype(L), scalartype(R)) + S = TensorKit.check_spacetype(L, R) + M = TensorKit.promote_storagetype(T, L, R) + return PrecomputedCDerivative{T, S, M, B, A} +end +Base.@assume_effects :foldable function prepared_operator_type( + ::Type{MPO_AC_Hamiltonian{L, O, R}}, ::Type{B}, ::Type{A} + ) where {L, O, R, B, A} + T = TensorOperations.promote_contract(scalartype(L), scalartype(O), scalartype(R)) + S = TensorKit.check_spacetype(L, O, R) + M = TensorKit.promote_storagetype(T, L, O, R) + return PrecomputedACDerivative{T, S, M, B, A} +end +Base.@assume_effects :foldable function prepared_operator_type( + ::Type{MPO_AC2_Hamiltonian{L, O₁, O₂, R}}, ::Type{B}, ::Type{A} + ) where {L, O₁, O₂, R, B, A} + T = TensorOperations.promote_contract(scalartype(L), scalartype(O₁), scalartype(O₂), scalartype(R)) + S = TensorKit.check_spacetype(L, O₁, O₂, R) + M = TensorKit.promote_storagetype(T, L, O₁, O₂, R) + return PrecomputedAC2Derivative{T, S, M, B, A} +end function prepare_operator!!( H::MPO_C_Hamiltonian{<:MPSTensor, <:MPSTensor}, @@ -134,7 +165,9 @@ function prepare_operator!!( ) leftenv = _transpose_tail(H.leftenv isa TensorMap ? H.leftenv : TensorMap(H.leftenv)) rightenv = H.rightenv isa TensorMap ? H.rightenv : TensorMap(H.rightenv) - return PrecomputedDerivative(leftenv, rightenv, backend, allocator) + return prepared_operator_type(typeof(H), typeof(backend), typeof(allocator))( + leftenv, rightenv, backend, allocator + ) end function prepare_operator!!( H::MPO_AC_Hamiltonian{<:MPSTensor, <:MPOTensor, <:MPSTensor}, @@ -146,7 +179,9 @@ function prepare_operator!!( leftenv = GL_O isa TensorMap ? GL_O : TensorMap(GL_O) rightenv = H.rightenv isa TensorMap ? H.rightenv : TensorMap(H.rightenv) - return PrecomputedDerivative(leftenv, rightenv, backend, allocator) + return prepared_operator_type(typeof(H), typeof(backend), typeof(allocator))( + leftenv, rightenv, backend, allocator + ) end function prepare_operator!!( @@ -160,7 +195,9 @@ function prepare_operator!!( leftenv = GL_O isa TensorMap ? GL_O : TensorMap(GL_O) rightenv = O_GR isa TensorMap ? O_GR : TensorMap(O_GR) - return PrecomputedDerivative(leftenv, rightenv, backend, allocator) + return prepared_operator_type(typeof(H), typeof(backend), typeof(allocator))( + leftenv, rightenv, backend, allocator + ) end function (H::PrecomputedCDerivative)(x::MPSBondTensor) From 4be4667bba8bf20da2aab06fcd34a2ca6a822c80 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sun, 1 Mar 2026 13:09:46 -0500 Subject: [PATCH 37/37] test for inferred --- test/algorithms/excitations.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/algorithms/excitations.jl b/test/algorithms/excitations.jl index 48d5720c5..d2d65b52c 100644 --- a/test/algorithms/excitations.jl +++ b/test/algorithms/excitations.jl @@ -19,7 +19,7 @@ verbosity_conv = 1 ψ, envs, _ = find_groundstate( ψ, H; maxiter = 400, verbosity = verbosity_conv, tol = 1.0e-10 ) - energies, ϕs = @inferred excitations( + energies, ϕs = @testinferred excitations( H, QuasiparticleAnsatz(), Float64(pi), ψ, envs ) @test energies[1] ≈ 0.41047925 atol = 1.0e-4 @@ -46,7 +46,7 @@ verbosity_conv = 1 ψ, envs, _ = leading_boundary( ψ, H, VUMPS(; maxiter = 400, verbosity = verbosity_conv, tol = 1.0e-10) ) - energies, ϕs = @inferred excitations( + energies, ϕs = @testinferred excitations( H, QuasiparticleAnsatz(), [0.0, Float64(pi / 2)], ψ, envs; verbosity = 0 ) @test abs(energies[1]) > abs(energies[2]) # has a minimum at pi/2 @@ -66,7 +66,7 @@ verbosity_conv = 1 ψ, envs, = find_groundstate(ψ, H; verbosity) # find energy with quasiparticle ansatz - energies_QP, ϕs = @inferred excitations(H, QuasiparticleAnsatz(), ψ, envs) + energies_QP, ϕs = @testinferred excitations(H, QuasiparticleAnsatz(), ψ, envs) @test variance(ϕs[1], H) < 1.0e-6 # find energy with normal dmrg @@ -74,14 +74,14 @@ verbosity_conv = 1 DMRG(; verbosity, tol = 1.0e-6), DMRG2(; verbosity, tol = 1.0e-6, trscheme = trunctol(; atol = 1.0e-4)), ) - energies_dm, _ = @inferred excitations(H, FiniteExcited(; gsalg), ψ) + energies_dm, _ = @testinferred excitations(H, FiniteExcited(; gsalg), ψ) @test energies_dm[1] ≈ energies_QP[1] + expectation_value(ψ, H, envs) atol = 1.0e-4 end # find energy with Chepiga ansatz - energies_ch, _ = @inferred excitations(H, ChepigaAnsatz(), ψ, envs) + energies_ch, _ = @testinferred excitations(H, ChepigaAnsatz(), ψ, envs) @test energies_ch[1] ≈ energies_QP[1] + expectation_value(ψ, H, envs) atol = 1.0e-4 - energies_ch2, _ = @inferred excitations(H, ChepigaAnsatz2(), ψ, envs) + energies_ch2, _ = @testinferred excitations(H, ChepigaAnsatz2(), ψ, envs) @test energies_ch2[1] ≈ energies_QP[1] + expectation_value(ψ, H, envs) atol = 1.0e-4 return energies_QP[1] end