@@ -95,8 +95,10 @@ function SolverCore.solve!(
9595 stats:: GenericExecutionStats{T, V} ;
9696 callback = (args... ) -> nothing ,
9797 x:: V = reg_nls. model. meta. x0,
98+ nonlinear:: Bool = true ,
9899 atol:: T = √ eps (T),
99100 rtol:: T = √ eps (T),
101+ neg_tol:: T = zero (T),
100102 verbose:: Int = 0 ,
101103 max_iter:: Int = 10000 ,
102104 max_time:: Float64 = 30.0 ,
@@ -124,8 +126,7 @@ function SolverCore.solve!(
124126 Fkn = solver. Fkn
125127 Jk = solver. Jk
126128 ∇fk = solver.∇fk
127- JdFk = solver. JdFk
128- Jt_Fk = solver. Jt_Fk
129+ mν∇fk = solver. mν∇fk
129130 ψ = solver. ψ
130131 xkn = solver. xkn
131132 s = solver. s
@@ -162,8 +163,8 @@ function SolverCore.solve!(
162163 :xi => " √(ξ1/ν)" ,
163164 :normx => " ‖x‖" ,
164165 :norms => " ‖s‖" ,
165- :normB => " ‖J‖²" ,
166- :arrow => " R2N " ,
166+ :normJ => " ‖J‖²" ,
167+ :arrow => " LM " ,
167168 ),
168169 colsep = 1 ,
169170 )
@@ -174,7 +175,7 @@ function SolverCore.solve!(
174175
175176 residual! (nls, xk, Fk)
176177 Jk = jac_op_residual (nls, xk)
177- mul! (∇fk, Jk ' , Fk)
178+ jtprod_residual! (nls, xk , Fk, ∇fk )
178179 fk = dot (Fk, Fk) / 2
179180
180181 σmax, found_σ = opnorm (Jk)
@@ -184,11 +185,208 @@ function SolverCore.solve!(
184185
185186 @. mν∇fk = - ν * ∇fk
186187
187- φ1 (d) = let Fk = Fk, Jk = Jk,
188- d -> dot (Fk, Fk) / 2
188+ set_iter! (stats, 0 )
189+ start_time = time ()
190+ set_time! (stats, 0.0 )
191+ set_objective! (stats, fk + hk)
192+ set_solver_specific! (stats, :smooth_obj , fk)
193+ set_solver_specific! (stats, :nonsmooth_obj , hk)
194+
195+ φ1 = let Fk = Fk, ∇fk = ∇fk
196+ d -> dot (Fk, Fk) / 2 + dot (∇fk, d) # ∇fk = Jk^T Fk
197+ end
198+
199+ mk1 = let φ1 = φ1, ψ = ψ
200+ d -> φ1 (d) + ψ (d)
201+ end
202+
203+ mk = let ψ = ψ, solver = solver
204+ d -> obj (solver. subpb. model, d) + ψ (d)
205+ end
206+
207+ prox! (s, ψ, mν∇fk, ν)
208+ ξ1 = fk + hk - mk1 (s) + max (1 , abs (fk + hk)) * 10 * eps ()
209+ sqrt_ξ1_νInv = ξ1 ≥ 0 ? sqrt (ξ1 / ν) : sqrt (- ξ1 / ν)
210+ solved = (ξ1 < 0 && sqrt_ξ1_νInv ≤ neg_tol) || (ξ1 ≥ 0 && sqrt_ξ1_νInv ≤ atol)
211+ (ξ1 < 0 && sqrt_ξ1_νInv > neg_tol) &&
212+ error (" LM: prox-gradient step should produce a decrease but ξ1 = $(ξ1) " )
213+ atol += rtol * sqrt_ξ1_νInv # make stopping test absolute and relative
214+
215+ set_status! (
216+ stats,
217+ get_status (
218+ reg_nls,
219+ elapsed_time = stats. elapsed_time,
220+ iter = stats. iter,
221+ optimal = solved,
222+ improper = improper,
223+ max_eval = max_eval,
224+ max_time = max_time,
225+ max_iter = max_iter,
226+ ),
227+ )
228+
229+ callback (nls, solver, stats)
230+
231+ done = stats. status != :unknown
232+
233+ while ! done
234+
235+ sub_atol = stats. iter == 0 ? 1.0e-3 : min (sqrt_ξ1_νInv ^ (1.5 ), sqrt_ξ1_νInv * 1e-3 )
236+ solver. subpb. model. σ = σk
237+ isa (solver. subsolver, R2DHSolver) && (solver. subsolver. D. d[1 ] = 1 / ν)
238+ if isa (solver. subsolver, R2Solver) # FIXME
239+ solve! (
240+ solver. subsolver,
241+ solver. subpb,
242+ solver. substats,
243+ x = s,
244+ atol = sub_atol,
245+ ν = ν,
246+ )
247+ else
248+ solve! (
249+ solver. subsolver,
250+ solver. subpb,
251+ solver. substats,
252+ x = s,
253+ atol = sub_atol,
254+ σk = σk, # FIXME
255+ )
256+ end
257+
258+ s .= solver. substats. solution
259+
260+ xkn .= xk .+ s
261+ residual! (nls, xkn, Fkn)
262+ fkn = dot (Fkn, Fkn) / 2
263+ hkn = @views h (xkn[selected])
264+ mks = mk (s)
265+ ξ = fk + hk - mks + max (1 , abs (hk)) * 10 * eps ()
266+
267+ if (ξ ≤ 0 || isnan (ξ))
268+ error (" LM: failed to compute a step: ξ = $ξ " )
269+ end
270+
271+ Δobj = fk + hk - (fkn + hkn) + max (1 , abs (fk + hk)) * 10 * eps ()
272+ ρk = Δobj / ξ
273+
274+ verbose > 0 &&
275+ stats. iter % verbose == 0 &&
276+ @info log_row (
277+ Any[
278+ stats. iter,
279+ solver. substats. iter,
280+ fk,
281+ hk,
282+ sqrt_ξ1_νInv,
283+ ρk,
284+ σk,
285+ norm (xk),
286+ norm (s),
287+ 1 / ν,
288+ (η2 ≤ ρk < Inf ) ? " ↘" : (ρk < η1 ? " ↗" : " =" ),
289+ ],
290+ colsep = 1 ,
291+ )
292+
293+ if η1 ≤ ρk < Inf
294+ xk .= xkn
295+
296+ if has_bnds
297+ @. l_bound_m_x = l_bound - xk
298+ @. u_bound_m_x = u_bound - xk
299+ set_bounds! (ψ, l_bound_m_x, u_bound_m_x)
300+ end
301+
302+ # update functions
303+ Fk .= Fkn
304+ fk = fkn
305+ hk = hkn
306+
307+ # update gradient & Hessian
308+ shift! (ψ, xk)
309+ Jk = jac_op_residual (nls, xk)
310+ jtprod_residual! (nls, xk, Fk, ∇fk)
311+
312+ # update opnorm if not linear least squares
313+ if nonlinear == true
314+ σmax, found_σ = opnorm (Jk)
315+ found_σ || error (" operator norm computation failed" )
316+ end
317+ end
318+
319+ if η2 ≤ ρk < Inf
320+ σk = max (σk / γ, σmin)
321+ end
322+
323+ if ρk < η1 || ρk == Inf
324+ σk = σk * γ
325+ end
326+
327+ set_objective! (stats, fk + hk)
328+ set_solver_specific! (stats, :smooth_obj , fk)
329+ set_solver_specific! (stats, :nonsmooth_obj , hk)
330+ set_iter! (stats, stats. iter + 1 )
331+ set_time! (stats, time () - start_time)
332+
333+ ν = θ / (σmax^ 2 + σk) # ‖J'J + σₖ I‖ = ‖J‖² + σₖ
334+
335+ @. mν∇fk = - ν * ∇fk
336+ prox! (s, ψ, mν∇fk, ν)
337+ mks = mk1 (s)
338+
339+ ξ1 = fk + hk - mks + max (1 , abs (hk)) * 10 * eps ()
340+
341+ sqrt_ξ1_νInv = ξ1 ≥ 0 ? sqrt (ξ1 / ν) : sqrt (- ξ1 / ν)
342+ solved = (ξ1 < 0 && sqrt_ξ1_νInv ≤ neg_tol) || (ξ1 ≥ 0 && sqrt_ξ1_νInv ≤ atol)
343+
344+ (ξ1 < 0 && sqrt_ξ1_νInv > neg_tol) &&
345+ error (" LM: prox-gradient step should produce a decrease but ξ1 = $(ξ1) " )
346+
347+ set_status! (
348+ stats,
349+ get_status (
350+ reg_nls,
351+ elapsed_time = stats. elapsed_time,
352+ iter = stats. iter,
353+ optimal = solved,
354+ improper = improper,
355+ max_eval = max_eval,
356+ max_time = max_time,
357+ max_iter = max_iter,
358+ ),
359+ )
360+
361+ callback (nls, solver, stats)
362+
363+ done = stats. status != :unknown
364+
365+ end
366+
367+ if verbose > 0 && stats. status == :first_order
368+ @info log_row (
369+ Any[
370+ stats. iter,
371+ 0 ,
372+ fk,
373+ hk,
374+ sqrt_ξ1_νInv,
375+ ρk,
376+ σk,
377+ norm (xk),
378+ norm (s),
379+ 1 / ν,
380+ " " ,
381+ ],
382+ colsep = 1 ,
383+ )
384+ @info " LM: terminating with √(ξ1/ν) = $(sqrt_ξ1_νInv) "
189385 end
190386
191- return
387+ set_solution! (stats, xk)
388+ set_residuals! (stats, zero (T), sqrt_ξ1_νInv)
389+ return stats
192390end
193391
194392"""
@@ -388,9 +586,10 @@ function LM(
388586 subsolver_options. ν = ν
389587 subsolver_args = subsolver == R2DH ? (SpectralGradient (1 / ν, nls. meta. nvar),) : ()
390588 @debug " setting inner stopping tolerance to" subsolver_options. optTol
391- s, iter, _ = with_logger (subsolver_logger) do
392- subsolver (φ, ∇φ!, ψ, subsolver_args... , subsolver_options, s)
393- end
589+ # s, iter, _ = with_logger(subsolver_logger) do
590+ # subsolver_options.verbose = 1
591+ s, iter, _ = subsolver (φ, ∇φ!, ψ, subsolver_args... , subsolver_options, s)
592+ # end
394593 # restore initial subsolver_options here so that it is not modified if there is an error
395594 subsolver_options. ν = ν_subsolver
396595 subsolver_options. ϵa = ϵa_subsolver
0 commit comments