Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions src/AL_alg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,12 @@ If adopted, the Hessian is accessed as an abstract operator and need not be the

- `x::AbstractVector`: a primal initial guess (default: `reg_nlp.model.meta.x0`)
- `y::AbstractVector`: a dual initial guess (default: `reg_nlp.model.meta.y0`)
- `atol::T = √eps(T)`: absolute optimality tolerance;
- `atol::T = eps(T)^(1/3)`: absolute tolerance
- `diverging_iterates_tol::T = 1/eps(T)`: tolerance to detect divergence of the iterates (divergence occurs when the iterate norm exceeds the tolerance for `diverging_max_iter` consecutive iterations);
- `diverging_obj_tol::T = -1/eps(T)`: tolerance to detect unboundedness of the objective (unboundedness occurs when the objective value is less than the tolerance for `diverging_max_iter` consecutive iterations);
- `cviol_tol::T = 1/eps(T)`: tolerance to detect local infeasibility (local infeasibility occurs when ... [PLEASE COMPLETE] ...);
- `diverging_max_iter::Int = 5`: number of consecutive iterations used to detect divergence or unboundedness (see `diverging_iterates_tol` and `diverging_obj_tol`);
- `cviol_max_iter::Int = 5`: maximum number of iteration at which the regularisation parameter is increasing and the constraints are still violated;
- `ctol::T = atol`: absolute feasibility tolerance;
- `verbose::Int = 0`: if > 0, display iteration details every `verbose` iteration;
- `max_iter::Int = 10000`: maximum number of iterations;
Expand Down Expand Up @@ -209,7 +214,12 @@ function SolverCore.solve!(
callback = (args...) -> nothing,
x::V = reg_nlp.model.meta.x0,
y::V = reg_nlp.model.meta.y0,
atol::T = √eps(T),
atol::T = eps(T)^(1/3),
diverging_iterates_tol::T = 1/eps(T),
diverging_obj_tol::T = -1/eps(T),
cviol_tol::T = 1/eps(T),
diverging_max_iter::Int = 5,
cviol_max_iter::Int = 5,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main question is to find out if the criteria you implemented result in a lot of "false positives", i.e., problems that are falsely detected as (locally) infeasible.

verbose::Int = 0,
max_iter::Int = 10000,
max_time::Float64 = 30.0,
Expand All @@ -225,6 +235,9 @@ function SolverCore.solve!(
) where {T, V}
reset!(stats)

diverging_iter::Int = 0
cviol_iter::Int = 0

# Retrieve workspace
nlp = reg_nlp.model
h = reg_nlp.h
Expand Down Expand Up @@ -315,6 +328,8 @@ function SolverCore.solve!(
# objective
fx = obj(nlp, solver.x)
hx = @views h(solver.x[selected])
improper = (hx == -Inf)

objx = fx + hx
set_objective!(stats, objx)
set_solver_specific!(stats, :smooth_obj, fx)
Expand Down Expand Up @@ -345,19 +360,19 @@ function SolverCore.solve!(
set_time!(stats, time() - start_time)
set_status!(
stats,
SolverCore.get_status(
nlp,
get_status(
reg_nlp;
elapsed_time = stats.elapsed_time,
iter = stats.iter,
optimal = optimal,
infeasible = false,
parameter_too_large = false,
unbounded = false,
stalled = false,
exception = false,
improper = improper,
diverging_iter = diverging_iter,
cviol_iter = cviol_iter,
max_eval = max_eval,
max_time = max_time,
max_iter = max_iter,
diverging_max_iter = diverging_max_iter,
cviol_max_iter = cviol_max_iter,
),
)

Expand All @@ -372,6 +387,13 @@ function SolverCore.solve!(
if !done
if cviol > max(ctol, factor_primal_linear_improvement * cviol_old)
mu *= factor_penalty_up
if cviol > cviol_tol
cviol_iter += 1
end
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think cviol_iter should be reset to zero if cviol ≤ cviol_tol. We want the tolerance to be exceeded for a number of consecutive iterations, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, my mistake, this has been implemented in R2 and R2N but not in AL.

end
if (fx + hx < diverging_obj_tol) || (norm(solver.x) > diverging_iterates_tol)
mu *= factor_penalty_up
diverging_iter = diverging_iter + 1
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

end
update_μ!(solver.sub_problem.model, mu)
cviol_old = cviol
Expand Down
36 changes: 26 additions & 10 deletions src/R2N.jl
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,11 @@ For advanced usage, first define a solver "R2NSolver" to preallocate the memory

# Keyword arguments
- `x::V = nlp.meta.x0`: the initial guess;
- `atol::T = √eps(T)`: absolute tolerance;
- `rtol::T = √eps(T)`: relative tolerance;
- `atol::T = eps(T)^(1/3)`: absolute tolerance
- `diverging_iterates_tol::T = eps(T)^(-1)`: diverging tolerance for the norm of the iterates (the norm should be lower than the tolerance);
- `diverging_obj_tol::T = -eps(T)^(-1)`: diverging tolerance for the objective function (the objective function should be higher than the tolerance);
- `diverging_max_iter::Int = 5`: maximum number of iteration at which `diverging_obj_tol` or `diverging_iterates_tol` is violated;
- `rtol::T = eps(T)^(1/3)`: relative tolerance;
- `neg_tol::T = eps(T)^(1 / 4)`: negative tolerance;
- `max_eval::Int = -1`: maximum number of evaluation of the objective function (negative number means unlimited);
- `max_time::Float64 = 30.0`: maximum time limit in seconds;
Expand Down Expand Up @@ -216,8 +219,11 @@ function SolverCore.solve!(
qn_update_y!::Function = _qn_grad_update_y!,
qn_copy!::Function = _qn_grad_copy!,
x::V = reg_nlp.model.meta.x0,
atol::T = √eps(T),
rtol::T = √eps(T),
atol::T = eps(T)^(1/3),
diverging_iterates_tol::T = eps(T)^(-1),
diverging_obj_tol::T = -eps(T)^(-1),
diverging_max_iter::Int = 5,
rtol::T = eps(T)^(1/3),
neg_tol::T = eps(T)^(1 / 4),
verbose::Int = 0,
max_iter::Int = 10000,
Expand Down Expand Up @@ -299,6 +305,7 @@ function SolverCore.solve!(
local ξ1::T
local ρk::T = zero(T)
local prox_evals::Int = 0
local diverging_iter::Int = zero(Int)

fk = compute_obj ? obj(nlp, xk) : stats.solver_specific[:smooth_obj]
compute_grad && grad!(nlp, xk, ∇fk)
Expand Down Expand Up @@ -368,9 +375,11 @@ function SolverCore.solve!(
iter = stats.iter,
optimal = solved,
improper = improper,
diverging_iter = diverging_iter,
max_eval = max_eval,
max_time = max_time,
max_iter = max_iter,
diverging_max_iter = diverging_max_iter,
),
)

Expand Down Expand Up @@ -475,13 +484,18 @@ function SolverCore.solve!(
set_step_status!(stats, :accepted)
end

if η2 ≤ ρk < Inf
σk = max(σk/γ, σmin)
end

if ρk < η1 || ρk == Inf
if (fk + hk < diverging_obj_tol) || (norm(xk) > diverging_iterates_tol)
σk = σk * γ
set_step_status!(stats, :rejected)
diverging_iter = diverging_iter + 1
else
diverging_iter = 0
if η2 ≤ ρk < Inf
σk = max(σk / γ, σmin)
end
if ρk < η1 || ρk == Inf
σk = σk * γ
set_step_status!(stats, :rejected)
end
end

ν₁ = θ / (λmax + σk)
Expand Down Expand Up @@ -515,9 +529,11 @@ function SolverCore.solve!(
iter = stats.iter,
optimal = solved,
improper = improper,
diverging_iter = diverging_iter,
max_eval = max_eval,
max_time = max_time,
max_iter = max_iter,
diverging_max_iter = diverging_max_iter,
),
)

Expand Down
41 changes: 29 additions & 12 deletions src/R2_alg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,12 @@ For advanced usage, first define a solver "R2Solver" to preallocate the memory u

# Keyword arguments
- `x::V = nlp.meta.x0`: the initial guess;
- `atol::T = √eps(T)`: absolute tolerance;
- `rtol::T = √eps(T)`: relative tolerance;
- `neg_tol::T = eps(T)^(1 / 4)`: negative tolerance
- `atol::T = eps(T)^(1/3)`: absolute tolerance
- `diverging_iterates_tol::T = eps(T)^(-1)`: diverging tolerance for the norm of the iterates (the norm should be lower than the tolerance);
- `diverging_obj_tol::T = -eps(T)^(-1)`: diverging tolerance for the objective function (the objective function should be higher than the tolerance);
- `diverging_max_iter::Int = 5`: maximum number of iteration at which `diverging_obj_tol` or `diverging_iterates_tol` is violated;
- `rtol::T = eps(T)^(1/3)`: relative tolerance;
- `neg_tol::T = eps(T)^(1 / 4)`: negative tolerance;
- `max_eval::Int = -1`: maximum number of evaluation of the objective function (negative number means unlimited);
- `max_time::Float64 = 30.0`: maximum time limit in seconds;
- `max_iter::Int = 10000`: maximum number of iterations;
Expand Down Expand Up @@ -313,8 +316,11 @@ function SolverCore.solve!(
stats::GenericExecutionStats{T, V};
callback = (args...) -> nothing,
x::V = reg_nlp.model.meta.x0,
atol::T = √eps(T),
rtol::T = √eps(T),
atol::T = eps(T)^(1/3),
diverging_iterates_tol::T = eps(T)^(-1),
diverging_obj_tol::T = -eps(T)^(-1),
diverging_max_iter::Int = 5,
rtol::T = eps(T)^(1/3),
neg_tol::T = eps(T)^(1 / 4),
verbose::Int = 0,
max_iter::Int = 10000,
Expand Down Expand Up @@ -386,6 +392,7 @@ function SolverCore.solve!(

local ξ::T
local ρk::T = zero(T)
local diverging_iter::Int = zero(Int)
σk = max(1 / ν, σmin)
ν = 1 / σk
sqrt_ξ_νInv = one(T)
Expand Down Expand Up @@ -420,14 +427,16 @@ function SolverCore.solve!(
set_status!(
stats,
get_status(
reg_nlp,
reg_nlp;
elapsed_time = stats.elapsed_time,
iter = stats.iter,
optimal = solved,
improper = improper,
diverging_iter = diverging_iter,
max_eval = max_eval,
max_time = max_time,
max_iter = max_iter,
diverging_max_iter = diverging_max_iter,
),
)

Expand Down Expand Up @@ -476,12 +485,18 @@ function SolverCore.solve!(
set_step_status!(stats, :accepted)
end

if η2 ≤ ρk < Inf
σk = max(σk / γ, σmin)
end
if ρk < η1 || ρk == Inf
if (fk + hk < diverging_obj_tol) || (norm(xk) > diverging_iterates_tol)
σk = σk * γ
set_step_status!(stats, :rejected)
diverging_iter = diverging_iter + 1
else
diverging_iter = 0
if η2 ≤ ρk < Inf
σk = max(σk / γ, σmin)
end
if ρk < η1 || ρk == Inf
σk = σk * γ
set_step_status!(stats, :rejected)
end
end

ν = 1 / σk
Expand All @@ -506,14 +521,16 @@ function SolverCore.solve!(
set_status!(
stats,
get_status(
reg_nlp,
reg_nlp;
elapsed_time = stats.elapsed_time,
iter = stats.iter,
optimal = solved,
improper = improper,
diverging_iter = diverging_iter,
max_eval = max_eval,
max_time = max_time,
max_iter = max_iter,
diverging_max_iter = diverging_max_iter,
),
)

Expand Down
8 changes: 8 additions & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,13 @@ function get_status(
iter = 0,
optimal = false,
improper = false,
diverging_iter = 0,
cviol_iter = 0,
max_eval = Inf,
max_time = Inf,
max_iter = Inf,
diverging_max_iter = Inf,
cviol_max_iter = Inf,
) where {M <: AbstractRegularizedNLPModel}
if optimal
:first_order
Expand All @@ -156,6 +160,10 @@ function get_status(
:max_time
elseif neval_obj(reg_nlp.model) >= max_eval && max_eval >= 0
:max_eval
elseif diverging_max_iter < diverging_iter
:unbounded
elseif cviol_max_iter < cviol_iter
:infeasible
else
:unknown
end
Expand Down