Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "LinearSolve"
uuid = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae"
version = "3.86.0"
version = "3.86.1"
authors = ["SciML"]

[deps]
Expand Down
8 changes: 6 additions & 2 deletions ext/LinearSolveForwardDiffExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -393,11 +393,15 @@ end
# Check if the algorithm should use the direct dual solve path
# (algorithms that can work directly with Dual numbers without the primal/partials separation)
function _use_direct_dual_solve(alg)
# NOTE: RFLUFactorization is intentionally *not* on the direct path. Even when
# A carries duals, its fast Float64 factorization is BLAS/SIMD-grade, and routing
# the Dual problem through it falls back to generic scalar dual arithmetic, losing
# that speedup entirely (~40x slower, see issue #1052). The split path keeps the
# fast primal factorization and reuses it across the partial back-solves.
return alg isa GenericLUFactorization ||
alg isa LinearSolve.SpecializedLUFactorization ||
alg isa LinearSolve.SpecializedQRFactorization ||
alg isa LinearSolve.PureKLUFactorization ||
alg isa LinearSolve.RFLUFactorization
alg isa LinearSolve.PureKLUFactorization
end

function _use_direct_dual_solve(alg::DefaultLinearSolver)
Expand Down
13 changes: 13 additions & 0 deletions test/Core/forwarddiff_overloads.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ prob = LinearProblem(plain_A, b)
@test ≈(solve(prob, GenericLUFactorization()), plain_A \ b, rtol = 1.0e-9)
@test ≈(solve(prob, RFLUFactorization()), plain_A \ b, rtol = 1.0e-9)

# Regression test for #1052: RFLUFactorization must stay on the split
# primal/partials path and NOT take the direct dual solve. Its fast Float64
# factorization is BLAS/SIMD-grade; routing the Dual problem through it falls
# back to generic scalar dual arithmetic (~40x slower). Guard the routing
# decision directly so RFLU is never re-added to the direct path.
@testset "RFLU stays off the direct dual path (#1052)" begin
ext = Base.get_extension(LinearSolve, :LinearSolveForwardDiffExt)
@test !ext._use_direct_dual_solve(RFLUFactorization())
# Sanity: the genuinely-cheap-in-dual algorithms are still on the direct path.
@test ext._use_direct_dual_solve(GenericLUFactorization())
@test ext._use_direct_dual_solve(SpecializedLUFactorization())
end

# Overload Dense

A, b = h([ForwardDiff.Dual(5.0, 1.0, 0.0), ForwardDiff.Dual(5.0, 0.0, 1.0)])
Expand Down
Loading