From 453b26b0a78b7787275333bd528fc5d40a8be258 Mon Sep 17 00:00:00 2001 From: VictorVanthilt Date: Wed, 12 Aug 2026 17:03:40 +0200 Subject: [PATCH 1/3] first attempt at fixing non-square finite time evo mpos --- src/algorithms/timestep/taylorcluster.jl | 40 +++++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/algorithms/timestep/taylorcluster.jl b/src/algorithms/timestep/taylorcluster.jl index b129e9d0c..0e195ad89 100644 --- a/src/algorithms/timestep/taylorcluster.jl +++ b/src/algorithms/timestep/taylorcluster.jl @@ -130,21 +130,45 @@ function _taylor_loopback!(mpo, virtual_sz, linds, ::Val{N}, τ::Number) where { V_right = virtual_sz[i + 1] linds_right = linds[i + 1] cinds_right = CartesianIndices(linds_right) - for b in cinds_right[2:end] - all(in((1, V_right)), b.I) || continue - b_lin = linds_right[b] - a = count(==(V_right), b.I) + threelevel_linds_right = _get_threelevel_linds(V_right, linds_right) + for c in threelevel_linds_right + c_cart = cinds_right[c] + a = count(==(V_right), c_cart.I) factor = τ^a * factorial(N - a) / factorial(N) - slice[:, 1, 1, 1] = slice[:, 1, 1, 1] + factor * slice[:, 1, 1, b_lin] - for I in nonzero_keys(slice) - (I[1] == b_lin || I[4] == b_lin) && delete!(slice, I) - end + slice[:, 1, 1, 1] = slice[:, 1, 1, 1] + factor * slice[:, 1, 1, c] end end + _remove_threelevels!(mpo, virtual_sz, linds) return mpo end +function _get_threelevel_linds(virtual_sz, linds) + row_threelevels_linds = Int[] + for c in CartesianIndices(linds) + c_lin = linds[c] + cI = c.I + all(in((1, virtual_sz)), cI) && !all(==(1), cI) && push!(row_threelevels_linds, c_lin) + end + return row_threelevels_linds +end + +# removes the rows and columns that are labled by level-labels made up of 1 and "3" only, but not all 1's. +function _remove_threelevels!(mpo, virtual_sz, linds) + for (i, slice) in enumerate(parent(mpo)) + # remove the three-level rows + row_threelevel_linds = _get_threelevel_linds(virtual_sz[i], linds[i]) + + # remove the three-level columns + col_threelevel_linds = _get_threelevel_linds(virtual_sz[i + 1], linds[i + 1]) + + for I in nonzero_keys(slice) + (I[1] in row_threelevel_linds || I[4] in col_threelevel_linds) && delete!(slice, I) + end + end + return +end + # Algorithm 2: collapse rows and columns that are equivalent under the # permutation symmetry of the Taylor expansion. function _taylor_remove_equivalents!(mpo, virtual_sz, linds) From f5489dc0c97ed32fc09de8081e4cd02385ee3ec4 Mon Sep 17 00:00:00 2001 From: VictorVanthilt Date: Thu, 13 Aug 2026 10:57:17 +0200 Subject: [PATCH 2/3] Build threelevel cartesianindices for more efficient deletion --- src/algorithms/timestep/taylorcluster.jl | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/algorithms/timestep/taylorcluster.jl b/src/algorithms/timestep/taylorcluster.jl index 0e195ad89..89ad94026 100644 --- a/src/algorithms/timestep/taylorcluster.jl +++ b/src/algorithms/timestep/taylorcluster.jl @@ -156,14 +156,26 @@ end # removes the rows and columns that are labled by level-labels made up of 1 and "3" only, but not all 1's. function _remove_threelevels!(mpo, virtual_sz, linds) for (i, slice) in enumerate(parent(mpo)) - # remove the three-level rows + # three-level rows row_threelevel_linds = _get_threelevel_linds(virtual_sz[i], linds[i]) - # remove the three-level columns + # three-level columns col_threelevel_linds = _get_threelevel_linds(virtual_sz[i + 1], linds[i + 1]) - for I in nonzero_keys(slice) - (I[1] in row_threelevel_linds || I[4] in col_threelevel_linds) && delete!(slice, I) + # build the set of all CartesianIndices in a three-level row or column + d1, _, _, d4 = size(slice) + threelevel_cinds = Set{CartesianIndex{4}}() + for r in row_threelevel_linds + union!(threelevel_cinds, CartesianIndices((r:r, 1:1, 1:1, 1:d4))) + end + for c in col_threelevel_linds + union!(threelevel_cinds, CartesianIndices((1:d1, 1:1, 1:1, c:c))) + end + + # remove the nonzero entries that fall in a three-level row or column + # this avoids a lot of misses wrt looping over all nonzero_keys + for I in intersect(nonzero_keys(slice), threelevel_cinds) + delete!(slice, I) end end return From 08ee9f6884f70a6ffd5af8ffc179c8e773657d70 Mon Sep 17 00:00:00 2001 From: VictorVanthilt Date: Thu, 13 Aug 2026 12:14:58 +0200 Subject: [PATCH 3/3] update changelog --- docs/src/changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/changelog.md b/docs/src/changelog.md index 1788564bd..61b69d258 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -96,6 +96,9 @@ When releasing a new version, move the "Unreleased" changes to a new version sec and the right virtual leg of `mpo[end]` and contracted the two — which at length 1 is the *same* tensor, so it returned `O * O` on twice the physical space instead of `O`. ([#484](https://github.com/QuantumKitHub/MPSKit.jl/pull/484)) +- `make_time_mpo` with `TaylorCluster` on a Hamiltonian whose virtual bond dimension varies along + the chain. The loopback step labels rows by the left virtual bond and columns by the right one, but deleted the absorbed "three-level" rows and columns using the *right*-bond linear index for both. When the two bonds differ in size this deletes the wrong rows, leaving spurious rows behind and removing valid ones, so the resulting time-evolution MPO was wrong. Rows and columns are now derived from their own bond, and the removal happens in a single pass after all loopback contributions have been accumulated instead of inside the loop that still reads those entries. + ([#511](https://github.com/QuantumKitHub/MPSKit.jl/pull/511)) ### Performance