Skip to content

Commit

Permalink
Merge pull request #22 from vepiteski/gen-counters
Browse files Browse the repository at this point in the history
Generalize counters
  • Loading branch information
tmigot committed May 2, 2021
2 parents 28cb724 + adc3306 commit ea41e74
Show file tree
Hide file tree
Showing 15 changed files with 80 additions and 92 deletions.
3 changes: 3 additions & 0 deletions docs/src/api.md
Expand Up @@ -38,6 +38,9 @@ Stopping.update_and_stop!
Stopping.reinit!
Stopping.fill_in!
Stopping.status
Stopping.init_max_counters
Stopping.init_max_counters_NLS
Stopping.init_max_counters_linear_operators
```

## Non-linear admissibility functions
Expand Down
4 changes: 2 additions & 2 deletions docs/src/howtostop-nlp.md
Expand Up @@ -81,9 +81,9 @@ evaluations:
@test stop_nlp.max_cntrs[:neval_grad] == 20000
```

Limit can be set using \_init_max_counters function:
Limit can be set using init_max_counters function:
```
stop_nlp.max_cntrs = Stopping._init_max_counters(obj = 3, grad = 0, hess = 0)
stop_nlp.max_cntrs = init_max_counters(obj = 3, grad = 0, hess = 0)
@test stop_nlp.max_cntrs[:neval_obj] == 3
@test stop_nlp.max_cntrs[:neval_grad] == 0
Expand Down
4 changes: 2 additions & 2 deletions docs/src/lastopping.md
Expand Up @@ -22,11 +22,11 @@ x0 = zeros(n)
la_stop = LAStopping(A, b, GenericState(x0),
max_iter = 150000,
rtol = 1e-6,
max_cntrs = Stopping._init_max_counters_NLS(residual = 150000))
max_cntrs = init_max_counters_NLS(residual = 150000))
#2) for a linear operator:
op_stop = LAStopping(LinearSystem(LinearOperator(A), b),
GenericState(x0),
max_iter = 150000,
rtol = 1e-6,
max_cntrs = Stopping._init_max_counters_linear_operators(nprod = 150000))
max_cntrs = init_max_counters_linear_operators(nprod = 150000))
```
2 changes: 1 addition & 1 deletion docs/src/nlpstopping.md
Expand Up @@ -10,7 +10,7 @@ The Stopping-structure can be adapted to any problem solved by iterative methods
```julia
nlp = ADNLPModel(x->sum(x.^2), zeros(5))
nlp_at_x = NLPAtX(zeros(5))
meta = StoppingMeta(max_cntrs = _init_max_counters())
meta = StoppingMeta(max_cntrs = init_max_counters())
stp = NLPStopping(pb, meta, state)
```

Expand Down
2 changes: 1 addition & 1 deletion docs/src/run-optimsolver.md
Expand Up @@ -129,7 +129,7 @@ nlp2 = ADNLPModel(rosenbrock, x0,
nlp_at_x_c = NLPAtX(x0, zeros(nlp2.meta.ncon))
stop_nlp_c = NLPStopping(nlp2, (x,y) -> KKT(x,y), nlp_at_x_c, atol = 1e-3,
max_cntrs = Main.Stopping._init_max_counters(obj = 400000, cons = 800000, sum = 1000000))
max_cntrs = init_max_counters(obj = 400000, cons = 800000, sum = 1000000))
penalty(stop_nlp_c)
@show status(stop_nlp_c)
Expand Down
3 changes: 2 additions & 1 deletion src/Stopping.jl
Expand Up @@ -188,10 +188,11 @@ module Stopping
export update_and_stop!, cheap_update_and_stop!, cheap_update_and_start!
export fill_in!, reinit!, status, elapsed_time
export NLPStopping, unconstrained_check, unconstrained2nd_check, max_evals!
export optim_check_bounded, KKT
export optim_check_bounded, KKT, init_max_counters, init_max_counters_NLS

include("Stopping/LinearAlgebraStopping.jl")

export LAStopping, LinearSystem, LACounters, linear_system_check, normal_equation_check
export init_max_counters_linear_operators

end # end of module
26 changes: 13 additions & 13 deletions src/Stopping/LinearAlgebraStopping.jl
Expand Up @@ -31,7 +31,7 @@ Note:
- State don't necessarily keep track of evals
- Evals are checked only for pb.A being a LinearOperator
- zero_start is true if 0 is the initial guess (not check automatically)
- LLSModel counter follow NLSCounters (see _init_max_counters_NLS in NLPStoppingmod.jl)
- LLSModel counter follow NLSCounters (see init_max_counters_NLS in NLPStoppingmod.jl)
- By default, meta.max\\_cntrs is initialized with an NLSCounters
There is additional constructors:
Expand Down Expand Up @@ -108,9 +108,9 @@ See also GenericStopping, NLPStopping, LS\\_Stopping, linear\\_system\\_check, n
if :max_cntrs in keys(kwargs)
mcntrs = kwargs[:max_cntrs]
elseif Pb <: LLSModel
mcntrs = _init_max_counters_NLS()
mcntrs = init_max_counters_NLS()
else
mcntrs = _init_max_counters_linear_operators()
mcntrs = init_max_counters_linear_operators()
end

if :optimality_check in keys(kwargs)
Expand All @@ -135,7 +135,7 @@ function LAStopping(A :: TA,
pb = sparse ? LLSModel(A,b) : LinearSystem(A,b)
state = GenericState(x)

mcntrs = sparse ? _init_max_counters_NLS() : _init_max_counters_linear_operators()
mcntrs = sparse ? init_max_counters_NLS() : init_max_counters_linear_operators()

if n_listofstates > 0 && :list keys(kwargs)
list = ListofStates(n_listofstates, Val{typeof(state)}())
Expand All @@ -153,7 +153,7 @@ function LAStopping(A :: TA,

pb = sparse ? LLSModel(A,b) : LinearSystem(A,b)

mcntrs = sparse ? _init_max_counters_NLS() : _init_max_counters_linear_operators()
mcntrs = sparse ? init_max_counters_NLS() : init_max_counters_linear_operators()

return LAStopping(pb, state, max_cntrs = mcntrs; kwargs...)
end
Expand Down Expand Up @@ -182,15 +182,15 @@ function LACounters(;nprod :: Int64 = 0, ntprod :: Int64 = 0,
end

"""
\\_init\\_max\\_counters\\_linear\\_operators(): counters for LinearOperator
init\\_max\\_counters\\_linear\\_operators: counters for LinearOperator
`_init_max_counters_linear_operators(;nprod :: Int = 20000, ntprod :: Int = 20000, nctprod :: Int = 20000, sum :: Int = 20000*11)`
`init_max_counters_linear_operators(; allevals :: T = 20000, nprod = allevals, ntprod = allevals, nctprod = allevals, sum = 11 * allevals)`
"""
function _init_max_counters_linear_operators(;quick :: T = 20000,
nprod :: T = quick,
ntprod :: T = quick,
nctprod :: T = quick,
sum :: T = quick*11
function init_max_counters_linear_operators(; allevals :: T = 20000,
nprod :: T = allevals,
ntprod :: T = allevals,
nctprod :: T = allevals,
sum :: T = allevals * 11
) where T <: Int

cntrs = Dict{Symbol,T}([(:nprod, nprod),
Expand Down Expand Up @@ -242,7 +242,7 @@ function LAStopping(A :: TA,
) where {TA <: AbstractLinearOperator,
Tb <: AbstractVector}
return LAStopping(LinearSystem(A,b), state,
max_cntrs = _init_max_counters_linear_operators(),
max_cntrs = init_max_counters_linear_operators(),
kwargs...)
end

Expand Down
82 changes: 33 additions & 49 deletions src/Stopping/NLPStoppingmod.jl
Expand Up @@ -16,7 +16,7 @@ Attributes:
- (opt) listofstates : ListofStates designed to store the history of States.
- (opt) stopping_user_struct : Contains any structure designed by the user.
`NLPStopping(:: AbstractNLPModel, :: AbstractState; meta :: AbstractStoppingMeta = StoppingMeta(), max_cntrs :: Dict = _init_max_counters(), main_stp :: Union{AbstractStopping, Nothing} = nothing, list :: Union{ListofStates, Nothing} = nothing, stopping_user_struct :: Any = nothing, kwargs...)`
`NLPStopping(:: AbstractNLPModel, :: AbstractState; meta :: AbstractStoppingMeta = StoppingMeta(), max_cntrs :: Dict = init_max_counters(), main_stp :: Union{AbstractStopping, Nothing} = nothing, list :: Union{ListofStates, Nothing} = nothing, stopping_user_struct :: Any = nothing, kwargs...)`
Note:
- designed for `NLPAtX` State. Constructor checks that the State has the
Expand Down Expand Up @@ -98,7 +98,7 @@ function NLPStopping(pb :: Pb,
if :max_cntrs in keys(kwargs)
mcntrs = kwargs[:max_cntrs]
else
mcntrs = _init_max_counters()
mcntrs = init_max_counters()
end

if :optimality_check in keys(kwargs)
Expand Down Expand Up @@ -129,70 +129,54 @@ function NLPStopping(pb :: AbstractNLPModel;
end

"""
\\_init\\_max\\_counters(): initialize the maximum number of evaluations on each of
the functions present in the Counters (NLPModels).
init\\_max\\_counters:
initialize the maximum number of evaluations on each of
the functions present in the NLPModels.Counters, e.g.
`_init_max_counters(; obj :: Int64 = 20000, grad :: Int64 = 20000, cons :: Int64 = 20000, jcon :: Int64 = 20000, jgrad :: Int64 = 20000, jac :: Int64 = 20000, jprod :: Int64 = 20000, jtprod :: Int64 = 20000, hess :: Int64 = 20000, hprod :: Int64 = 20000, jhprod :: Int64 = 20000, sum :: Int64 = 20000*11)`
`init_max_counters(; allevals :: T = 20000, obj = allevals, grad = allevals, cons = allevals, jcon = allevals, jgrad = allevals, jac = allevals, jprod = allevals, jtprod = allevals, hess = allevals, hprod = allevals, jhprod = allevals, sum = 11 * allevals, kwargs...)`
`:neval_sum` is by default limited to `|Counters| * allevals`.
"""
function _init_max_counters(; allevals :: T = 20000,
obj :: T = allevals,
grad :: T = allevals,
cons :: T = allevals,
jcon :: T = allevals,
jgrad :: T = allevals,
jac :: T = allevals,
jprod :: T = allevals,
jtprod :: T = allevals,
hess :: T = allevals,
hprod :: T = allevals,
jhprod :: T = allevals,
sum :: T = allevals*11) where {T <: Int}

cntrs = Dict{Symbol,T}([(:neval_obj, obj), (:neval_grad, grad),
(:neval_cons, cons), (:neval_jcon, jcon),
(:neval_jgrad, jgrad), (:neval_jac, jac),
(:neval_jprod, jprod), (:neval_jtprod, jtprod),
(:neval_hess, hess), (:neval_hprod, hprod),
(:neval_jhprod, jhprod), (:neval_sum, sum)])
function init_max_counters(; allevals :: T = 20000, kwargs...) where {T <: Int}

entries = [Meta.parse(split("$(f)", '_')[2]) for f in fieldnames(Counters)]
lim_fields = keys(kwargs)
cntrs = Dict{Symbol,T}([
(Meta.parse("neval_$(t)"), t in lim_fields ? kwargs[t] : allevals) for t in entries
])
push!(cntrs,
(:neval_sum => :sum in lim_fields ? kwargs[:sum] : length(entries) * allevals )
)

return cntrs
end

function max_evals!(stp :: NLPStopping, allevals :: Int)
stp.meta.max_cntrs = _init_max_counters(allevals = allevals)
stp.meta.max_cntrs = init_max_counters(allevals = allevals)
return stp
end

function max_evals!(stp :: NLPStopping; allevals :: T = 20000, kwargs...) where {T <: Int}
stp.meta.max_cntrs = _init_max_counters(allevals = allevals; kwargs...)
stp.meta.max_cntrs = init_max_counters(allevals = allevals; kwargs...)
return stp
end

"""
\\_init\\_max\\_counters\\_NLS(): initialize the maximum number of evaluations on each of
the functions present in the NLSCounters (NLPModels).
https://github.com/JuliaSmoothOptimizers/NLPModels.jl/blob/master/src/NLSModels.jl
init\\_max\\_counters\\_NLS:
initialize the maximum number of evaluations on each of
the functions present in the `NLPModels.NLSCounters`, e.g.
`_init_max_counters_NLS(; residual :: Int = 20000, jac_residual :: Int = 20000, jprod_residual :: Int = 20000, jtprod_residual :: Int = 20000, hess_residual :: Int = 20000, jhess_residual :: Int = 20000, hprod_residual :: Int = 20000, kwargs...)`
`init_max_counters_NLS(; allevals = 20000, residual = allevals, jac_residual = allevals, jprod_residual = allevals, jtprod_residual = allevals, hess_residual = allevals, jhess_residual = allevals, hprod_residual = allevals, kwargs...)`
"""
function _init_max_counters_NLS(; allevals :: T = 20000,
residual :: T = allevals,
jac_residual :: T = allevals,
jprod_residual :: T = allevals,
jtprod_residual :: T = allevals,
hess_residual :: T = allevals,
jhess_residual :: T = allevals,
hprod_residual :: T = allevals,
kwargs...) where {T <: Int}

cntrs_nlp = _init_max_counters(;kwargs...)
cntrs = Dict{Symbol,T}([(:neval_residual, residual),
(:neval_jac_residual, jac_residual),
(:neval_jprod_residual, jprod_residual),
(:neval_jtprod_residual, jtprod_residual),
(:neval_hess_residual, hess_residual),
(:neval_jhess_residual, jhess_residual),
(:neval_hprod_residual, hprod_residual)])
function init_max_counters_NLS(; allevals :: T = 20000, kwargs...) where {T <: Int}

cntrs_nlp = init_max_counters(; allevals = allevals, kwargs...)

entries = [Meta.parse(split("$(f)", '_')[2]) for f in setdiff(fieldnames(NLSCounters),[:counters])]
lim_fields = keys(kwargs)
cntrs = Dict{Symbol,T}([
(Meta.parse("neval_$(t)"), t in lim_fields ? kwargs[t] : allevals) for t in entries
])

return merge(cntrs_nlp, cntrs)
end
Expand Down
6 changes: 3 additions & 3 deletions src/Stopping/StoppingMetamod.jl
Expand Up @@ -87,7 +87,7 @@ mutable struct StoppingMeta{TolType <: Number,

# fine grain control on ressources
max_f :: IntType # max function evaluations allowed TODO: used?
max_cntrs :: Dict{Symbol,Int64} #contains the detailed max number of evaluations
max_cntrs :: Dict{Symbol, Int} #contains the detailed max number of evaluations

# global control on ressources
max_eval :: IntType # max evaluations (f+g+H+Hv) allowed TODO: used?
Expand Down Expand Up @@ -130,7 +130,7 @@ function StoppingMeta(tol_check :: CheckType,
unbounded_threshold :: Number = 1.0e50, #typemax(Float64)
unbounded_x :: Number = 1.0e50,
max_f :: Int = typemax(Int),
max_cntrs :: Dict{Symbol,Int} = Dict{Symbol,Int64}(),
max_cntrs :: Dict{Symbol, Int} = Dict{Symbol, Int}(),
max_eval :: Int = 20000,
max_iter :: Int = 5000,
max_time :: Float64 = 300.0,
Expand Down Expand Up @@ -187,7 +187,7 @@ function StoppingMeta(;atol :: Number = 1.0e-6,
unbounded_threshold :: Number = 1.0e50, #typemax(Float64)
unbounded_x :: Number = 1.0e50,
max_f :: Int = typemax(Int),
max_cntrs :: Dict{Symbol,Int} = Dict{Symbol,Int64}(),
max_cntrs :: Dict{Symbol, Int} = Dict{Symbol, Int}(),
max_eval :: Int = 20000,
max_iter :: Int = 5000,
max_time :: Float64 = 300.0,
Expand Down
4 changes: 2 additions & 2 deletions test/examples/howtostop-nlp.jl
Expand Up @@ -71,8 +71,8 @@ fill_in!(stop_nlp_lazy, x1)
@test stop_nlp.meta.max_cntrs[:neval_obj] == 20000
@test stop_nlp.meta.max_cntrs[:neval_grad] == 20000

#Limit can be set using _init_max_counters function:
stop_nlp.meta.max_cntrs = Stopping._init_max_counters(obj = 3, grad = 0, hess = 0)
#Limit can be set using init_max_counters function:
stop_nlp.meta.max_cntrs = init_max_counters(obj = 3, grad = 0, hess = 0)
@test stop_nlp.meta.max_cntrs[:neval_obj] == 3
@test stop_nlp.meta.max_cntrs[:neval_grad] == 0

Expand Down
2 changes: 1 addition & 1 deletion test/examples/run-optimsolver.jl
Expand Up @@ -147,7 +147,7 @@ nlp2 = ADNLPModel(rosenbrock, x0,

nlp_at_x_c = NLPAtX(x0, zeros(nlp2.meta.ncon))
stop_nlp_c = NLPStopping(nlp2, nlp_at_x_c, atol = 1e-3,
max_cntrs = Stopping._init_max_counters(obj = 400000, cons = 800000, sum = 1000000), optimality_check = (x,y) -> KKT(x,y))
max_cntrs = init_max_counters(obj = 400000, cons = 800000, sum = 1000000), optimality_check = (x,y) -> KKT(x,y))

penalty(stop_nlp_c)
@show status(stop_nlp_c)
Expand Down
6 changes: 3 additions & 3 deletions test/test-stopping/test-unitaire-generic-stopping.jl
Expand Up @@ -56,8 +56,8 @@
#We build a substopping:
x1 = zeros(6)
state1 = GenericState(x1)
ABigInt = 100000000000000000 #to avoid the stop by counting stop calls
substop = GenericStopping(rosenbrock, state1, main_stp = stop, max_iter = ABigInt, rtol = 0.0 )
# to avoid the stop by counting stop calls
substop = GenericStopping(rosenbrock, state1, main_stp = stop, max_iter = typemax(Int), rtol = 0.0 )
substop.stop_remote = StopRemoteControl()
#If rtol != 0, any point is a solution as optimality0 = Inf.

Expand Down Expand Up @@ -115,7 +115,7 @@
#
# Test the triple sub-Stopping now:
#
subsubstop = GenericStopping(rosenbrock, state1, main_stp = substop, max_iter = ABigInt, rtol = 0.0 )
subsubstop = GenericStopping(rosenbrock, state1, main_stp = substop, max_iter = typemax(Int), rtol = 0.0 )
#If rtol != 0, any point is a solution as optimality0 = Inf.

#Solve again the problem
Expand Down
14 changes: 7 additions & 7 deletions test/test-stopping/test-unitaire-linearalgebrastopping.jl
Expand Up @@ -24,16 +24,16 @@ opA = LinearOperator(A)
mLO = LinearSystem(A, b)
sLO = LLSModel(sA, b)
opLO = LinearSystem(opA, b)
meta = StoppingMeta(max_cntrs = Stopping._init_max_counters_linear_operators())
meta = StoppingMeta(max_cntrs = init_max_counters_linear_operators())
mLOstp_meta = LAStopping(mLO, meta, GenericState(x0)) #this is different because of optimality_check
mLOstp = LAStopping(mLO, GenericState(x0), max_cntrs = Stopping._init_max_counters_linear_operators())
mLOstp = LAStopping(mLO, GenericState(x0), max_cntrs = init_max_counters_linear_operators())
sLOstp = LAStopping(sLO, GenericState(x0))
short_stop = LAStopping(A,b, sparse = true) #note that sparse is true by default
maxcn = Stopping._init_max_counters_linear_operators(nprod = 1)
maxcn = init_max_counters_linear_operators(nprod = 1)
opLOstp = LAStopping(opLO, GenericState(x0), max_cntrs = maxcn)

opLOstp2 = LAStopping(opLO, GenericState(x0), optimality_check = linear_system_check)
@test opLOstp2.meta.max_cntrs == Stopping._init_max_counters_linear_operators()
@test opLOstp2.meta.max_cntrs == init_max_counters_linear_operators()
@test opLOstp2.meta.optimality_check == opLOstp.meta.optimality_check

mLOstp_src = LAStopping(mLO, meta, StopRemoteControl(), GenericState(x0))
Expand Down Expand Up @@ -110,19 +110,19 @@ x0 = zeros(n)
la_stop = LAStopping(A, b, GenericState(x0),
max_iter = 150000,
rtol = 1e-6,
max_cntrs = Stopping._init_max_counters_NLS(residual = 150000))
max_cntrs = init_max_counters_NLS(residual = 150000))
#Be careful using GenericState(x0) would not work here without forcing convert = true
#in the update function. As the iterate will be a SparseVector to the contrary of initial guess.
#Tangi: maybe start! should send a Warning for such problem !?
sa_stop = LAStopping(sparse(A), b, GenericState(sparse(x0)),
max_iter = 150000,
rtol = 1e-6,
max_cntrs = Stopping._init_max_counters_NLS(residual = 150000))
max_cntrs = init_max_counters_NLS(residual = 150000))
op_stop = LAStopping(LinearSystem(LinearOperator(A), b),
GenericState(x0),
max_iter = 150000,
rtol = 1e-6,
max_cntrs = Stopping._init_max_counters_linear_operators(nprod = 150000))
max_cntrs = init_max_counters_linear_operators(nprod = 150000))
opbis_stop = LAStopping(LinearOperator(A), b)

try
Expand Down

0 comments on commit ea41e74

Please sign in to comment.