Skip to content

Speed up simplicial selected inversion - #14

Merged
timweiland merged 3 commits into
mainfrom
perf/simplicial-selinv
Oct 5, 2026
Merged

timweiland merged 3 commits into
mainfrom
perf/simplicial-selinv

Conversation

@timweiland

Copy link
Copy Markdown
Owner

Many sparse problems in statistics have Cholesky factors with only a handful of nonzeros per column: tree-structured models, nested random effects, random walks and other latent Gaussian models. CHOLMOD factorizes these with its simplicial method, so selinv takes the simplicial path. That path was noticeably less optimized than the supernodal one, and the SuiteSparse benchmarks never exercised it.

Changes

  • Merge instead of search. The column update looked up each previously computed entry through SparseMatrixCSC indexing, which is a binary search, and it allocated a temporary vector per column. Both row lists involved are sorted, so the lookups are now a single merge. When the merge has to skip far ahead in a long column, a galloping search keeps the cost logarithmic.
  • Direct factor access. Simplicial CHOLMOD factors are read directly from their column arrays instead of going through sparse(F.L), which took about as long as the inversion itself on low-fill problems. Unpacked factors, such as those left by lowrankupdate, are handled.
  • Fused LL → LDL conversion. This now happens column by column during the sweep instead of in a separate pass.
  • selinv_diag. The diagonal is read directly from the result instead of through generic diag on a Symmetric sparse matrix, and is depermuted with a single scatter. Before, selinv_diag was slower than the full selinv it calls.

The supernodal code is untouched.

Results

M1 Max, single-threaded. Low-fill problems are generated by the new benchmark/lowfill_problems.jl:

problem n selinv before → after selinv_diag before → after
tree-structured field 200k 12.2 → 2.5 ms 35.9 → 2.9 ms
tree, 3 correlated fields 60k 6.8 → 1.7 ms 12.6 → 1.7 ms
nested random effects 105k 27.8 → 11.1 ms 38.7 → 11.5 ms
second-order random walk 1M 79.4 → 21.8 ms 146 → 24.8 ms
2D grid (supernodal control) 90k 70.9 → 70.7 ms 72.2 → 71.8 ms

On these problems, a selected inversion now costs 5–25% of the Cholesky factorization.

Higher-fill matrices pushed through the simplicial path, either by forcing CHOLMOD's simplicial mode or through the LDLFactorizations extension, also benefit. For example, crystm03 drops from 19.5 s to 1.6 s with forced simplicial CHOLMOD. The SuiteSparse benchmark set, which is entirely supernodal, is unchanged within noise.

Testing

New tests in test/test_simplicial.jl check the results against a dense inverse for low-fill problems with LL and LDL factors, unpacked factors after a rank update, a short column pointing into a long one, and a supernodal factor passed to selinv_simplicial. The full suite passes on Julia 1.10, 1.11 and 1.12.

The simplicial kernel looked up each entry of the already-computed part of
the selected inverse with a binary search through sparse indexing, and
allocated a temporary vector per column. Since both row lists involved are
sorted, the lookups can be done as a single merge instead, with a galloping
search when the merge needs to skip far ahead in a long column.

Also:
- Read simplicial CHOLMOD factors directly from their column arrays
  instead of converting through `sparse(F.L)`.
- Convert LL to LDL column by column inside the sweep.
- Extract the diagonal in `selinv_diag` directly and depermute it with a
  single scatter.

Adds tests for the simplicial path on low-fill problems, LL and LDL
factors, unpacked factors after a rank update, and supernodal factors
passed to `selinv_simplicial`.
Latent Gaussian models whose Cholesky factors have few nonzeros per
column (tree-structured fields, nested random effects, random walks), so
CHOLMOD factorizes them with the simplicial method. A 2D grid serves as a
supernodal control.
@timweiland
timweiland merged commit 0cb37a7 into main Oct 5, 2026
3 checks passed
@timweiland
timweiland deleted the perf/simplicial-selinv branch October 5, 2026 10:26
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.

1 participant