diff --git a/paper/code/test.jl b/paper/code/test.jl index b8029ba2..f05ec5e5 100644 --- a/paper/code/test.jl +++ b/paper/code/test.jl @@ -1,4 +1,4 @@ -using NLPModels, Stopping +using LinearAlgebra, NLPModels, Stopping include("NewtonSolver.jl") include("Armijo.jl") diff --git a/pluto/notebook.jl b/pluto/notebook.jl new file mode 100644 index 00000000..88395d30 --- /dev/null +++ b/pluto/notebook.jl @@ -0,0 +1,219 @@ +### A Pluto.jl notebook ### +# v0.12.6 + +using Markdown +using InteractiveUtils + +# ╔═╡ 24e89936-2048-11eb-2e22-3771c6cbf492 +begin + using LinearAlgebra, NLPModels, Stopping, Test +end + +# ╔═╡ 6919e7e4-2047-11eb-1994-67f541031e50 +md" +# Stopping + +[![Build Status](https://travis-ci.org/vepiteski/Stopping.jl.svg?branch=master)](https://travis-ci.org/vepiteski/Stopping.jl) +[![Coverage Status](https://coveralls.io/repos/vepiteski/Stopping.jl/badge.svg?branch=master&service=github)](https://coveralls.io/github/vepiteski/Stopping.jl?branch=julia-0.7) +[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://vepiteski.github.io/Stopping.jl/dev/) +" + +# ╔═╡ bdc19b18-2047-11eb-04a0-f75a546514ce +md" +## How to install +Install and test the Stopping package with the Julia package manager: +```julia +pkg> add Stopping +pkg> test Stopping +``` +You can access the most up-to-date version of the Stopping package using: +```julia +pkg> add https://github.com/vepiteski/Stopping.jl +pkg> test Stopping +pkg> status Stopping +``` +" + +# ╔═╡ 7d8b468e-2047-11eb-118e-9f3f78f0cb2d +md" +## Purpose + +Tools to ease the uniformization of stopping criteria in iterative solvers. + +When a solver is called on an optimization model, four outcomes may happen: + +1. the approximate solution is obtained, the problem is considered solved +2. the problem is declared unsolvable (unboundedness, infeasibility ...) +3. the maximum available resources are not sufficient to compute the solution +4. some algorithm dependent failure happens + +This tool eases the first three items above. It defines a type + + mutable struct GenericStopping <: AbstractStopping + problem :: Any # an arbitrary instance of a problem + meta :: AbstractStoppingMeta # contains the used parameters and stopping status + current_state :: AbstractState # Current information on the problem + main_stp :: Union{AbstractStopping, Nothing} # Stopping of the main problem, or nothing + listofstates :: Union{ListStates, Nothing} # History of states + user_specific_struct :: Any # User-specific structure + +The [StoppingMeta](https://github.com/vepiteski/Stopping.jl/blob/master/src/Stopping/StoppingMetamod.jl) provides default tolerances, maximum resources, ... as well as (boolean) information on the result. + +## Functions + +The tool provides two main functions: +* `start!(stp :: AbstractStopping)` initializes the time and the tolerance at the starting point and check wether the initial guess is optimal. +* `stop!(stp :: AbstractStopping)` checks optimality of the current guess as well as failure of the system (unboundedness for instance) and maximum resources (number of evaluations of functions, elapsed time ...) + +Stopping uses the informations furnished by the State to evaluate its functions. Communication between the two can be done through the following functions: +* `update_and_start!(stp :: AbstractStopping; kwargs...)` updates the states with informations furnished as kwargs and then call start!. +* `update_and_stop!(stp :: AbstractStopping; kwargs...)` updates the states with informations furnished as kwargs and then call stop!. +* `fill_in!(stp :: AbstractStopping, x :: Iterate)` a function that fill in all the State with all the informations required to correctly evaluate the stopping functions. This can reveal useful, for instance, if the user do not trust the informations furnished by the algorithm in the State. +* `reinit!(stp :: AbstractStopping)` reinitialize the entries of +the Stopping to reuse for another call. +" + +# ╔═╡ 8f532b5c-2047-11eb-3ece-b5c66e3c1030 +md" +## Example + +As an example, a naive version of the Newton method is provided [here](https://github.com/vepiteski/Stopping.jl/blob/master/test/examples/newton.jl). First we import the packages: +" + +# ╔═╡ 2b84477c-2048-11eb-00cf-4d8cbd285252 +md" +We consider a quadratic test function, and create an uncontrained quadratic optimization problem using [NLPModels](https://github.com/JuliaSmoothOptimizers/NLPModels.jl): +" + +# ╔═╡ 31305268-2048-11eb-0145-9dded700c8c7 +begin + A = rand(5, 5); Q = A' * A; + f(x) = 0.5 * x' * Q * x + sum(x) + nlp = ADNLPModel(f, ones(5)) + + nlp.meta.nvar +end + +# ╔═╡ 3afd8c90-2048-11eb-1195-b7a16248f31d +md" +We now initialize the *NLPStopping*. First create a State. We use [unconstrained_check](https://github.com/vepiteski/Stopping.jl/blob/master/src/Stopping/nlp_admissible_functions.jl) as an optimality function +" + +# ╔═╡ 41b7df4a-2048-11eb-0823-3f28002e28a8 +begin + nlp_at_x = NLPAtX(ones(5)) + #stop_nlp = NLPStopping(nlp, nlp_at_x, optimality_check = unconstrained_check) + #Note that, since we used a default State, an alternative would have been: + stop_nlp = NLPStopping(nlp) + + stop_nlp.meta.atol +end + +# ╔═╡ 63dc7522-2048-11eb-2d72-5353bdba39eb +md" +Now a basic version of Newton to illustrate how to use Stopping. +" + +# ╔═╡ 675e49aa-2048-11eb-2263-65258ce6508e +begin + function newton(stp :: NLPStopping) + + #Notations + pb = stp.pb; state = stp.current_state; + #Initialization + xt = state.x + + #First, call start! to check optimality and set an initial configuration + #(start the time counter, set relative error ...) + OK = update_and_start!(stp, x = xt, gx = grad(pb, xt), Hx = hess(pb, xt)) + + while !OK + #Compute the Newton direction (state.Hx only has the lower triangular) + d = (state.Hx + state.Hx' - diagm(0 => diag(state.Hx))) \ (- state.gx) + #Update the iterate + xt = xt + d + #Update the State and call the Stopping with stop! + OK = update_and_stop!(stp, x = xt, gx = grad(pb, xt), Hx = hess(pb, xt)) + end + + return stp + end +end + +# ╔═╡ 78f87730-2048-11eb-14e4-0b692bf6e7a8 +md" +Finally, we can call the algorithm with our Stopping, and consult the Stopping to know what happened. +" + +# ╔═╡ 7be7cb08-2048-11eb-31ea-132cefd60433 +begin + newton(stop_nlp) + + #We can then ask stop_nlp the final status + status(stop_nlp, list = true) +end + +# ╔═╡ 8de7e950-2048-11eb-3e1b-b3d350e346c8 +begin + #Explore the final values in stop_nlp.current_state + @show "Final solution is $(stop_nlp.current_state.x)" +end + +# ╔═╡ 9de11048-2048-11eb-3ffc-7fc8110510e4 +md" +We reached optimality, and thanks to the Stopping structure this simple looking +algorithm verified at each step of the algorithm: +- time limit has been respected; +- evaluations of the problem are not excessive; +- the problem is not unbounded (w.r.t. x and f(x)); +- there is no NaN in x, f(x), g(x), H(x); +- the maximum number of iteration (call to stop!) is limited. +" + +# ╔═╡ ceaf484e-2047-11eb-018c-4b5f3696e597 +md" +### Your Stopping your way + +The GenericStopping (with GenericState) provides a complete structure to handle stopping criteria. +Then, depending on the problem structure, you can specialize a new Stopping by +redefining a State and some functions specific to your problem. + +We provide some specialization of the GenericStopping for optimization: + * [NLPStopping](https://github.com/vepiteski/Stopping.jl/blob/master/src/Stopping/NLPStoppingmod.jl) with [NLPAtX](https://github.com/vepiteski/Stopping.jl/blob/master/src/State/NLPAtXmod.jl) as a specialized State: for non-linear programming (based on [NLPModels](https://github.com/JuliaSmoothOptimizers/NLPModels.jl)); + * [LAStopping](https://github.com/vepiteski/Stopping.jl/blob/master/src/Stopping/LinearAlgebraStopping.jl) with [GenericState](https://github.com/vepiteski/Stopping.jl/blob/master/src/State/GenericStatemod.jl): for linear algebra problems. + * [LS_Stopping](https://github.com/vepiteski/Stopping.jl/blob/master/src/Stopping/LineSearchStoppingmod.jl) with [LSAtT](https://github.com/vepiteski/Stopping.jl/blob/master/src/State/LSAtTmod.jl) as a specialized State: for 1d optimization; + * more to come... + +### How To Stopping + +Consult the [HowTo tutorial](https://github.com/vepiteski/Stopping.jl/blob/master/test/examples/runhowto.jl) to learn more about the possibilities offered by Stopping. + +You can also access other examples of algorithms in the [test/examples](https://github.com/vepiteski/Stopping.jl/blob/master/test/examples/) folder, which for instance illustrate the strenght of Stopping with subproblems: +* Consult the [OptimSolver tutorial](https://github.com/vepiteski/Stopping.jl/blob/master/test/examples/run-optimsolver.jl) for more on how to use Stopping with nested algorithms. +* Check the [Benchmark tutorial](https://github.com/vepiteski/Stopping.jl/blob/master/test/examples/benchmark.jl) to see how Stopping can combined with [SolverBenchmark.jl](https://juliasmoothoptimizers.github.io/SolverBenchmark.jl/). +* Stopping can be adapted to closed solvers via a buffer function as in [Buffer tutorial](https://github.com/vepiteski/Stopping.jl/blob/master/test/examples/buffer.jl) for an instance with [Ipopt](https://github.com/JuliaOpt/Ipopt.jl) via [NLPModelsIpopt](https://github.com/JuliaSmoothOptimizers/NLPModelsIpopt.jl). + +## Long-Term Goals + +Stopping is aimed as a tool for improving the reusability and robustness in the implementation of iterative algorithms. We warmly welcome any feedback or comment leading to potential improvements. + +Future work will address more sophisticated problems such as mixed-integer optimization problems, optimization with uncertainty. The list of suggested optimality functions will be enriched with state of the art conditions. +" + +# ╔═╡ Cell order: +# ╟─6919e7e4-2047-11eb-1994-67f541031e50 +# ╟─bdc19b18-2047-11eb-04a0-f75a546514ce +# ╟─7d8b468e-2047-11eb-118e-9f3f78f0cb2d +# ╟─8f532b5c-2047-11eb-3ece-b5c66e3c1030 +# ╠═24e89936-2048-11eb-2e22-3771c6cbf492 +# ╠═2b84477c-2048-11eb-00cf-4d8cbd285252 +# ╠═31305268-2048-11eb-0145-9dded700c8c7 +# ╟─3afd8c90-2048-11eb-1195-b7a16248f31d +# ╠═41b7df4a-2048-11eb-0823-3f28002e28a8 +# ╟─63dc7522-2048-11eb-2d72-5353bdba39eb +# ╠═675e49aa-2048-11eb-2263-65258ce6508e +# ╟─78f87730-2048-11eb-14e4-0b692bf6e7a8 +# ╠═7be7cb08-2048-11eb-31ea-132cefd60433 +# ╠═8de7e950-2048-11eb-3e1b-b3d350e346c8 +# ╟─9de11048-2048-11eb-3ffc-7fc8110510e4 +# ╟─ceaf484e-2047-11eb-018c-4b5f3696e597 diff --git a/src/State/GenericStatemod.jl b/src/State/GenericStatemod.jl index 41f81be6..747f1eeb 100644 --- a/src/State/GenericStatemod.jl +++ b/src/State/GenericStatemod.jl @@ -110,38 +110,44 @@ function reinit!(stateatx :: AbstractState; kwargs...) end """ -\\_domain\\_check: returns true if there is a NaN in the State entries, false otherwise +\\_domain\\_check: returns true if there is a *NaN* or a *Missing* in the state entries (short-circuiting), false otherwise. -`_domain_check(:: AbstractState)` +`_domain_check(:: AbstractState; kwargs...)` + +Note: +- The fields given as keys in kwargs are not checked. Examples: \\_domain\\_check(state1) +\\_domain\\_check(state1, x = true) """ -function _domain_check(stateatx :: AbstractState) - domainerror = false +function _domain_check(stateatx :: T; kwargs...) where T <: AbstractState - for k ∈ fieldnames(typeof(stateatx)) - _temp = getfield(stateatx, k) - domainerror = domainerror || _check_nan(_temp) + for k ∈ setdiff(fieldnames(T), keys(kwargs)) + + gf = getfield(stateatx, k) + if _check_nan_miss(gf) + return true + end end - return domainerror + return false end -_check_nan(field :: Any) = false #Nothing or Counters -_check_nan(field :: SparseMatrixCSC) = any(isnan, field.nzval) #because checking in sparse matrices is too slow -_check_nan(field :: Union{AbstractVector,AbstractMatrix}) = any(isnan, field) -_check_nan(field :: AbstractFloat) = isnan(field) +_check_nan_miss(field :: Any) = false #Nothing or Counters +_check_nan_miss(field :: SparseMatrixCSC) = any(isnan, field.nzval) #because checking in sparse matrices is too slow +_check_nan_miss(field :: Union{AbstractVector,AbstractMatrix}) = any(isnan, field) +_check_nan_miss(field :: AbstractFloat) = ismissing(field) || isnan(field) import Base.copy ex=:(_genobj(typ)=$(Expr(:new, :typ))); eval(ex) -function copy(state :: AbstractState) +function copy(state :: T) where T <: AbstractState #ex=:(_genobj(typ)=$(Expr(:new, :typ))); eval(ex) - cstate = _genobj(typeof(state)) + cstate = _genobj(T) #cstate = $(Expr(:new, typeof(state))) - for k ∈ fieldnames(typeof(state)) + for k ∈ fieldnames(T) setfield!(cstate, k, deepcopy(getfield(state, k))) end @@ -162,14 +168,14 @@ corresponding entries are replaced by a vector of size 1 containing its pnorm-no see also: copy, copy\\_compress\\_state, ListStates """ -function compress_state!(stateatx :: AbstractState; +function compress_state!(stateatx :: T; save_matrix :: Bool = false, max_vector_size :: Int = length(stateatx.x), pnorm :: Float64 = Inf, keep :: Bool = false, - kwargs...) + kwargs...) where T <: AbstractState - for k ∈ fieldnames(typeof(stateatx)) + for k ∈ fieldnames(T) if k ∈ keys(kwargs) && !keep try setfield!(stateatx, k, nothing) diff --git a/src/State/NLPAtXmod.jl b/src/State/NLPAtXmod.jl index a039752c..ef45dc4d 100644 --- a/src/State/NLPAtXmod.jl +++ b/src/State/NLPAtXmod.jl @@ -113,7 +113,7 @@ prioritized over the existing *x*, *lambda* and the default *Counters*. """ function reinit!(stateatx :: NLPAtX, x :: AbstractVector, l :: AbstractVector; kwargs...) - for k ∈ fieldnames(typeof(stateatx)) + for k ∈ fieldnames(NLPAtX) if k ∉ [:x,:lambda,:evals] setfield!(stateatx, k, nothing) end end diff --git a/src/Stopping/GenericStoppingmod.jl b/src/Stopping/GenericStoppingmod.jl index 91933134..ace07e45 100644 --- a/src/Stopping/GenericStoppingmod.jl +++ b/src/Stopping/GenericStoppingmod.jl @@ -92,7 +92,7 @@ fill_in!: fill in the unspecified values of the AbstractState. Note: NotImplemented for Abstract/Generic-Stopping. """ -function fill_in!(stp :: AbstractStopping, x :: Union{Number, AbstractVector}) +function fill_in!(stp :: AbstractStopping, x :: T) where T return throw(error("NotImplemented function")) end @@ -129,19 +129,19 @@ end """ function start!(stp :: AbstractStopping; no_start_opt_check :: Bool = false, kwargs...) - stt_at_x = stp.current_state - x = stt_at_x.x + state = stp.current_state + x = state.x #Initialize the time counter if isnan(stp.meta.start_time) stp.meta.start_time = time() end #and synchornize with the State - if stt_at_x.current_time == nothing - update!(stt_at_x, current_time = time()) + if state.current_time == nothing + update!(state, current_time = time()) end - stp.meta.domainerror = _domain_check(stp.current_state) + stp.meta.domainerror = _domain_check(state) if !stp.meta.domainerror && !no_start_opt_check # Optimality check optimality0 = _optimality_check(stp; kwargs...) @@ -246,7 +246,8 @@ function stop!(stp :: AbstractStopping; kwargs...) x = stp.current_state.x time = stp.meta.start_time - stp.meta.domainerror = _domain_check(stp.current_state) #pb here? + _unbounded_and_domain_x_check!(stp, x) + stp.meta.domainerror = _domain_check(stp.current_state, x = true) if !stp.meta.domainerror # Optimality check score = _optimality_check(stp; kwargs...) @@ -255,7 +256,6 @@ function stop!(stp :: AbstractStopping; kwargs...) end stp.meta.optimal = _null_test(stp, score) - _unbounded_check!(stp, x) _unbounded_problem_check!(stp, x) _tired_check!(stp, x, time_t = time) _resources_check!(stp, x) @@ -310,7 +310,7 @@ limit. Note: Compare *meta.iteration_limit* with *meta.nb\\_of\\_stop*. """ function _iteration_check!(stp :: AbstractStopping, - x :: T) where T <: Union{Number, AbstractVector} + x :: T) where T max_iter = stp.meta.nb_of_stop >= stp.meta.max_iter @@ -327,7 +327,7 @@ end Note: By default *meta.stalled* is false for Abstract/Generic Stopping. """ function _stalled_check!(stp :: AbstractStopping, - x :: T) where T <: Union{Number, AbstractVector} + x :: T) where T stp.meta.stalled = false @@ -344,7 +344,7 @@ Note: - Return false if *time_t* is NaN (by default). """ function _tired_check!(stp :: AbstractStopping, x :: T; - time_t :: Number = NaN) where T <: Union{Number, AbstractVector} + time_t :: Number = NaN) where T # Time check if !isnan(time_t) @@ -368,7 +368,7 @@ end Note: By default *meta.resources* is false for Abstract/Generic Stopping. """ function _resources_check!(stp :: AbstractStopping, - x :: T) where T <: Union{Number, AbstractVector} + x :: T) where T max_evals = false max_f = false @@ -387,7 +387,7 @@ Note: - Modify the meta of the *main_stp*. - By default `meta.main_pb = false`. """ function _main_pb_check!(stp :: AbstractStopping, - x :: T) where T <: Union{Number, AbstractVector} + x :: T) where T # Time check time = stp.main_stp.meta.start_time @@ -411,21 +411,34 @@ function _main_pb_check!(stp :: AbstractStopping, end """ -\\_unbounded\\_check!: check if x gets too big. +\\_unbounded\\_and\\_domain\\_x\\_check!: check if x gets too big, and if it has NaN or missing values. -`_unbounded_check!(:: AbstractStopping, :: Union{Number, AbstractVector})` +`_unbounded_and_domain_x_check!(:: AbstractStopping, :: Union{Number, AbstractVector})` -Note: compare ||x|| with *meta.unbounded_x* and update *meta.unbounded*. +Note: +- compare ||x||_∞ with *meta.unbounded_x* and update *meta.unbounded*. +- it also checks *NaN* and *missing* and update *meta.domainerror*. +- short-circuiting if one of the two is true. """ -function _unbounded_check!(stp :: AbstractStopping, - x :: T) where T <: Union{Number, AbstractVector} +function _unbounded_and_domain_x_check!(stp :: AbstractStopping, + x :: T) where T - pnorm = stp.meta.norm_unbounded_x - x_too_large = norm(x, pnorm) >= stp.meta.unbounded_x + bigX(z :: eltype(T)) = (abs(z) >= stp.meta.unbounded_x) + (stp.meta.unbounded, stp.meta.domainerror) = _large_and_domain_check(bigX, x) - stp.meta.unbounded = x_too_large +end - return stp +function _large_and_domain_check(f, itr) + for x in itr + v = f(x) + w = ismissing(x) || isnan(x) + if w + return (false, true) + elseif v + return (true, false) + end + end + return (false, false) end """ @@ -436,7 +449,7 @@ end Note: *meta.unbounded_pb* is false by default. """ function _unbounded_problem_check!(stp :: AbstractStopping, - x :: T) where T <: Union{Number, AbstractVector} + x :: T) where T stp.meta.unbounded_pb = false @@ -472,21 +485,41 @@ and `meta.tol_check_neg(meta.atol, meta.rtol, meta.optimality0)`. function _null_test(stp :: AbstractStopping, optimality :: T) where T <: Union{Number,AbstractVector} atol, rtol, opt0 = stp.meta.atol, stp.meta.rtol, stp.meta.optimality0 + check_pos = stp.meta.tol_check(atol, rtol, opt0) check_neg = stp.meta.tol_check_neg(atol, rtol, opt0) - optimal = !(false in (optimality .<= check_pos)) - optimal &= !(false in (optimality .>= check_neg)) + optimal = _inequality_check(optimality, check_pos, check_neg) return optimal end +_inequality_check(opt :: Number, check_pos :: Number, check_neg :: Number) = (opt <= check_pos) && (opt >= check_neg) +_inequality_check(opt, check_pos :: Number, check_neg :: Number) = !any(z->((z > check_pos) || (z < check_neg)), opt) +function _inequality_check(opt :: T, check_pos :: T, check_neg :: T) where T + + n = size(opt) + + if n != size(check_pos) || n != size(check_neg) + throw("Error: incompatible size in _null_test wrong size of optimality, tol_check and tol_check_neg") + end + + for (o, cp, cn) in zip(opt, check_pos, check_neg) + v = o > cp || o < cn + if v + return false + end + end + + return true +end + """ \\_user\\_check: nothing by default. `_user_check!( :: AbstractStopping, x :: Union{Number, AbstractVector})` """ -function _user_check!(stp :: AbstractStopping, x :: T) where T <: Union{Number, AbstractVector} +function _user_check!(stp :: AbstractStopping, x :: T) where T nothing end diff --git a/src/Stopping/NLPStoppingmod.jl b/src/Stopping/NLPStoppingmod.jl index b564387d..0e2d98eb 100644 --- a/src/Stopping/NLPStoppingmod.jl +++ b/src/Stopping/NLPStoppingmod.jl @@ -16,7 +16,7 @@ Attributes: - (opt) listofstates : ListStates designed to store the history of States. - (opt) user_specific_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, user_specific_struct :: Any = nothing, kwargs...)` +`NLPStopping(:: AbstractNLPModel, :: AbstractState; meta :: AbstractStoppingMeta = StoppingMeta(), max_cntrs :: Dict = _init_max_counters(), main_stp :: Union{AbstractStopping, Nothing} = nothing, list :: Union{ListStates, Nothing} = nothing, user_specific_struct :: Any = nothing, kwargs...)` Note: - designed for *NLPAtX* State. Constructor checks that the State has the diff --git a/src/Stopping/StoppingMetamod.jl b/src/Stopping/StoppingMetamod.jl index 897249ac..b2e5716a 100644 --- a/src/Stopping/StoppingMetamod.jl +++ b/src/Stopping/StoppingMetamod.jl @@ -11,7 +11,6 @@ Attributes: - optimality_check : a stopping criterion via an admissibility function - unbounded_threshold : threshold for unboundedness of the problem. - unbounded_x : threshold for unboundedness of the iterate. -- norm_unbounded_x : norm used for the threshold for unboundedness of the iterate. - max_f : maximum number of function (and derivatives) evaluations. - max_cntrs : Dict contains the maximum number of evaluations - max_eval : maximum number of function (and derivatives) evaluations. @@ -63,8 +62,7 @@ mutable struct StoppingMeta <: AbstractStoppingMeta # Function of (pb, state; kwargs...) unbounded_threshold :: Number # beyond this value, the problem is declared unbounded - unbounded_x :: Number # beyond this value, ||x|| is unbounded - norm_unbounded_x :: Number #norm used to check unboundedness of x. + unbounded_x :: Number # beyond this value, ||x||_\infty is unbounded # fine grain control on ressources max_f :: Int # max function evaluations allowed @@ -102,7 +100,6 @@ mutable struct StoppingMeta <: AbstractStoppingMeta optimality_check :: Function = (a,b) -> Inf, unbounded_threshold :: Number = 1.0e50, unbounded_x :: Number = 1.0e50, - norm_unbounded_x :: Number = Inf, max_f :: Int = typemax(Int), max_cntrs :: Dict = Dict(), max_eval :: Int = 20000, @@ -134,7 +131,7 @@ mutable struct StoppingMeta <: AbstractStoppingMeta nb_of_stop = 0 return new(atol, rtol, optimality0, tol_check, tol_check_neg, optimality_check, - unbounded_threshold, unbounded_x, norm_unbounded_x, + unbounded_threshold, unbounded_x, max_f, max_cntrs, max_eval, max_iter, max_time, nb_of_stop, start_time, fail_sub_pb, unbounded, unbounded_pb, tired, stalled, iteration_limit, resources, optimal, infeasible, main_pb, diff --git a/test/test-stopping/strong-epsilon-check.jl b/test/test-stopping/strong-epsilon-check.jl index 735ecc68..170f2f6e 100644 --- a/test/test-stopping/strong-epsilon-check.jl +++ b/test/test-stopping/strong-epsilon-check.jl @@ -85,8 +85,12 @@ fill_in!(stop_nlp, sol) OK = stop!(stop_nlp) @test OK -#Finally, let us comment on the case where the optimality_check returns a number: -stop_nlp = NLPStopping(nlp, nlp_at_x_c, optimality_check = KKT, tol_check = tol_check1) -fill_in!(stop_nlp, esol) -OK = stop!(stop_nlp) -@test !OK #esol is not a solution as the score returned by KKT is not smaller than minimum(tol_check) +#An error is returned if size(KKT) is different from size(tol_check). +try + stop_nlp2 = NLPStopping(nlp, nlp_at_x_c, optimality_check = KKT, tol_check = tol_check1) + fill_in!(stop_nlp2, esol) + stop!(stop_nlp2) + @test false +catch + @test true +end diff --git a/test/test-stopping/test-unitaire-generic-stopping.jl b/test/test-stopping/test-unitaire-generic-stopping.jl index 5a41c432..7e5371cd 100644 --- a/test/test-stopping/test-unitaire-generic-stopping.jl +++ b/test/test-stopping/test-unitaire-generic-stopping.jl @@ -11,9 +11,6 @@ stop0 = GenericStopping(rosenbrock, state0, tol_check = (atol,rtol,opt0) -> atol stop0.meta.unbounded_x = sqrt(6) stop!(stop0) @test status(stop0, list = true) == [:Optimal] #ok as ||x||_\infty = 1 < sqrt(6) -stop0.meta.norm_unbounded_x = 2 -stop!(stop0) -@test status(stop0, list = true) == [:Optimal, :Unbounded] #indeed ||x||_2 = sqrt(6) !! #We now test that stop! verifies that: #- there are no NaN in the score diff --git a/test/test-stopping/test-unitaire-stopping-meta.jl b/test/test-stopping/test-unitaire-stopping-meta.jl index de16f62b..ef2b7ff3 100644 --- a/test/test-stopping/test-unitaire-stopping-meta.jl +++ b/test/test-stopping/test-unitaire-stopping-meta.jl @@ -5,7 +5,6 @@ test_meta = StoppingMeta() @test test_meta.optimality_check(1,1) == Inf @test test_meta.unbounded_threshold == 1.0e50 @test test_meta.unbounded_x == 1.0e50 -@test test_meta.norm_unbounded_x == Inf @test test_meta.max_f == 9223372036854775807 @test test_meta.max_cntrs == Dict() @test test_meta.max_eval == 20_000