@@ -29,8 +29,8 @@ mutable struct TRSolver{
2929end
3030
3131function TRSolver (
32- reg_nlp:: AbstractRegularizedNLPModel{T, V} ,
33- χ:: X ;
32+ reg_nlp:: AbstractRegularizedNLPModel{T, V} ;
33+ χ:: X = NormLinf ( one (T)),
3434 subsolver = R2Solver
3535) where {T, V, X}
3636 x0 = reg_nlp. model. meta. x0
@@ -138,245 +138,40 @@ function TR(
138138 subsolver = R2,
139139 subsolver_options = ROSolverOptions (ϵa = options. ϵa),
140140 selected:: AbstractVector{<:Integer} = 1 : (f. meta. nvar),
141+ kwargs...
141142) where {H, X, R}
142- start_time = time ()
143- elapsed_time = 0.0
144- # initialize passed options
145- ϵ = options. ϵa
146- ϵ_subsolver = subsolver_options. ϵa
147- ϵr = options. ϵr
148- Δk = options. Δk
149- verbose = options. verbose
150- maxIter = options. maxIter
151- maxTime = options. maxTime
152- η1 = options. η1
153- η2 = options. η2
154- γ = options. γ
155- α = options. α
156- θ = options. θ
157- β = options. β
158-
159- # store initial values of the subsolver_options fields that will be modified
160- ν_subsolver = subsolver_options. ν
161- ϵa_subsolver = subsolver_options. ϵa
162- Δk_subsolver = subsolver_options. Δk
163-
164- local l_bound, u_bound
165- if has_bounds (f) || subsolver == TRDH
166- l_bound = f. meta. lvar
167- u_bound = f. meta. uvar
168- end
169-
170- if verbose == 0
171- ptf = Inf
172- elseif verbose == 1
173- ptf = round (maxIter / 10 )
174- elseif verbose == 2
175- ptf = round (maxIter / 100 )
176- else
177- ptf = 1
178- end
179-
180- # initialize parameters
181- xk = copy (x0)
182- hk = h (xk[selected])
183- if hk == Inf
184- verbose > 0 && @info " TR: finding initial guess where nonsmooth term is finite"
185- prox! (xk, h, x0, one (eltype (x0)))
186- hk = h (xk[selected])
187- hk < Inf || error (" prox computation must be erroneous" )
188- verbose > 0 && @debug " TR: found point where h has value" hk
189- end
190- hk == - Inf && error (" nonsmooth term is not proper" )
191-
192- xkn = similar (xk)
193- s = zero (xk)
194- ψ =
195- (has_bounds (f) || subsolver == TRDH) ?
196- shifted (h, xk, max .(- Δk, l_bound - xk), min .(Δk, u_bound - xk), selected) :
197- shifted (h, xk, Δk, χ)
198-
199- Fobj_hist = zeros (maxIter)
200- Hobj_hist = zeros (maxIter)
201- Complex_hist = zeros (Int, maxIter)
202- if verbose > 0
203- # ! format: off
204- @info @sprintf " %6s %8s %8s %8s %7s %7s %8s %7s %7s %7s %7s %1s" " outer" " inner" " f(x)" " h(x)" " √(ξ1/ν)" " √ξ" " ρ" " Δ" " ‖x‖" " ‖s‖" " ‖Bₖ‖" " TR"
205- # ! format: on
206- end
207-
208- local ξ1
209- k = 0
210-
211- fk = obj (f, xk)
212- ∇fk = grad (f, xk)
213- ∇fk⁻ = copy (∇fk)
214-
215- quasiNewtTest = isa (f, QuasiNewtonModel)
216- Bk = hess_op (f, xk)
217-
218- λmax, found_λ = opnorm (Bk)
219- found_λ || error (" operator norm computation failed" )
220- α⁻¹Δ⁻¹ = 1 / (α * Δk)
221- ν = 1 / (α⁻¹Δ⁻¹ + λmax * (α⁻¹Δ⁻¹ + 1 ))
222- sqrt_ξ1_νInv = one (R)
223-
224- optimal = false
225- tired = k ≥ maxIter || elapsed_time > maxTime
226-
227- while ! (optimal || tired)
228- k = k + 1
229- elapsed_time = time () - start_time
230- Fobj_hist[k] = fk
231- Hobj_hist[k] = hk
232-
233- # model for first prox-gradient step and ξ1
234- φ1 (d) = ∇fk' * d
235- mk1 (d) = φ1 (d) + ψ (d)
236-
237- # model for subsequent prox-gradient steps and ξ
238- φ (d) = (d' * (Bk * d)) / 2 + ∇fk' * d
239-
240- ∇φ! (g, d) = begin
241- mul! (g, Bk, d)
242- g .+ = ∇fk
243- g
244- end
245-
246- mk (d) = φ (d) + ψ (d)
247-
248- # Take first proximal gradient step s1 and see if current xk is nearly stationary.
249- # s1 minimizes φ1(s) + ‖s‖² / 2 / ν + ψ(s) ⟺ s1 ∈ prox{νψ}(-ν∇φ1(0)).
250- prox! (s, ψ, - ν * ∇fk, ν)
251- ξ1 = hk - mk1 (s) + max (1 , abs (hk)) * 10 * eps ()
252- ξ1 > 0 || error (" TR: first prox-gradient step should produce a decrease but ξ1 = $(ξ1) " )
253- sqrt_ξ1_νInv = sqrt (ξ1 / ν)
254-
255- if ξ1 ≥ 0 && k == 1
256- ϵ_increment = ϵr * sqrt_ξ1_νInv
257- ϵ += ϵ_increment # make stopping test absolute and relative
258- ϵ_subsolver += ϵ_increment
259- end
260-
261- if sqrt_ξ1_νInv < ϵ
262- # the current xk is approximately first-order stationary
263- optimal = true
264- continue
265- end
266-
267- subsolver_options. ϵa = k == 2 ? 1.0e-5 : max (ϵ_subsolver, min (1e-2 , sqrt_ξ1_νInv))
268- ∆_effective = min (β * χ (s), Δk)
269- (has_bounds (f) || subsolver == TRDH) ?
270- set_bounds! (ψ, max .(- ∆_effective, l_bound - xk), min .(∆_effective, u_bound - xk)) :
271- set_radius! (ψ, ∆_effective)
272- subsolver_options. Δk = ∆_effective / 10
273- subsolver_options. ν = ν
274- subsolver_args = subsolver == TRDH ? (SpectralGradient (1 / ν, f. meta. nvar),) : ()
275-
276- stats = subsolver (φ, ∇φ!, ψ, subsolver_args... , subsolver_options, s)
277-
278- s = stats. solution
279- iter = stats. iter
280-
281- # restore initial values of subsolver_options here so that it is not modified
282- # if there is an error
283- subsolver_options. ν = ν_subsolver
284- subsolver_options. ϵa = ϵa_subsolver
285- subsolver_options. Δk = Δk_subsolver
286-
287- Complex_hist[k] = 1
288-
289- sNorm = χ (s)
290- xkn .= xk .+ s
291- fkn = obj (f, xkn)
292- hkn = h (xkn[selected])
293- hkn == - Inf && error (" nonsmooth term is not proper" )
294-
295- Δobj = fk + hk - (fkn + hkn) + max (1 , abs (fk + hk)) * 10 * eps ()
296- ξ = hk - mk (s) + max (1 , abs (hk)) * 10 * eps ()
297-
298- if (ξ ≤ 0 || isnan (ξ))
299- error (" TR: failed to compute a step: ξ = $ξ " )
300- end
301-
302- ρk = Δobj / ξ
303-
304- TR_stat = (η2 ≤ ρk < Inf ) ? " ↗" : (ρk < η1 ? " ↘" : " =" )
305-
306- if (verbose > 0 ) && (k % ptf == 0 )
307- # ! format: off
308- @info @sprintf " %6d %8d %8.1e %8.1e %7.1e %7.1e %8.1e %7.1e %7.1e %7.1e %7.1e %1s" k iter fk hk sqrt_ξ1_νInv sqrt (ξ) ρk ∆_effective χ (xk) sNorm λmax TR_stat
309- # ! format: on
310- end
311-
312- if η2 ≤ ρk < Inf
313- Δk = max (Δk, γ * sNorm)
314- ! (has_bounds (f) || subsolver == TRDH) && set_radius! (ψ, Δk)
315- end
316-
317- if η1 ≤ ρk < Inf
318- xk .= xkn
319- (has_bounds (f) || subsolver == TRDH) &&
320- set_bounds! (ψ, max .(- Δk, l_bound - xk), min .(Δk, u_bound - xk))
321-
322- # update functions
323- fk = fkn
324- hk = hkn
325- shift! (ψ, xk)
326- ∇fk = grad (f, xk)
327- # grad!(f, xk, ∇fk)
328- if quasiNewtTest
329- push! (f, s, ∇fk - ∇fk⁻)
330- end
331- Bk = hess_op (f, xk)
332- λmax, found_λ = opnorm (Bk)
333- found_λ || error (" operator norm computation failed" )
334- ∇fk⁻ .= ∇fk
335- end
336-
337- if ρk < η1 || ρk == Inf
338- Δk = Δk / 2
339- (has_bounds (f) || subsolver == TRDH) ?
340- set_bounds! (ψ, max .(- Δk, l_bound - xk), min .(Δk, u_bound - xk)) : set_radius! (ψ, Δk)
341- end
342- α⁻¹Δ⁻¹ = 1 / (α * Δk)
343- ν = 1 / (α⁻¹Δ⁻¹ + λmax * (α⁻¹Δ⁻¹ + 1 ))
344- tired = k ≥ maxIter || elapsed_time > maxTime
345- end
346-
347- if verbose > 0
348- if k == 1
349- @info @sprintf " %6d %8s %8.1e %8.1e" k " " fk hk
350- elseif optimal
351- # ! format: off
352- @info @sprintf " %6d %8d %8.1e %8.1e %7.1e %7.1e %8s %7.1e %7.1e %7.1e %7.1e" k 1 fk hk sqrt_ξ1_νInv sqrt (ξ1) " " Δk χ (xk) χ (s) λmax
353- # ! format: on
354- @info " TR: terminating with √(ξ1/ν) = $(sqrt_ξ1_νInv) "
355- end
356- end
357-
358- status = if optimal
359- :first_order
360- elseif elapsed_time > maxTime
361- :max_time
362- elseif tired
363- :max_iter
364- else
365- :exception
366- end
143+ reg_nlp = RegularizedNLPModel (f, h, selected)
144+ stats = TR (
145+ reg_nlp;
146+ x = x0,
147+ atol = options. ϵa,
148+ sub_atol = subsolver_options. ϵa,
149+ rtol = options. ϵr,
150+ neg_tol = options. neg_tol,
151+ verbose = options. verbose,
152+ max_iter = options. maxIter,
153+ max_time = options. maxTime,
154+ Δk = options. Δk,
155+ η1 = options. η1,
156+ η2 = options. η2,
157+ γ = options. γ,
158+ α = options. α,
159+ β = options. β,
160+ kwargs...
161+ )
162+ return stats
163+ end
367164
368- stats = GenericExecutionStats (f)
369- set_status! (stats, status)
370- set_solution! (stats, xk)
371- set_objective! (stats, fk + hk)
372- set_residuals! (stats, zero (eltype (xk)), sqrt_ξ1_νInv)
373- set_iter! (stats, k)
374- set_time! (stats, elapsed_time)
375- set_solver_specific! (stats, :radius , Δk)
376- set_solver_specific! (stats, :Fhist , Fobj_hist[1 : k])
377- set_solver_specific! (stats, :Hhist , Hobj_hist[1 : k])
378- set_solver_specific! (stats, :NonSmooth , h)
379- set_solver_specific! (stats, :SubsolverCounter , Complex_hist[1 : k])
165+ function TR (
166+ reg_nlp:: AbstractRegularizedNLPModel{T, V} ;
167+ kwargs...
168+ ) where {T, V}
169+ kwargs_dict = Dict (kwargs... )
170+ subsolver = pop! (kwargs_dict, :subsolver , R2Solver)
171+ χ = pop! (kwargs_dict, :χ , NormLinf (one (T)))
172+ solver = TRSolver (reg_nlp, subsolver = subsolver, χ = χ)
173+ stats = RegularizedExecutionStats (reg_nlp)
174+ solve! (solver, reg_nlp, stats; kwargs_dict... )
380175 return stats
381176end
382177
@@ -394,7 +189,6 @@ function SolverCore.solve!(
394189 max_iter:: Int = 10000 ,
395190 max_time:: Float64 = 30.0 ,
396191 max_eval:: Int = - 1 ,
397- reduce_TR:: Bool = true ,
398192 Δk:: T = T (1 ),
399193 η1:: T = √√ eps (T),
400194 η2:: T = T (0.9 ),
0 commit comments