11"""
2- SimpleLimitedMemoryBroyden(; threshold::Int = 27, linesearch = Val(false))
3- SimpleLimitedMemoryBroyden(; threshold::Val = Val(27), linesearch = Val(false))
2+ SimpleLimitedMemoryBroyden(; threshold::Union{Val, Int} = Val(27),
3+ linesearch = Val(false), alpha = nothing )
44
55A limited memory implementation of Broyden. This method applies the L-BFGS scheme to
66Broyden's method.
77
88If the threshold is larger than the problem size, then this method will use `SimpleBroyden`.
99
10- If `linesearch` is `Val(true)`, then we use the `LiFukushimaLineSearch` [1] line search else
11- no line search is used. For advanced customization of the line search, use the
12- [`LimitedMemoryBroyden`](@ref) algorithm in `NonlinearSolve.jl`.
10+ ### Keyword Arguments:
11+
12+ - `linesearch`: If `linesearch` is `Val(true)`, then we use the
13+ `LiFukushimaLineSearch` [1] line search else no line search is used. For advanced
14+ customization of the line search, use the [`LimitedMemoryBroyden`](@ref) algorithm in
15+ `NonlinearSolve.jl`.
16+ - `alpha`: Scale the initial jacobian initialization with `alpha`. If it is `nothing`, we
17+ will compute the scaling using `2 * norm(fu) / max(norm(u), true)`.
1318
1419### References
1520
1621[1] Li, Dong-Hui, and Masao Fukushima. "A derivative-free line search and global convergence
1722of Broyden-like method for nonlinear equations." Optimization methods and software 13.3
1823(2000): 181-201.
1924"""
20- struct SimpleLimitedMemoryBroyden{threshold, linesearch} < :
21- AbstractSimpleNonlinearSolveAlgorithm end
25+ @concrete struct SimpleLimitedMemoryBroyden{threshold, linesearch} < :
26+ AbstractSimpleNonlinearSolveAlgorithm
27+ alpha
28+ end
2229
2330__get_threshold (:: SimpleLimitedMemoryBroyden{threshold} ) where {threshold} = Val (threshold)
2431__use_linesearch (:: SimpleLimitedMemoryBroyden{Th, LS} ) where {Th, LS} = Val (LS)
2532
2633function SimpleLimitedMemoryBroyden (; threshold:: Union{Val, Int} = Val (27 ),
27- linesearch = Val (false ))
28- return SimpleLimitedMemoryBroyden {_unwrap_val(threshold), _unwrap_val(linesearch)} ()
34+ linesearch = Val (false ), alpha = nothing )
35+ return SimpleLimitedMemoryBroyden {_unwrap_val(threshold), _unwrap_val(linesearch)} (alpha )
2936end
3037
38+ # Don't resolve the `abstol` and `reltol` here
3139function SciMLBase. solve (prob:: NonlinearProblem{<:Union{<:Number, <:SArray}} ,
3240 alg:: SimpleLimitedMemoryBroyden , args... ; kwargs... )
33- # Don't resolve the `abstol` and `reltol` here
3441 return SciMLBase. __solve (prob, alg, args... ; kwargs... )
3542end
3643
@@ -133,8 +140,17 @@ function __static_solve(prob::NonlinearProblem{<:SArray}, alg::SimpleLimitedMemo
133140 ls_cache = __use_linesearch (alg) === Val (true ) ?
134141 LiFukushimaLineSearch ()(prob, fx, x) : nothing
135142
143+ T = promote_type (eltype (x), eltype (fx))
144+ if alg. alpha === nothing
145+ fx_norm = NONLINEARSOLVE_DEFAULT_NORM (fx)
146+ x_norm = NONLINEARSOLVE_DEFAULT_NORM (x)
147+ init_α = ifelse (fx_norm ≥ 1e-5 , max (x_norm, T (true )) / (2 * fx_norm), T (true ))
148+ else
149+ init_α = inv (alg. alpha)
150+ end
151+
136152 converged, res = __unrolled_lbroyden_initial_iterations (prob, xo, fo, δx, abstol, U, Vᵀ,
137- threshold, ls_cache)
153+ threshold, ls_cache, init_α )
138154
139155 converged &&
140156 return build_solution (prob, alg, res. x, res. fx; retcode = ReturnCode. Success)
@@ -150,16 +166,16 @@ function __static_solve(prob::NonlinearProblem{<:SArray}, alg::SimpleLimitedMemo
150166 maximum (abs, fx) ≤ abstol &&
151167 return build_solution (prob, alg, x, fx; retcode = ReturnCode. Success)
152168
153- vᵀ = _restructure (x, _rmatvec!! (U, Vᵀ, vec (δx)))
154- mvec = _restructure (x, _matvec!! (U, Vᵀ, vec (δf)))
169+ vᵀ = _restructure (x, _rmatvec!! (U, Vᵀ, vec (δx), init_α ))
170+ mvec = _restructure (x, _matvec!! (U, Vᵀ, vec (δf), init_α ))
155171
156172 d = dot (vᵀ, δf)
157173 δx = @. (δx - mvec) / d
158174
159175 U = Base. setindex (U, vec (δx), mod1 (i, _unwrap_val (threshold)))
160176 Vᵀ = Base. setindex (Vᵀ, vec (vᵀ), mod1 (i, _unwrap_val (threshold)))
161177
162- δx = - _restructure (fx, _matvec!! (U, Vᵀ, vec (fx)))
178+ δx = - _restructure (fx, _matvec!! (U, Vᵀ, vec (fx), init_α ))
163179
164180 xo = x
165181 fo = fx
@@ -169,7 +185,7 @@ function __static_solve(prob::NonlinearProblem{<:SArray}, alg::SimpleLimitedMemo
169185end
170186
171187@generated function __unrolled_lbroyden_initial_iterations (prob, xo, fo, δx, abstol, U,
172- Vᵀ, :: Val{threshold} , ls_cache) where {threshold}
188+ Vᵀ, :: Val{threshold} , ls_cache, init_α ) where {threshold}
173189 calls = []
174190 for i in 1 : threshold
175191 static_idx, static_idx_p1 = Val (i - 1 ), Val (i)
185201 _U = __first_n_getindex (U, $ (static_idx))
186202 _Vᵀ = __first_n_getindex (Vᵀ, $ (static_idx))
187203
188- vᵀ = _restructure (x, _rmatvec!! (_U, _Vᵀ, vec (δx)))
189- mvec = _restructure (x, _matvec!! (_U, _Vᵀ, vec (δf)))
204+ vᵀ = _restructure (x, _rmatvec!! (_U, _Vᵀ, vec (δx), init_α ))
205+ mvec = _restructure (x, _matvec!! (_U, _Vᵀ, vec (δf), init_α ))
190206
191207 d = dot (vᵀ, δf)
192208 δx = @. (δx - mvec) / d
196212
197213 _U = __first_n_getindex (U, $ (static_idx_p1))
198214 _Vᵀ = __first_n_getindex (Vᵀ, $ (static_idx_p1))
199- δx = - _restructure (fx, _matvec!! (_U, _Vᵀ, vec (fx)))
215+ δx = - _restructure (fx, _matvec!! (_U, _Vᵀ, vec (fx), init_α ))
200216
201217 xo = x
202218 fo = fx
@@ -226,8 +242,8 @@ function _rmatvec!!(y, xᵀU, U, Vᵀ, x)
226242 return y
227243end
228244
229- @inline _rmatvec!! (:: Nothing , Vᵀ, x) = - x
230- @inline _rmatvec!! (U, Vᵀ, x) = __mapTdot (__mapdot (x, U), Vᵀ) .- x
245+ @inline _rmatvec!! (:: Nothing , Vᵀ, x, init_α ) = - x .* init_α
246+ @inline _rmatvec!! (U, Vᵀ, x, init_α ) = __mapTdot (__mapdot (x, U), Vᵀ) .- x .* init_α
231247
232248function _matvec!! (y, Vᵀx, U, Vᵀ, x)
233249 # (-I + UVᵀ) × x
@@ -244,8 +260,8 @@ function _matvec!!(y, Vᵀx, U, Vᵀ, x)
244260 return y
245261end
246262
247- @inline _matvec!! (:: Nothing , Vᵀ, x) = - x
248- @inline _matvec!! (U, Vᵀ, x) = __mapTdot (__mapdot (x, Vᵀ), U) .- x
263+ @inline _matvec!! (:: Nothing , Vᵀ, x, init_α ) = - x .* init_α
264+ @inline _matvec!! (U, Vᵀ, x, init_α ) = __mapTdot (__mapdot (x, Vᵀ), U) .- x .* init_α
249265
250266function __mapdot (x:: SVector{S1} , Y:: SVector{S2, <:SVector{S1}} ) where {S1, S2}
251267 return map (Base. Fix1 (dot, x), Y)
0 commit comments