Skip to content

Commit 3be4992

Browse files
Add Val{cache} type parameter to DirectLdiv!
This allows explicit control over whether DirectLdiv! caches a copy of the matrix during init. DirectLdiv!{true} caches, DirectLdiv!{false} does not. Default is Val(true) for backwards compatibility. - DirectLdiv!() → DirectLdiv!{true} (default, caches) - DirectLdiv!(Val(true)) → DirectLdiv!{true} (explicit caching) - DirectLdiv!(Val(false)) → DirectLdiv!{false} (no caching, may mutate A) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 88ec3d5 commit 3be4992

File tree

1 file changed

+35
-9
lines changed

1 file changed

+35
-9
lines changed

src/solve_function.jl

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,29 @@ function SciMLBase.solve!(cache::LinearCache, alg::LinearSolveFunction,
5555
end
5656

5757
"""
58-
DirectLdiv! <: AbstractSolveFunction
58+
DirectLdiv!{cache}() <: AbstractSolveFunction
5959
60-
A simple linear solver that directly applies the left-division operator (`\\`)
60+
A simple linear solver that directly applies the left-division operator (`\\`)
6161
to solve the linear system. This algorithm calls `ldiv!(u, A, b)` which computes
6262
`u = A \\ b` in-place.
6363
64+
## Type Parameter
65+
66+
- `cache::Bool`: Whether to cache a copy of the matrix for use with ldiv!.
67+
When `true`, a copy of the matrix is stored during `init` and used during `solve!`,
68+
preventing mutation of `cache.A`. Default is `true` for matrix types where `ldiv!`
69+
mutates the input (e.g., `Tridiagonal`, `SymTridiagonal`).
70+
6471
## Usage
6572
6673
```julia
74+
# Default: automatically caches for matrix types that need it
6775
alg = DirectLdiv!()
6876
sol = solve(prob, alg)
77+
78+
# Explicit caching control
79+
alg = DirectLdiv!(Val(true)) # Always cache
80+
alg = DirectLdiv!(Val(false)) # Never cache (may mutate A)
6981
```
7082
7183
## Notes
@@ -75,13 +87,27 @@ sol = solve(prob, alg)
7587
- Performance depends on the specific matrix type and its `ldiv!` implementation
7688
- No preconditioners or advanced numerical techniques are applied
7789
- Best used for small to medium problems or when `A` has special structure
90+
- For `Tridiagonal` and `SymTridiagonal`, `ldiv!` performs in-place LU factorization
91+
which mutates the matrix. Use `cache=true` (default) to preserve `cache.A`.
7892
"""
79-
struct DirectLdiv! <: AbstractSolveFunction end
93+
struct DirectLdiv!{cache} <: AbstractSolveFunction
94+
function DirectLdiv!(::Val{cache} = Val(true)) where {cache}
95+
new{cache}()
96+
end
97+
end
8098

81-
function SciMLBase.solve!(cache::LinearCache, alg::DirectLdiv!, args...; kwargs...)
99+
# Default solve! for non-caching or matrix types that don't need caching
100+
function SciMLBase.solve!(cache::LinearCache, alg::DirectLdiv!{false}, args...; kwargs...)
82101
(; A, b, u) = cache
83102
ldiv!(u, A, b)
103+
return SciMLBase.build_linear_solution(alg, u, nothing, cache)
104+
end
84105

106+
# For caching DirectLdiv! with general matrices, just use regular ldiv!
107+
# (caching is only needed for specific matrix types like Tridiagonal)
108+
function SciMLBase.solve!(cache::LinearCache, alg::DirectLdiv!{true}, args...; kwargs...)
109+
(; A, b, u) = cache
110+
ldiv!(u, A, b)
85111
return SciMLBase.build_linear_solution(alg, u, nothing, cache)
86112
end
87113

@@ -90,21 +116,21 @@ end
90116
# We cache a copy of the Tridiagonal matrix and use that for the factorization.
91117
# See https://github.com/SciML/LinearSolve.jl/issues/825
92118

93-
function init_cacheval(alg::DirectLdiv!, A::Tridiagonal, b, u, Pl, Pr, maxiters::Int,
119+
function init_cacheval(alg::DirectLdiv!{true}, A::Tridiagonal, b, u, Pl, Pr, maxiters::Int,
94120
abstol, reltol, verbose::Union{LinearVerbosity, Bool},
95121
assumptions::OperatorAssumptions)
96122
# Allocate a copy of the Tridiagonal matrix to use as workspace for ldiv!
97123
return copy(A)
98124
end
99125

100-
function init_cacheval(alg::DirectLdiv!, A::SymTridiagonal, b, u, Pl, Pr, maxiters::Int,
101-
abstol, reltol, verbose::Union{LinearVerbosity, Bool},
126+
function init_cacheval(alg::DirectLdiv!{true}, A::SymTridiagonal, b, u, Pl, Pr,
127+
maxiters::Int, abstol, reltol, verbose::Union{LinearVerbosity, Bool},
102128
assumptions::OperatorAssumptions)
103129
# SymTridiagonal also gets mutated by ldiv!, cache a copy
104130
return copy(A)
105131
end
106132

107-
function SciMLBase.solve!(cache::LinearCache{<:Tridiagonal}, alg::DirectLdiv!,
133+
function SciMLBase.solve!(cache::LinearCache{<:Tridiagonal}, alg::DirectLdiv!{true},
108134
args...; kwargs...)
109135
(; A, b, u, cacheval) = cache
110136
# Copy current A values into the cached workspace (non-allocating)
@@ -116,7 +142,7 @@ function SciMLBase.solve!(cache::LinearCache{<:Tridiagonal}, alg::DirectLdiv!,
116142
return SciMLBase.build_linear_solution(alg, u, nothing, cache)
117143
end
118144

119-
function SciMLBase.solve!(cache::LinearCache{<:SymTridiagonal}, alg::DirectLdiv!,
145+
function SciMLBase.solve!(cache::LinearCache{<:SymTridiagonal}, alg::DirectLdiv!{true},
120146
args...; kwargs...)
121147
(; A, b, u, cacheval) = cache
122148
# Copy current A values into the cached workspace (non-allocating)

0 commit comments

Comments
 (0)