Skip to content

Commit b4ea93f

Browse files
committed
preserve LM linearsolve structure
1 parent fabd33c commit b4ea93f

File tree

5 files changed

+35
-29
lines changed

5 files changed

+35
-29
lines changed

.github/workflows/CI.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ jobs:
1616
strategy:
1717
matrix:
1818
group:
19-
- Core
20-
- 23TestProblems
19+
- All
2120
version:
2221
- '1'
2322
steps:

docs/src/solvers/NonlinearSystemSolvers.md

+2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ features, but have a bit of overhead on very small problems.
6969
Automatic Jacobian Resetting. This is a fast method but unstable for most problems!
7070
- `GeneralKlement()`: Generalization of Klement's Quasi-Newton Method with Line Search and
7171
Automatic Jacobian Resetting. This is a fast method but unstable for most problems!
72+
- `LimitedMemoryBroyden()`: An advanced version of `LBroyden` which uses a limited memory
73+
Broyden method. This is a fast method but unstable for most problems!
7274

7375
### SimpleNonlinearSolve.jl
7476

src/jacobian.jl

+19-16
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ jacobian!!(::Number, cache) = last(value_derivative(cache.uf, cache.u))
5050

5151
# Build Jacobian Caches
5252
function jacobian_caches(alg::AbstractNonlinearSolveAlgorithm, f, u, p, ::Val{iip};
53-
linsolve_kwargs = (;),
54-
linsolve_with_JᵀJ::Val{needsJᵀJ} = Val(false)) where {iip, needsJᵀJ}
53+
linsolve_kwargs = (;), lininit::Val{linsolve_init} = Val(true),
54+
linsolve_with_JᵀJ::Val{needsJᵀJ} = Val(false)) where {iip, needsJᵀJ, linsolve_init}
5555
uf = JacobianWrapper{iip}(f, p)
5656

5757
haslinsolve = hasfield(typeof(alg), :linsolve)
@@ -95,25 +95,28 @@ function jacobian_caches(alg::AbstractNonlinearSolveAlgorithm, f, u, p, ::Val{ii
9595
Jᵀfu = J' * _vec(fu)
9696
end
9797

98-
linprob = LinearProblem(needsJᵀJ ? __maybe_symmetric(JᵀJ) : J,
99-
needsJᵀJ ? _vec(Jᵀfu) : _vec(fu); u0 = _vec(du))
100-
101-
if alg isa PseudoTransient
102-
alpha = convert(eltype(u), alg.alpha_initial)
103-
J_new = J - (1 / alpha) * I
104-
linprob = LinearProblem(J_new, _vec(fu); u0 = _vec(du))
98+
if linsolve_init
99+
linprob_A = alg isa PseudoTransient ?
100+
(J - (1 / (convert(eltype(u), alg.alpha_initial))) * I) :
101+
(needsJᵀJ ? __maybe_symmetric(JᵀJ) : J)
102+
linsolve = __setup_linsolve(linprob_A, needsJᵀJ ? Jᵀfu : fu, du, p, alg)
103+
else
104+
linsolve = nothing
105105
end
106106

107+
needsJᵀJ && return uf, linsolve, J, fu, jac_cache, du, JᵀJ, Jᵀfu
108+
return uf, linsolve, J, fu, jac_cache, du
109+
end
110+
111+
function __setup_linsolve(A, b, u, p, alg)
112+
linprob = LinearProblem(A, _vec(b); u0 = _vec(u))
113+
107114
weight = similar(u)
108115
recursivefill!(weight, true)
109116

110-
Pl, Pr = wrapprecs(alg.precs(needsJᵀJ ? __maybe_symmetric(JᵀJ) : J, nothing, u, p,
111-
nothing, nothing, nothing, nothing, nothing)..., weight)
112-
linsolve = init(linprob, alg.linsolve; alias_A = true, alias_b = true, Pl, Pr,
113-
linsolve_kwargs...)
114-
115-
needsJᵀJ && return uf, linsolve, J, fu, jac_cache, du, JᵀJ, Jᵀfu
116-
return uf, linsolve, J, fu, jac_cache, du
117+
Pl, Pr = wrapprecs(alg.precs(A, nothing, u, p, nothing, nothing, nothing, nothing,
118+
nothing)..., weight)
119+
return init(linprob, alg.linsolve; alias_A = true, alias_b = true, Pl, Pr)
117120
end
118121

119122
__get_nonsparse_ad(::AutoSparseForwardDiff) = AutoForwardDiff()

src/klement.jl

+9-9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ solves.
2727
linesearch
2828
end
2929

30+
function set_linsolve(alg::GeneralKlement, linsolve)
31+
return GeneralKlement(alg.max_resets, linsolve, alg.precs, alg.linesearch)
32+
end
33+
3034
function GeneralKlement(; max_resets::Int = 5, linsolve = nothing,
3135
linesearch = LineSearch(), precs = DEFAULT_PRECS)
3236
linesearch = linesearch isa LineSearch ? linesearch : LineSearch(; method = linesearch)
@@ -60,7 +64,7 @@ end
6064

6165
get_fu(cache::GeneralKlementCache) = cache.fu
6266

63-
function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::GeneralKlement, args...;
67+
function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg_::GeneralKlement, args...;
6468
alias_u0 = false, maxiters = 1000, abstol = 1e-6, internalnorm = DEFAULT_NORM,
6569
linsolve_kwargs = (;), kwargs...) where {uType, iip}
6670
@unpack f, u0, p = prob
@@ -70,17 +74,13 @@ function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::GeneralKlemen
7074

7175
if u isa Number
7276
linsolve = nothing
77+
alg = alg_
7378
else
7479
# For General Julia Arrays default to LU Factorization
75-
linsolve_alg = alg.linsolve === nothing && u isa Array ? LUFactorization() :
80+
linsolve_alg = alg_.linsolve === nothing && u isa Array ? LUFactorization() :
7681
nothing
77-
weight = similar(u)
78-
recursivefill!(weight, true)
79-
Pl, Pr = wrapprecs(alg.precs(J, nothing, u, p, nothing, nothing, nothing, nothing,
80-
nothing)..., weight)
81-
linprob = LinearProblem(J, _vec(fu); u0 = _vec(fu))
82-
linsolve = init(linprob, linsolve_alg; alias_A = true, alias_b = true, Pl, Pr,
83-
linsolve_kwargs...)
82+
alg = set_linsolve(alg_, linsolve_alg)
83+
linsolve = __setup_linsolve(J, _vec(fu), _vec(u), p, alg)
8484
end
8585

8686
return GeneralKlementCache{iip}(f, alg, u, fu, zero(fu), _mutable_zero(u), p, linsolve,

src/levenberg.jl

+4-2
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,12 @@ function SciMLBase.__init(prob::Union{NonlinearProblem{uType, iip},
213213
mat_tmp = zero(JᵀJ)
214214
rhs_tmp = nothing
215215
else
216-
mat_tmp = similar(JᵀJ, length(fu1) + length(u), length(u))
216+
# Preserve Types
217+
mat_tmp = vcat(J, DᵀD)
217218
fill!(mat_tmp, zero(eltype(u)))
218-
rhs_tmp = similar(mat_tmp, length(fu1) + length(u))
219+
rhs_tmp = vcat(fu1, u)
219220
fill!(rhs_tmp, zero(eltype(u)))
221+
linsolve = __setup_linsolve(mat_tmp, rhs_tmp, u, p, alg)
220222
end
221223

222224
return LevenbergMarquardtCache{iip, !_unwrap_val(linsolve_with_JᵀJ)}(f, alg, u, fu1,

0 commit comments

Comments
 (0)