Skip to content

Commit

Permalink
Add unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
mpf committed Oct 6, 2024
1 parent 313cf41 commit 6c29ea8
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 16 deletions.
15 changes: 15 additions & 0 deletions src/JSOSolvers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@ Notably, you can access, and modify, the following:
- `stats.elapsed_time`: elapsed time in seconds.
"


"""
normM!(n, x, M, z)
Weighted norm of `x` with respect to `M`, i.e., `z = sqrt(x' * M * x)`. Uses `z` as workspace.
"""
function normM!(n, x, M, z)
if M === I
return nrm2(n, x)
else
mul!(z, M, x)
return (xz)
end
end

# Unconstrained solvers
include("lbfgs.jl")
include("trunk.jl")
Expand Down
19 changes: 3 additions & 16 deletions src/trunk.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ The keyword arguments may include
- `nm_itmax::Int = 25`: algorithm parameter.
- `verbose::Int = 0`: if > 0, display iteration information every `verbose` iteration.
- `subsolver_verbose::Int = 0`: if > 0, display iteration information every `subsolver_verbose` iteration of the subsolver.
- `M`: linear operator that models a Hermitian positive-definite matrix of size `n`; passed to Krylov subsolvers.
# Output
The returned value is a `GenericExecutionStats`, see `SolverCore.jl`.
Expand Down Expand Up @@ -129,20 +130,6 @@ end
return solve!(solver, nlp; x = x, kwargs...)
end

"""
normM!(n, x, M, z)
Weighted norm of `x` with respect to `M`, i.e., `z = sqrt(x' * M * x)`. Uses `z` as workspace.
"""
function normM!(x, M, z)
if M === I
return nrm2(n, x)
else
mul!(z, M, x)
return (xz)
end
end

function SolverCore.solve!(
solver::TrunkSolver{T, V},
nlp::AbstractNLPModel{T, V},
Expand Down Expand Up @@ -194,7 +181,7 @@ function SolverCore.solve!(
grad!(nlp, x, ∇f)
isa(nlp, QuasiNewtonModel) && (∇fn .= ∇f)
∇fNorm2 = norm(∇f)
∇fNormM = normM!(∇f, M, Hs)
∇fNormM = normM!(n, ∇f, M, Hs)
ϵ = atol + rtol * ∇fNorm2
tr = solver.tr
tr.radius = min(max(∇fNormM / 10, one(T)), T(100))
Expand Down Expand Up @@ -371,7 +358,7 @@ function SolverCore.solve!(
tr.good_grad = false
end
∇fNorm2 = nrm2(n, ∇f)
∇fNormM = normM!(∇f, M, Hs)
∇fNormM = normM!(n, ∇f, M, Hs)

set_objective!(stats, f)
set_time!(stats, time() - start_time)
Expand Down
19 changes: 19 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,22 @@ include("objgrad-on-tron.jl")
nls = ADNLSModel(x -> [100 * (x[2] - x[1]^2); x[1] - 1], [-1.2; 1.0], 2)
stats = tron(nls, max_radius = max_radius, increase_factor = increase_factor, callback = cb)
end

@testset "Preconditioner in Trunk" begin
x0 = [-1.2; 1.0]
nlp = ADNLPModel(x -> 100 * (x[2] - x[1]^2)^2 + (x[1] - 1)^2, x0)
DiagPrecon(x) = Diagonal(( [200 + 800 * x[1]^2 - 400 * x[2] 0.0;
0.0 200] ))

M = DiagPrecon(x0)
# implement `ldiv!` for `Diagonal` to avoid copying
function LinearAlgebra.ldiv!(y, M::Diagonal, x)
y .= M \ x
end
function callback(nlp, solver, stats)
M[:] = DiagPrecon(solver.x)
end
stats = trunk(nlp, callback=callback, M=M)
@test stats.status == :success

end

0 comments on commit 6c29ea8

Please sign in to comment.