Repository navigation
Faster stable lower-weight CGC solve - #64
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests.
🚀 New features to boost your workflow:
|
The Gram matrix `B` of the raising operators is very sparse, and all the shifted matrices `B + μ * I` share its sparsity pattern. It is now built as a sparse matrix `R * Rᵀ`, and for blocks of at least 100 pairs (and `Float64`) the shifted systems are factorized with CHOLMOD, reusing the symbolic factorization, instead of with a dense Cholesky. This restores the scaling of the CGC computation from before the stable solve, e.g. SU(3) (16,8,0)³ takes 12 s, compared to 23 s before the stable solve and 95 s with the dense solve. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lkdvos
force-pushed
the
claude/sparse-cholesky
branch
from
October 28, 2026 12:39
7919264 to
6ca74a2
Compare
The CGCs of every solved weight are now kept as a dense block `sols[p, α, j]`, together with its pairs and their indices, so that the right hand sides of the lowering equations read the parent CGCs from these blocks instead of from the `Dict`-backed `SparseArray`. The CGCs are written into the `SparseArray` once at the end, after reserving the space for all entries. Parent pairs are still enumerated over the full weight blocks, so that the pairs reached from omitted parent pairs, of which the CGCs vanish, are still solved for. This matters: `highest_weight_CGC` sets entries below `TOL_GAUGE` to zero, which the raising equations correct at lower weights. This reduces the time of e.g. SU(3) (12,6,0)³ from 1.41 s to 1.04 s, which is now dominated by the sparse Cholesky factorizations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lowering and raising equations are consistent, so any positive weighting of them has the same least-squares solution. Weighting the lowering equations with `c * eqs * A⁻² * eqsᵀ`, with `A = eqsᵀ * eqs`, turns the Sylvester equation `B * sols + sols * A = 2 * rhs * eqs` into `(B + c * I) * sols = rhs * eqs * (I + c * A⁻¹)`. This needs a single Cholesky factorization per weight instead of one for every eigenvalue of `A`, and no eigendecomposition. With `c` the mean eigenvalue of `A`, the CGCs are as accurate as before. This reduces the time of e.g. SU(3) (16,8,0)³ from 9.3 s to 5.8 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR speeds up the stable lower-weight CGC solve from #61. With dense factorizations, #61 made the per-weight cost cubic in the number of pairs. This PR brings the runtime back below that of the old, unstable code. It combines what were #64, #65 and #67, one commit per change:
B, the Gram matrix of the raising operators on the pairs |m₁, m₂⟩ of a weight, is very sparse. It is now built as a sparseR * Rᵀfrom the nonzero entries of the raising operators. Blocks of at least 100 pairs withFloat64entries are factorized with CHOLMOD. Small blocks and other element types keep the dense Cholesky. This addsSparseArrays, a stdlib, as a dependency.sols[p, α, j], together with its pairs and their indices. The right-hand sides read the parent CGCs from these blocks: one lookup in a small per-weightDictper parent pair, instead ofN123lookups in the largeSparseArray. TheSparseArrayis filled once at the end.B * sols + sols * A = 2 * rhs * eqsfrom Numerically stable computation of lower-weight CGCs #61, withA = eqsᵀ * eqs, needed one factorization ofB + μ * Ifor every eigenvalueμofA. The lowering and raising equations are consistent: the true CGCs satisfy both exactly, so any positive weighting of them has the same least-squares solution. Weighting the lowering equations withc * eqs * A⁻² * eqsᵀgivesc = tr(A) / size(A, 1)is the mean eigenvalue ofA.abs(v) <= TOL_PURGEare not written into theSparseArray, sincepurge!would remove them right afterwards. This leaves the result unchanged.Timings
Single BLAS thread, CGCs computed directly (bypassing the caches):
main(#61, dense)Very small cases, such as SU(3) (6,3,0)³ at about 10 ms, are slightly slower, because the Gram matrix is always built as a sparse matrix. About 60 % of the remaining time goes to the sparse Cholesky factorization.
Accuracy
Largest residual:
mainThe full test suite passes.
Tried and left out
gaugefix!zeroes small highest-weight CGCs (fixed in Keep small highest-weight CGCs ingaugefix!#66).🤖 Generated with Claude Code