@@ -26,7 +26,15 @@ function LineSearch(; method = Static(), autodiff = AutoFiniteDiff(), alpha = tr
26
26
return LineSearch (method, autodiff, alpha)
27
27
end
28
28
29
- @concrete mutable struct LineSearchCache
29
+ @inline function init_linesearch_cache (ls:: LineSearch , args... )
30
+ return init_linesearch_cache (ls. method, ls, args... )
31
+ end
32
+
33
+ # LineSearches.jl doesn't have a supertype so default to that
34
+ init_linesearch_cache (_, ls, f, u, p, fu, iip) = LineSearchesJLCache (ls, f, u, p, fu, iip)
35
+
36
+ # Wrapper over LineSearches.jl algorithms
37
+ @concrete mutable struct LineSearchesJLCache
30
38
f
31
39
ϕ
32
40
dϕ
35
43
ls
36
44
end
37
45
38
- function LineSearchCache (ls:: LineSearch , f, u:: Number , p, _, :: Val{false} )
46
+ function LineSearchesJLCache (ls:: LineSearch , f, u:: Number , p, _, :: Val{false} )
39
47
eval_f (u, du, α) = eval_f (u - α * du)
40
48
eval_f (u) = f (u, p)
41
49
42
- ls. method isa Static && return LineSearchCache (eval_f, nothing , nothing , nothing ,
50
+ ls. method isa Static && return LineSearchesJLCache (eval_f, nothing , nothing , nothing ,
43
51
convert (typeof (u), ls. α), ls)
44
52
45
53
g (u, fu) = last (value_derivative (Base. Fix2 (f, p), u)) * fu
@@ -73,11 +81,11 @@ function LineSearchCache(ls::LineSearch, f, u::Number, p, _, ::Val{false})
73
81
return ϕdϕ_internal
74
82
end
75
83
76
- return LineSearchCache (eval_f, ϕ, dϕ, ϕdϕ, convert (eltype (u), ls. α), ls)
84
+ return LineSearchesJLCache (eval_f, ϕ, dϕ, ϕdϕ, convert (eltype (u), ls. α), ls)
77
85
end
78
86
79
- function LineSearchCache (ls:: LineSearch , f, u, p, fu1, IIP:: Val{iip} ) where {iip}
80
- fu = iip ? fu1 : nothing
87
+ function LineSearchesJLCache (ls:: LineSearch , f, u, p, fu1, IIP:: Val{iip} ) where {iip}
88
+ fu = iip ? deepcopy ( fu1) : nothing
81
89
u_ = _mutable_zero (u)
82
90
83
91
function eval_f (u, du, α)
@@ -86,7 +94,7 @@ function LineSearchCache(ls::LineSearch, f, u, p, fu1, IIP::Val{iip}) where {iip
86
94
end
87
95
eval_f (u) = evaluate_f (f, u, p, IIP; fu)
88
96
89
- ls. method isa Static && return LineSearchCache (eval_f, nothing , nothing , nothing ,
97
+ ls. method isa Static && return LineSearchesJLCache (eval_f, nothing , nothing , nothing ,
90
98
convert (eltype (u), ls. α), ls)
91
99
92
100
g₀ = _mutable_zero (u)
@@ -138,10 +146,10 @@ function LineSearchCache(ls::LineSearch, f, u, p, fu1, IIP::Val{iip}) where {iip
138
146
return ϕdϕ_internal
139
147
end
140
148
141
- return LineSearchCache (eval_f, ϕ, dϕ, ϕdϕ, convert (eltype (u), ls. α), ls)
149
+ return LineSearchesJLCache (eval_f, ϕ, dϕ, ϕdϕ, convert (eltype (u), ls. α), ls)
142
150
end
143
151
144
- function perform_linesearch! (cache:: LineSearchCache , u, du)
152
+ function perform_linesearch! (cache:: LineSearchesJLCache , u, du)
145
153
cache. ls. method isa Static && return cache. α
146
154
147
155
ϕ = cache. ϕ (u, du)
@@ -155,3 +163,120 @@ function perform_linesearch!(cache::LineSearchCache, u, du)
155
163
156
164
return first (cache. ls. method (ϕ, cache. dϕ (u, du), cache. ϕdϕ (u, du), cache. α, ϕ₀, dϕ₀))
157
165
end
166
+
167
+ """
168
+ LiFukushimaLineSearch(; lambda_0 = 1.0, beta = 0.5, sigma_1 = 0.001,
169
+ eta = 0.1, nan_max_iter = 5, maxiters = 50)
170
+
171
+ A derivative-free line search and global convergence of Broyden-like method for nonlinear
172
+ equations by Dong-Hui Li & Masao Fukushima. For more details see
173
+ https://doi.org/10.1080/10556780008805782
174
+ """
175
+ struct LiFukushimaLineSearch{T} <: AbstractNonlinearSolveLineSearchAlgorithm
176
+ λ₀:: T
177
+ β:: T
178
+ σ₁:: T
179
+ σ₂:: T
180
+ η:: T
181
+ ρ:: T
182
+ nan_max_iter:: Int
183
+ maxiters:: Int
184
+ end
185
+
186
+ function LiFukushimaLineSearch (; lambda_0 = 1.0 , beta = 0.1 , sigma_1 = 0.001 ,
187
+ sigma_2 = 0.001 , eta = 0.1 , rho = 0.9 , nan_max_iter = 5 , maxiters = 50 )
188
+ T = promote_type (typeof (lambda_0), typeof (beta), typeof (sigma_1), typeof (eta),
189
+ typeof (rho), typeof (sigma_2))
190
+ return LiFukushimaLineSearch {T} (lambda_0, beta, sigma_1, sigma_2, eta, rho,
191
+ nan_max_iter, maxiters)
192
+ end
193
+
194
+ @concrete mutable struct LiFukushimaLineSearchCache{iip}
195
+ f
196
+ p
197
+ u_cache
198
+ fu_cache
199
+ alg
200
+ α
201
+ end
202
+
203
+ function init_linesearch_cache (alg:: LiFukushimaLineSearch , ls:: LineSearch , f, _u, p, _fu,
204
+ :: Val{iip} ) where {iip}
205
+ fu = iip ? deepcopy (_fu) : nothing
206
+ u = iip ? deepcopy (_u) : nothing
207
+ return LiFukushimaLineSearchCache {iip} (f, p, u, fu, alg, ls. α)
208
+ end
209
+
210
+ function perform_linesearch! (cache:: LiFukushimaLineSearchCache{iip} , u, du) where {iip}
211
+ (; β, σ₁, σ₂, η, λ₀, ρ, nan_max_iter, maxiters) = cache. alg
212
+ λ₂ = λ₀
213
+ λ₁ = λ₂
214
+
215
+ if iip
216
+ cache. f (cache. fu_cache, u, cache. p)
217
+ fx_norm = norm (cache. fu_cache, 2 )
218
+ else
219
+ fx_norm = norm (cache. f (u, cache. p), 2 )
220
+ end
221
+
222
+ # Non-Blocking exit if the norm is NaN or Inf
223
+ ! isfinite (fx_norm) && return cache. α
224
+
225
+ # Early Terminate based on Eq. 2.7
226
+ if iip
227
+ cache. u_cache .= u .+ du
228
+ cache. f (cache. fu_cache, cache. u_cache, cache. p)
229
+ fxλ_norm = norm (cache. fu_cache, 2 )
230
+ else
231
+ fxλ_norm = norm (cache. f (u .+ du, cache. p), 2 )
232
+ end
233
+
234
+ fxλ_norm ≤ ρ * fx_norm - σ₂ * norm (du, 2 )^ 2 && return cache. α
235
+
236
+ if iip
237
+ cache. u_cache .= u .+ λ₂ .* du
238
+ cache. f (cache. fu_cache, cache. u_cache, cache. p)
239
+ fxλp_norm = norm (cache. fu_cache, 2 )
240
+ else
241
+ fxλp_norm = norm (cache. f (u .+ λ₂ .* du, cache. p), 2 )
242
+ end
243
+
244
+ if ! isfinite (fxλp_norm)
245
+ # Backtrack a finite number of steps
246
+ nan_converged = false
247
+ for _ in 1 : nan_max_iter
248
+ λ₁, λ₂ = λ₂, β * λ₂
249
+
250
+ if iip
251
+ cache. u_cache .= u .+ λ₂ .* du
252
+ cache. f (cache. fu_cache, cache. u_cache, cache. p)
253
+ fxλp_norm = norm (cache. fu_cache, 2 )
254
+ else
255
+ fxλp_norm = norm (cache. f (u .+ λ₂ .* du, cache. p), 2 )
256
+ end
257
+
258
+ nan_converged = isfinite (fxλp_norm)
259
+ nan_converged && break
260
+ end
261
+
262
+ # Non-Blocking exit if the norm is still NaN or Inf
263
+ ! nan_converged && return cache. α
264
+ end
265
+
266
+ for _ in 1 : maxiters
267
+ if iip
268
+ cache. u_cache .= u .+ λ₂ .* du
269
+ cache. f (cache. fu_cache, cache. u_cache, cache. p)
270
+ fxλp_norm = norm (cache. fu_cache, 2 )
271
+ else
272
+ fxλp_norm = norm (cache. f (u .+ λ₂ .* du, cache. p), 2 )
273
+ end
274
+
275
+ converged = fxλp_norm ≤ (1 + η) * fx_norm - σ₁ * λ₂^ 2 * norm (du, 2 )^ 2
276
+
277
+ converged && break
278
+ λ₁, λ₂ = λ₂, β * λ₂
279
+ end
280
+
281
+ return λ₂
282
+ end
0 commit comments