Skip to content

Take a zero eigenvalue for zero in the gauge fixing of the simple update - #124

Open
aoymt wants to merge 1 commit into
developfrom
fix/gauge-fix-rank-deficient
Open

aoymt wants to merge 1 commit into
developfrom
fix/gauge-fix-rank-deficient

Conversation

@aoymt

@aoymt aoymt commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #123.

Summary

With [parameter.simple_update] gauge_fix = true, a bond with fewer nonzero Schmidt values than its dimension filled the tensors with NaN, and the run ended in the environment update with a BLAS error (exit 255). A product initial state without noise is enough.

Input Before After
The input of #123 (Heisenberg, Neel state, noise = 0.0) exit 255 -0.656470
The same with gauge_fix = false -0.656471 unchanged
The same with noise = 0.01 -0.656469397980045777 the same to all digits
Decoupled dimers at beta = 1, gauge_fix = true, lambda_cutoff = 1e-7 exit 255 exact (-0.124700)

Cause

fix_local_gauge (src/iTPS/core/local_gauge.cpp) diagonalizes the boundary tensors of the two ends of a bond and divides by the square roots of their eigenvalues. boundary_tensor takes the inverse of a lambda below lambda_cutoff for zero, so on a rank-deficient bond the boundary tensors have zero eigenvalues. They come out of eigh as a round-off of either sign: 1 / sqrt(0) is inf, and the square root of a negative one is NaN.

Changes

  • A square root at or below lambda_cutoff times the largest is taken for zero, and its inverse too, as is done for lambda.
  • The same function tested lambda1[connect2] against the cutoff and inverted lambda2[connect2]. It tests lambda2 now.

Both are needed: with the first change alone, the two cases of the new test still end with exit 255.

Relation to #121

With lambda_cutoff at its present default, 1e-12, the dimers do not show this. A numerically zero lambda of about 1e-8 is then inverted, and the eigenvalue is not zero. Raising the default to 1e-7 (#121) is what makes them crash.

This should be merged before #121, or together with it. Otherwise an input with gauge_fix = true that runs today would stop running.

The four open branches (#120, #121, the version one and this one) merge without conflicts, and the test suite passes on the result (83/83).

Tests

  • New: gauge_fix_rank_deficient, an end-to-end test with two cases.
    • The Heisenberg antiferromagnet from the Neel state without noise: the energy must be that of the same run without gauge fixing.
    • Decoupled dimers at a finite temperature with lambda_cutoff = 1e-7: against the exact energy.
  • Both cases fail with a build of develop.
  • ctest: 78/78 (Apple clang, no MPI, Release).

gauge_fix is off by default, and no input under sample/ or test/ turned it on before this test.

Not tested: an MPI build.

🤖 Generated with Claude Code

With [parameter.simple_update] gauge_fix = true, a bond with fewer nonzero
Schmidt values than its dimension filled the tensors with NaN, and the run
ended in the environment update with "BLAS error: Parameter number 9
passed to cblas_dgemm had an invalid value" (#123). A product initial
state without noise is enough.

fix_local_gauge diagonalizes the boundary tensors of the two ends of the
bond and divides by the square roots of their eigenvalues. boundary_tensor
takes the inverse of a lambda below lambda_cutoff for zero, so on such a
bond the boundary tensors have zero eigenvalues, which come out of eigh as
a round-off of either sign: 1 / sqrt(0) is inf, and the square root of a
negative one is NaN. A square root at or below lambda_cutoff times the
largest is now taken for zero, and its inverse too, as is done for lambda.

The same function tested lambda1[connect2] against the cutoff and inverted
lambda2[connect2]. It tests lambda2 now.

gauge_fix is off by default and no input under sample/ or test/ turned it
on. gauge_fix_rank_deficient is a new test: the Heisenberg antiferromagnet
from the Neel state without noise, whose energy must be that of the same
run without gauge fixing, and decoupled dimers at a finite temperature
with lambda_cutoff = 1e-7 against the exact energy. Both cases end with
exit code 255 without the first change, and also with the first change
alone, without the second.

With lambda_cutoff at its present default, 1e-12, the dimers do not show
this: a numerically zero lambda of about 1e-8 is then inverted and the
eigenvalue is not zero. Raising the default (#121) is what would make them
crash, so this goes in before it or together with it.

With noise = 0.01 on the initial state, where no bond is rank deficient,
the energy of the first case is the same to all digits before and after.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@yomichi yomichi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick fix. I built c33d165 and checked gauge_fix_rank_deficient with mutations:

  • the lambda1/lambda2 fix undone: both cases exit with 255,
  • the former loop (no sign guard, no cutoff) with the lambda2 fix kept: both cases exit with 255,
  • unmodified: both pass, and the Neel energies with and without gauge fixing agree to 1.4e-6.

So both changes are needed, as you say. I also merged #121 into it: gauge_fix_rank_deficient, rank_deficient_bond and test_input pass.

Two small notes, no change needed for this PR:

  • The relative cutoff in sqrt_and_inverse is not exercised by the test. I counted what it sets to zero: 600 values in the Neel case and 180000 in the dimers, all from eigenvalues that were zero or negative, none positive. With the cutoff removed (and the sign guard kept), the test still passes. Keeping it is right for a positive round-off eigenvalue; it is just not pinned.
  • Nit: the comment in neel() says "1e-6 here", and the tolerance is 1e-4.

This branch has not been deployed

No deployments
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