Skip to content

Route RFLU matrix right-hand sides through TriangularSolve (1.5-1.7x multi-RHS solve)#1117

Merged
ChrisRackauckas merged 1 commit into
SciML:mainfrom
ChrisRackauckas-Claude:rflu-trsm
Jul 26, 2026
Merged

Route RFLU matrix right-hand sides through TriangularSolve (1.5-1.7x multi-RHS solve)#1117
ChrisRackauckas merged 1 commit into
SciML:mainfrom
ChrisRackauckas-Claude:rflu-trsm

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member

⚠️ Draft — please ignore until reviewed by @ChrisRackauckas.

Independent of the SupernodalLU PRs. Second TriangularSolve PR — the first is #1113 (SupernodalLU panel trsms); this one is the dense RFLU solve path.

Why here and not in RecursiveFactorization

RecursiveFactorization already uses TriangularSolve inside its own lu!, but the ldiv! that consumes the factorization only does so for the pivotless NotIPIV case (RecursiveFactorization/src/lu.jl:54). A pivoted LU — which is exactly what RFLUFactorization produces — falls back to LinearAlgebra, i.e. BLAS trsv/trsm.

Fixing it inside RecursiveFactorization would be type piracy: it owns neither ldiv! nor LU, so such a method would change behavior for all Julia code holding a standard LU, whether or not it came from RF. LinearSolve owns solve! for its own algorithm type, so this is the legitimate home.

Measured (solve-only, factorization already computed, 1 BLAS thread)

n nrhs=4 nrhs=8
64 6.31 → 3.76 µs (1.68×) 8.76 → 5.40 µs (1.62×)
128 21.11 → 12.68 µs (1.66×) 26.20 → 17.22 µs (1.52×)
256 86.43 → 55.11 µs (1.57×) 97.09 → 67.87 µs (1.43×)
500 277.11 → 175.42 µs (1.58×) 301.13 → 225.77 µs (1.33×)

What deliberately does not change

Vector right-hand sides keep the stdlib path — TriangularSolve has no vector kernel, and reshaping to n×1 measured 1.09× at n=128 but 0.88× by n=256. A single-column matrix is the same case in disguise and takes the matrix method, so it is guarded explicitly. With the guard, nrhs=1 and vector results are bit-identical to the stdlib path (agreement exactly 0.0), while multi-RHS keeps 1.5–1.7×.

TriangularSolve is added as a weakdep purely to trigger the extension; RecursiveFactorization already depends on it, so using RecursiveFactorization alone still activates everything and nobody's dependency graph changes.

GROUP=Core passes, with a new multi-RHS RFLU testset covering the direct and cache-reuse paths.

🤖 Generated with Claude Code

https://claude.ai/code/session_017rr42T1vFRRT8D7DMAmJzf

RecursiveFactorization already uses TriangularSolve inside its own lu!,
but the ldiv! that consumes the factorization only does so for the
pivotless NotIPIV case (RecursiveFactorization/src/lu.jl); a pivoted LU -
which is what RFLUFactorization produces - falls back to LinearAlgebra,
i.e. BLAS trsv/trsm.

Fixing that inside RecursiveFactorization would be type piracy (it owns
neither ldiv! nor LU), so it belongs here: LinearSolve owns solve! for
its own algorithm type. Matrix right-hand sides now go through
TriangularSolve's blocked kernels.

Measured solve-only, factorization already computed, 1 BLAS thread:

  n     nrhs=4                nrhs=8
  64    6.31 -> 3.76 us       8.76 -> 5.40 us    (1.68x / 1.62x)
  128  21.11 -> 12.68 us     26.20 -> 17.22 us   (1.66x / 1.52x)
  256  86.43 -> 55.11 us     97.09 -> 67.87 us   (1.57x / 1.43x)
  500 277.11 -> 175.42 us   301.13 -> 225.77 us  (1.58x / 1.33x)

Vector right-hand sides keep the stdlib path: TriangularSolve has no
vector kernel, and reshaping to n x 1 measured 1.09x at n=128 but 0.88x
by n=256. A single-column matrix is the same case in disguise, so it is
guarded explicitly - with the guard, nrhs=1 and vector results are
bit-identical to the stdlib path (agreement exactly 0.0), while
multi-RHS keeps 1.5-1.7x.

TriangularSolve is added as a weakdep purely to trigger the extension;
RecursiveFactorization depends on it, so loading RecursiveFactorization
alone still activates everything and no dependency graph changes.

New multi-RHS RFLU testset covers the direct and cache-reuse paths.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ChrisRackauckas
ChrisRackauckas marked this pull request as ready for review July 26, 2026 10:00
@ChrisRackauckas
ChrisRackauckas merged commit e7742ab into SciML:main Jul 26, 2026
61 of 62 checks passed
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