Skip to content

Commit 6b83054

Browse files
committed
Implement IIP Version of Broyden
1 parent 9c42b4f commit 6b83054

File tree

5 files changed

+95
-5
lines changed

5 files changed

+95
-5
lines changed

src/NonlinearSolve.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,21 @@ include("levenberg.jl")
6969
include("gaussnewton.jl")
7070
include("dfsane.jl")
7171
include("pseudotransient.jl")
72+
include("broyden.jl")
73+
include("klement.jl")
7274
include("jacobian.jl")
7375
include("ad.jl")
7476
include("default.jl")
7577

7678
import PrecompileTools
7779

78-
@static if VERSION >= v"1.10"
80+
@static if VERSION v"1.10-"
7981
PrecompileTools.@compile_workload begin
8082
for T in (Float32, Float64)
8183
prob = NonlinearProblem{false}((u, p) -> u .* u .- p, T(0.1), T(2))
8284

83-
precompile_algs = (NewtonRaphson(), TrustRegion(), LevenbergMarquardt())
85+
precompile_algs = (NewtonRaphson(), TrustRegion(), LevenbergMarquardt(),
86+
nothing)
8487

8588
for alg in precompile_algs
8689
solve(prob, alg, abstol = T(1e-2))
@@ -97,7 +100,8 @@ end
97100

98101
export RadiusUpdateSchemes
99102

100-
export NewtonRaphson, TrustRegion, LevenbergMarquardt, DFSane, GaussNewton, PseudoTransient
103+
export NewtonRaphson, TrustRegion, LevenbergMarquardt, DFSane, GaussNewton, PseudoTransient,
104+
GeneralBroyden, GeneralKlement
101105
export LeastSquaresOptimJL, FastLevenbergMarquardtJL
102106
export RobustMultiNewton, FastShortcutNonlinearPolyalg
103107

src/broyden.jl

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Sadly `Broyden` is taken up by SimpleNonlinearSolve.jl
2+
"""
3+
GeneralBroyden(max_resets)
4+
GeneralBroyden(; max_resets = 3)
5+
6+
An implementation of `Broyden` with support for caching!
7+
8+
## Arguments
9+
10+
- `max_resets`: the maximum number of resets to perform. Defaults to `3`.
11+
"""
12+
struct GeneralBroyden <: AbstractNewtonAlgorithm{false, Nothing}
13+
max_resets::Int
14+
end
15+
16+
GeneralBroyden(; max_resets = 3) = GeneralBroyden(max_resets)
17+
18+
@concrete mutable struct GeneralBroydenCache{iip} <: AbstractNonlinearSolveCache{iip}
19+
f
20+
alg
21+
u
22+
du
23+
fu
24+
fu2
25+
dfu
26+
p
27+
J⁻¹
28+
J⁻¹₂
29+
J⁻¹df
30+
force_stop::Bool
31+
resets::Int
32+
max_rests::Int
33+
maxiters::Int
34+
internalnorm
35+
retcode::ReturnCode.T
36+
abstol
37+
prob
38+
stats::NLStats
39+
end
40+
41+
get_fu(cache::GeneralBroydenCache) = cache.fu
42+
43+
function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg::GeneralBroyden, args...;
44+
alias_u0 = false, maxiters = 1000, abstol = 1e-6, internalnorm = DEFAULT_NORM,
45+
kwargs...) where {uType, iip}
46+
@unpack f, u0, p = prob
47+
u = alias_u0 ? u0 : deepcopy(u0)
48+
fu = evaluate_f(prob, u)
49+
J⁻¹ = convert(parameterless_type(_mutable(u)),
50+
Matrix{eltype(u)}(I, length(fu), length(u)))
51+
return GeneralBroydenCache{iip}(f, alg, u, _mutable_zero(u), fu, similar(fu),
52+
similar(fu), p, J⁻¹, similar(fu'), _mutable_zero(u), false, 0, alg.max_resets,
53+
maxiters, internalnorm, ReturnCode.Default, abstol, prob, NLStats(1, 0, 0, 0, 0))
54+
end
55+
56+
function perform_step!(cache::GeneralBroydenCache{true})
57+
@unpack f, p, du, fu, fu2, dfu, u, J⁻¹, J⁻¹df, J⁻¹₂ = cache
58+
T = eltype(u)
59+
60+
mul!(du, J⁻¹, -fu)
61+
u .+= du
62+
f(fu2, u, p)
63+
64+
cache.internalnorm(fu2) < cache.abstol && (cache.force_stop = true)
65+
cache.stats.nf += 1
66+
67+
cache.force_stop && return nothing
68+
69+
# Update the inverse jacobian
70+
dfu .= fu2 .- fu
71+
if cache.resets < cache.max_rests &&
72+
(all(x -> abs(x) 1e-12, du) || all(x -> abs(x) 1e-12, dfu))
73+
fill!(J⁻¹, 0)
74+
J⁻¹[diagind(J⁻¹)] .= T(1)
75+
cache.resets += 1
76+
else
77+
mul!(J⁻¹df, J⁻¹, dfu)
78+
mul!(J⁻¹₂, du', J⁻¹)
79+
du .= (du .- J⁻¹df) ./ (dot(du, J⁻¹df) .+ T(1e-5))
80+
mul!(J⁻¹, reshape(du, :, 1), J⁻¹₂, 1, 1)
81+
end
82+
fu .= fu2
83+
84+
return nothing
85+
end

src/default.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ end
162162
# FIXME: Broyden and Klement are type unstable
163163
# (upstream SimpleNonlinearSolve.jl issue)
164164
!iip ? :(Klement()) : nothing, # Klement not yet implemented for IIP
165-
!iip ? :(Broyden()) : nothing, # Broyden not yet implemented for IIP
165+
:(GeneralBroyden()),
166166
:(NewtonRaphson(; linsolve, precs, adkwargs...)),
167167
:(NewtonRaphson(; linsolve, precs, linesearch = BackTracking(), adkwargs...)),
168168
:(TrustRegion(; linsolve, precs, adkwargs...)),

src/klement.jl

Whitespace-only changes.

src/linesearch.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ function LineSearchCache(ls::LineSearch, f, u, p, fu1, IIP::Val{iip}) where {iip
9292
g₀ = _mutable_zero(u)
9393

9494
autodiff = if iip && (ls.autodiff isa AutoZygote || ls.autodiff isa AutoSparseZygote)
95-
@warn "Attempting to use Zygote.jl for linesearch on an in-place problem. Falling back to finite differencing."
95+
@warn "Attempting to use Zygote.jl for linesearch on an in-place problem. Falling \
96+
back to finite differencing."
9697
AutoFiniteDiff()
9798
else
9899
ls.autodiff

0 commit comments

Comments
 (0)