Skip to content

feat: BUG integrator - #468

Merged
lkdvos merged 13 commits into
mainfrom
ld-bug-consolidate
Aug 3, 2026
Merged

feat: BUG integrator#468
lkdvos merged 13 commits into
mainfrom
ld-bug-consolidate

Conversation

@lkdvos

@lkdvos lkdvos commented Jul 20, 2026

Copy link
Copy Markdown
Member

This PR adds the BUG integrator as an alternative to TDVP. It's a consolidation of part of #454.
The main purpose is to have a stable integrator to be able to handle (large) imaginary or complex time steps in a way that is more stable than standard TDVP since it does not involve a backwards integration.

@Jutho I would be very happy to hear your opinions on this, I'm still not completely sure I've done everything correctly and many parts still confuse me, so a second set of eyes would be greatly appreciated. 🙃

@lkdvos
lkdvos requested a review from Jutho July 20, 2026 23:47
@lkdvos
lkdvos force-pushed the ld-bug-consolidate branch from 21e8388 to f8a54a2 Compare July 20, 2026 23:55
@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.73585% with 13 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/algorithms/timestep/bug.jl 89.85% 7 Missing ⚠️
src/states/orthoview.jl 83.33% 5 Missing ⚠️
src/algorithms/timestep/tdvp.jl 83.33% 1 Missing ⚠️
Files with missing lines Coverage Δ
src/MPSKit.jl 100.00% <ø> (ø)
src/algorithms/timestep/time_evolve.jl 100.00% <100.00%> (ø)
src/algorithms/timestep/tdvp.jl 83.50% <83.33%> (+0.34%) ⬆️
src/states/orthoview.jl 87.37% <83.33%> (-0.73%) ⬇️
src/algorithms/timestep/bug.jl 89.85% <89.85%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@lkdvos
lkdvos marked this pull request as ready for review July 21, 2026 01:10
Comment thread docs/src/changelog.md Outdated
Comment thread src/algorithms/timestep/bug.jl Outdated
Comment thread src/algorithms/timestep/bug.jl Outdated
Comment thread src/algorithms/timestep/tdvp.jl Outdated
Comment thread src/algorithms/timestep/tdvp.jl
Comment thread src/algorithms/timestep/bug.jl Outdated
Comment thread src/algorithms/timestep/bug.jl Outdated
Comment thread src/algorithms/timestep/bug.jl
Comment thread src/algorithms/timestep/bug.jl Outdated
Comment thread src/algorithms/timestep/bug.jl Outdated
Comment thread src/algorithms/timestep/bug.jl Outdated
@lkdvos
lkdvos force-pushed the ld-bug-consolidate branch 2 times, most recently from 6b058d1 to d7251aa Compare July 30, 2026 17:17
@lkdvos

lkdvos commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

Alright, after a round of review and additional discussions, (thanks @Jutho for the insights!), I think I've now addressed some of the issues that were here and added some more convenience parts to the implementation.

The first major thing is that I now no longer truncate the augmented basis, which is indeed incorrect. From the small tests I ran this definitely did improve the accuracy, so this was definitely a needed step.

To consider where the truncation actually has to happen, I agree that the original formulation of the algorithm would mean to first evolve left-to-right, and then truncate right-to-left. Since I kind of wanted to keep some of the left-right symmetry here, I made a small alteration that I think is both more accurate as well as more efficient, but I would be happy to get a second opinion on this. The train of thought goes something like this: imagine that on the reverse pass, instead of first truncating right to left, then regauging to the right, and then starting the new evolution run from right-to-left again, I truncate site L-1, and then immediately start the evolution, as if no truncation happened 1:L-2. This means I don't have to regauge back up the chain, and additionally the evolution sees a less truncated state. Then I do the same for site L-2, all the way down to 1.
I'm pretty sure this change in order keeps everything consistent, of course up to truncation errors but it seems at least sound in my head?

I also added some timeroutput support to be able to track where the time is actually spent (almost entirely in the exponentiator, of course), but this can be useful for debugging.

Comment thread src/algorithms/timestep/bug.jl Outdated
Comment thread src/algorithms/timestep/bug.jl Outdated
Comment thread src/algorithms/timestep/bug.jl
Comment thread src/algorithms/timestep/bug.jl Outdated
Comment thread src/states/orthoview.jl Outdated
Comment thread src/algorithms/timestep/tdvp.jl
@Jutho

Jutho commented Aug 3, 2026

Copy link
Copy Markdown
Member

Ok, I think this looks fine, up to a few suggestions. I could probably go over it once more in even more detail, but I don't have time for this right now, so feel free to merge.

lkdvos and others added 5 commits August 3, 2026 08:59
Renormalization after each step is now controlled by an explicit `normalize`
kwarg on `timestep`/`time_evolve` (default `false`) instead of being tied to
`imaginary_evolution`. By default the norm is preserved, so it retains useful
information (accumulated truncation error in real time, decaying weight in
imaginary time); pass `normalize = true` to renormalize, e.g. for ground-state
or thermal-state search. Threaded through the driver and both TDVP/TDVP2
integrators; test norm/imaginary-time expectations updated accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the `BUG` time-evolution algorithm: a symmetric second-order Basis-Update
& Galerkin integrator for finite MPS. Unlike `TDVP` it has no backward-in-time
substep (stable for imaginary-time evolution); passing a truncating `trscheme`
enables rank-adaptivity, growing and shrinking the bond dimension to track the
entanglement. Wires up the export, include, docs (`@docs` entry, changelog,
Ceruti & Lubich 2022 reference).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add tests for the sequential `BUG` integrator: energy conservation, eigenstate
phase, agreement with TDVP, second-order convergence vs dense propagation,
imaginary-time cooling, LazySum/time-dependent operators, rank-adaptivity, and
symmetric tensors (U(1)/Z2/SU(2), incl. rank-adaptive-symmetric). Plus unit
tests for the `_bug_augment_*` basis-augmentation helpers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Remove unused `tolgauge`/`gaugemaxiter` fields from the `BUG` struct and
  constructor: they are read only for `InfiniteMPS` gauge reconstruction in
  TDVP, and BUG is finite-only, so they were silently ignored.
- Clarify the `BUG` docstring (single-site, symmetric second-order, finite MPS)
  and correct the `finalize` signature docs (`finalize(t, …)`, not `iter`) in
  BUG, TDVP and TDVP2.
- Document the `normalize` behavior change under changelog "Changed": it is now
  an explicit kwarg (default false) decoupled from `imaginary_evolution`;
  imaginary-time evolution no longer renormalizes unless `normalize = true`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lkdvos and others added 7 commits August 3, 2026 09:00
Co-authored-by: Jutho <Jutho@users.noreply.github.com>

small docstring update
The BUG work added a lot of tests that were written to debug the
implementation as it was developed. Now that it is settled, keep BUG
tested at the level TDVP/TDVP2 were: parametrized into the existing
shared testsets, plus one testset for its distinguishing feature.

Removed:
- `test/algorithms/bug_augment.jl` — unit tests for the inlined
  basis-augmentation step (isometry, old-first per sector, rank growth)
- `second-order convergence (BUG)` — log-log temporal-order fit against
  a dense reference
- `BUG agrees with TDVP` — subsumed by the `Finite BUG` testset, which
  runs the same system and asserts energy plus the eigenstate phase
- four of the five `BUG with truncation` testsets, and the Z2/SU(2)/
  second-sector/imaginary-time repeats of the symmetric-tensor block

Retained beyond the shared testsets: one truncated-accuracy testset
against a dense reference, one imaginary-time testset (BUG has no
backward substep), and one U(1) testset covering energy conservation,
eigenstate phase and boundary-charge preservation — symmetric coverage
the finite integrators did not have before.

Every `BUG` in the file is now constructed with a `trunc`: uncapped,
the augmentation doubles the bond dimension on every half-sweep with
nothing cutting it back, which is neither realistic nor cheap. Added
bond-dimension bounds where the cap should bite.

84 tests pass; the file runs in 573s, down from 879s.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@lkdvos
lkdvos force-pushed the ld-bug-consolidate branch 3 times, most recently from 6cd3b70 to 6d7b95c Compare August 3, 2026 13:06
@lkdvos

lkdvos commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

Will merge this as soon as tests pass :)

Co-authored-by: Jutho <Jutho@users.noreply.github.com>
@lkdvos
lkdvos force-pushed the ld-bug-consolidate branch from 6d7b95c to a4af2ab Compare August 3, 2026 14:02
@lkdvos
lkdvos merged commit 1c81790 into main Aug 3, 2026
28 of 29 checks passed
@lkdvos
lkdvos deleted the ld-bug-consolidate branch August 3, 2026 15:31
lkdvos added a commit that referenced this pull request Aug 3, 2026
Both landed after these pages were drafted, and the pages enumerate the time-evolution
options, so leaving them out would have shipped a listing that is wrong by omission.

`BUG` (#468) gets a how-to recipe, a paragraph in the algorithm landscape, and a row in the
decision table. Two things are worth stating explicitly and are easy to get wrong from the
name alone: it is the one single-site integrator that can change bond dimension, and a
`truncrank(D)` leaves the state at `2D`, because each half-sweep only truncates the previous
one's basis augmentation — so a follow-up `SvdCut` is needed to actually land on `D`.

`Zipup` (#470) is documented alongside the propagator-MPO route it belongs to, including the
two API differences from the variational path: no initial guess, and a 2-tuple return. It is
not mentioned on the statistical-mechanics page, since it is finite open-boundary only.

`approximate`/`approximate!` had no topical reference home at all; they now live on the
time-evolution reference page next to `Zipup`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lkdvos added a commit that referenced this pull request Aug 3, 2026
Both landed after these pages were drafted, and the pages enumerate the time-evolution
options, so leaving them out would have shipped a listing that is wrong by omission.

`BUG` (#468) gets a how-to recipe, a paragraph in the algorithm landscape, and a row in the
decision table. Two things are worth stating explicitly and are easy to get wrong from the
name alone: it is the one single-site integrator that can change bond dimension, and a
`truncrank(D)` leaves the state at `2D`, because each half-sweep only truncates the previous
one's basis augmentation — so a follow-up `SvdCut` is needed to actually land on `D`.

`Zipup` (#470) is documented alongside the propagator-MPO route it belongs to, including the
two API differences from the variational path: no initial guess, and a 2-tuple return. It is
not mentioned on the statistical-mechanics page, since it is finite open-boundary only.

`approximate`/`approximate!` had no topical reference home at all; they now live on the
time-evolution reference page next to `Zipup`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants