@@ -8,6 +8,7 @@ An implementation of `Broyden` with resetting and line search.
88## Arguments
99
1010 - `max_resets`: the maximum number of resets to perform. Defaults to `3`.
11+
1112 - `reset_tolerance`: the tolerance for the reset check. Defaults to
1213 `sqrt(eps(real(eltype(u))))`.
1314 - `linesearch`: the line search algorithm to use. Defaults to [`LineSearch()`](@ref),
@@ -22,29 +23,44 @@ An implementation of `Broyden` with resetting and line search.
2223 ignored if an analytical Jacobian is passed, as that will be used instead. Defaults to
2324 `nothing` which means that a default is selected according to the problem specification!
2425 Valid choices are types from ADTypes.jl. (Used if `init_jacobian = Val(:true_jacobian)`)
26+ - `update_rule`: Update Rule for the Jacobian. Choices are:
27+
28+ + `Val(:good_broyden)`: Good Broyden's Update Rule
29+ + `Val(:bad_broyden)`: Bad Broyden's Update Rule
2530"""
26- @concrete struct GeneralBroyden{IJ, CJ, AD} <: AbstractNewtonAlgorithm{CJ, AD}
31+ @concrete struct GeneralBroyden{IJ, UR, CJ, AD} <: AbstractNewtonAlgorithm{CJ, AD}
2732 ad:: AD
2833 max_resets:: Int
2934 reset_tolerance
3035 linesearch
3136end
3237
33- function set_ad (alg:: GeneralBroyden{IJ, CJ} , ad) where {IJ, CJ}
34- return GeneralBroyden {IJ, CJ} (ad, alg. max_resets, alg. reset_tolerance, alg. linesearch)
38+ function __alg_print_modifiers (:: GeneralBroyden{IJ, UR} ) where {IJ, UR}
39+ modifiers = String[]
40+ IJ != = :identity && push! (modifiers, " init_jacobian = :$(IJ) " )
41+ UR != = :good_broyden && push! (modifiers, " update_rule = :$(UR) " )
42+ return modifiers
3543end
3644
37- function GeneralBroyden (; max_resets = 3 , linesearch = nothing ,
38- reset_tolerance = nothing , init_jacobian:: Val = Val (:identity ),
39- autodiff = nothing )
45+ function set_ad (alg:: GeneralBroyden{IJ, UR, CJ} , ad) where {IJ, UR, CJ}
46+ return GeneralBroyden {IJ, UR, CJ} (ad, alg. max_resets, alg. reset_tolerance,
47+ alg. linesearch)
48+ end
49+
50+ function GeneralBroyden (; max_resets = 3 , linesearch = nothing , reset_tolerance = nothing ,
51+ init_jacobian:: Val = Val (:identity ), autodiff = nothing ,
52+ update_rule = Val (:good_broyden ))
53+ UR = _unwrap_val (update_rule)
54+ @assert UR ∈ (:good_broyden , :bad_broyden )
4055 IJ = _unwrap_val (init_jacobian)
4156 @assert IJ ∈ (:identity , :true_jacobian )
4257 linesearch = linesearch isa LineSearch ? linesearch : LineSearch (; method = linesearch)
4358 CJ = IJ === :true_jacobian
44- return GeneralBroyden {IJ, CJ} (autodiff, max_resets, reset_tolerance, linesearch)
59+ return GeneralBroyden {IJ, UR, CJ} (autodiff, max_resets, reset_tolerance, linesearch)
4560end
4661
47- @concrete mutable struct GeneralBroydenCache{iip, IJ} <: AbstractNonlinearSolveCache{iip}
62+ @concrete mutable struct GeneralBroydenCache{iip, IJ, UR} < :
63+ AbstractNonlinearSolveCache{iip}
4864 f
4965 alg
5066 u
7591 trace
7692end
7793
78- function SciMLBase. __init (prob:: NonlinearProblem{uType, iip} , alg_:: GeneralBroyden{IJ} ,
94+ function SciMLBase. __init (prob:: NonlinearProblem{uType, iip} , alg_:: GeneralBroyden{IJ, UR } ,
7995 args... ; alias_u0 = false , maxiters = 1000 , abstol = nothing , reltol = nothing ,
8096 termination_condition = nothing , internalnorm:: F = DEFAULT_NORM,
81- kwargs... ) where {uType, iip, F, IJ}
97+ kwargs... ) where {uType, iip, F, IJ, UR }
8298 @unpack f, u0, p = prob
8399 u = __maybe_unaliased (u0, alias_u0)
84100 fu = evaluate_f (prob, u)
@@ -109,14 +125,14 @@ function SciMLBase.__init(prob::NonlinearProblem{uType, iip}, alg_::GeneralBroyd
109125 trace = init_nonlinearsolve_trace (alg, u, fu, J⁻¹, du; uses_jac_inverse = Val (true ),
110126 kwargs... )
111127
112- return GeneralBroydenCache {iip, IJ} (f, alg, u, u_cache, du, fu, fu_cache, dfu, p, uf ,
113- J⁻¹, J⁻¹dfu, false , 0 , alg. max_resets, maxiters, internalnorm, ReturnCode . Default ,
114- abstol, reltol, reset_tolerance, reset_check, jac_cache, prob,
128+ return GeneralBroydenCache {iip, IJ, UR } (f, alg, u, u_cache, du, fu, fu_cache, dfu, p,
129+ uf, J⁻¹, J⁻¹dfu, false , 0 , alg. max_resets, maxiters, internalnorm,
130+ ReturnCode . Default, abstol, reltol, reset_tolerance, reset_check, jac_cache, prob,
115131 NLStats (1 , 0 , 0 , 0 , 0 ),
116132 init_linesearch_cache (alg. linesearch, f, u, p, fu, Val (iip)), tc_cache, trace)
117133end
118134
119- function perform_step! (cache:: GeneralBroydenCache{iip, IJ} ) where {iip, IJ}
135+ function perform_step! (cache:: GeneralBroydenCache{iip, IJ, UR } ) where {iip, IJ, UR }
120136 T = eltype (cache. u)
121137
122138 if IJ === :true_jacobian && cache. stats. nsteps == 0
@@ -152,10 +168,18 @@ function perform_step!(cache::GeneralBroydenCache{iip, IJ}) where {iip, IJ}
152168 else
153169 @bb cache. du .*= - 1
154170 @bb cache. J⁻¹dfu = cache. J⁻¹ × vec (cache. dfu)
155- @bb cache. u_cache = transpose (cache. J⁻¹) × vec (cache. du)
156- denom = dot (cache. du, cache. J⁻¹dfu)
157- @bb @. cache. du = (cache. du - cache. J⁻¹dfu) / ifelse (iszero (denom), T (1e-5 ), denom)
158- @bb cache. J⁻¹ += vec (cache. du) × transpose (_vec (cache. u_cache))
171+ if UR === :good_broyden
172+ @bb cache. u_cache = transpose (cache. J⁻¹) × vec (cache. du)
173+ denom = dot (cache. du, cache. J⁻¹dfu)
174+ @bb @. cache. du = (cache. du - cache. J⁻¹dfu) /
175+ ifelse (iszero (denom), T (1e-5 ), denom)
176+ @bb cache. J⁻¹ += vec (cache. du) × transpose (_vec (cache. u_cache))
177+ elseif UR === :bad_broyden
178+ dfu_norm = norm (cache. dfu)^ 2
179+ @bb @. cache. du = (cache. du - cache. J⁻¹dfu) /
180+ ifelse (iszero (dfu_norm), T (1e-5 ), dfu_norm)
181+ @bb cache. J⁻¹ += vec (cache. du) × transpose (_vec (cache. dfu))
182+ end
159183 end
160184
161185 @bb copyto! (cache. dfu, cache. fu)
0 commit comments