From c28e3101650b980219eb9ad6aa019c4c18143800 Mon Sep 17 00:00:00 2001 From: Jean-Francois Baffier Date: Mon, 12 Aug 2024 20:13:55 +0900 Subject: [PATCH 1/3] Dev (#131) * CI and other small fixes (#120) * Update compat and CI (#115) * Fixes for a demo * Cleaning unused files. Added Aqua and other CI * spelling * New version * Fix an issue when restarting (#122) * Update Project.toml * Compat, CI, and threads (#126) * Add an optional sat requirement for stopping the solver (#129) * Sat stop (#130) * Add an optional sat requirement for stopping the solver * Fixes stop with sat condition, opt runs * Update sub.jl * Update Project.toml --- Project.toml | 2 +- src/options.jl | 38 +++++++++++++++++++++++++------------- src/solvers/lead.jl | 2 +- src/solvers/main.jl | 17 +++++++++++------ src/solvers/sub.jl | 2 +- 5 files changed, 39 insertions(+), 22 deletions(-) diff --git a/Project.toml b/Project.toml index 8cf79d7..5a2e02b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "LocalSearchSolvers" uuid = "2b10edaa-728d-4283-ac71-07e312d6ccf3" authors = ["Jean-Francois Baffier"] -version = "0.4.7" +version = "0.4.8" [deps] CompositionalNetworks = "4b67e4b5-442d-4ef5-b760-3f5df3a57537" diff --git a/src/options.jl b/src/options.jl index 2b33676..8b6e972 100644 --- a/src/options.jl +++ b/src/options.jl @@ -5,11 +5,6 @@ const print_levels = Dict( :verbose => 3 ) -# # Tabu times -# get!(s, :tabu_time, length_vars(s) ÷ 2) # 10? -# get!(s, :local_tabu, setting(s, :tabu_time) ÷ 2) -# get!(s, :δ_tabu, setting(s, :tabu_time) - setting(s, :local_tabu))# 20-30 - """ Options() # Arguments: @@ -36,7 +31,7 @@ set_time_limit_sec(model, 5.0) mutable struct Options dynamic::Bool info_path::String - iteration::Union{Int, Float64} + iteration::Tuple{Bool, Union{Int, Float64}} print_level::Symbol process_threads_map::Dict{Int, Int} solutions::Int @@ -44,12 +39,12 @@ mutable struct Options tabu_time::Int tabu_local::Int tabu_delta::Float64 - time_limit::Float64 # seconds + time_limit::Tuple{Bool, Float64} # seconds function Options(; dynamic = false, info_path = "", - iteration = 10000, + iteration = (false, 100), print_level = :minimal, process_threads_map = Dict{Int, Int}(1 => typemax(0)), solutions = 1, @@ -57,7 +52,7 @@ mutable struct Options tabu_time = 0, tabu_local = 0, tabu_delta = 0.0, - time_limit = 60 # seconds + time_limit = (false, 1.0) # seconds ) ds_str = "The model types are specialized to the starting domains, constraints," * " and objectives types. Dynamic elements that add a new type will raise an error!" @@ -69,12 +64,25 @@ mutable struct Options itertime_str = "Both iteration and time limits are disabled. " * "Optimization runs will run infinitely." - iteration == Inf && time_limit == Inf && @warn itertime_str + + new_iteration = if iteration isa Tuple{Bool, Union{Int, Float64}} + iteration + else + iteration = (false, iteration) + end + + new_time_limit = if time_limit isa Tuple{Bool, Float64} + time_limit + else + time_limit = (false, time_limit) + end + + new_iteration[2] == Inf && new_time_limit[2] == Inf && @warn itertime_str new( dynamic, info_path, - iteration, + new_iteration, print_level, process_threads_map, solutions, @@ -82,7 +90,7 @@ mutable struct Options tabu_time, tabu_local, tabu_delta, - time_limit + new_time_limit ) end end @@ -137,6 +145,9 @@ _iteration(options) = options.iteration DOCSTRING """ _iteration!(options, iterations) = options.iteration = iterations +function _iteration!(options, iterations::Union{Int, Float64}) + options.iteration = (false, iterations) +end """ _print_level(options) = begin @@ -266,7 +277,8 @@ _time_limit(options) = options.time_limit DOCSTRING """ -_time_limit!(options, time) = options.time_limit = time +_time_limit!(options, time::Tuple{Bool, Float64}) = options.time_limit = time +_time_limit!(options, time::Float64) = options.time_limit = (false, time) function set_option!(options, name, value) eval(Symbol("_" * name * "!"))(options, value) diff --git a/src/solvers/lead.jl b/src/solvers/lead.jl index 020d1b4..90e366f 100644 --- a/src/solvers/lead.jl +++ b/src/solvers/lead.jl @@ -18,7 +18,7 @@ end function solver( mlid, model, options, pool, rc_report, rc_sol, rc_stop, strats, ::Val{:lead}) l_options = deepcopy(options) - set_option!(options, "print_level", :silent) + set_option!(l_options, "print_level", :silent) ss = Vector{_SubSolver}() return LeadSolver( mlid, model, l_options, pool, rc_report, rc_sol, rc_stop, state(), strats, ss) diff --git a/src/solvers/main.jl b/src/solvers/main.jl index ac3536e..abe8f30 100644 --- a/src/solvers/main.jl +++ b/src/solvers/main.jl @@ -71,21 +71,26 @@ function _init!(s::MainSolver) end function stop_while_loop(s::MainSolver, ::Atomic{Bool}, iter, start_time) - remote_limit = isready(s.rc_stop) # Add ! when MainSolver is passive - iter_limit = iter < get_option(s, "iteration") - time_limit = time() - start_time < get_option(s, "time_limit") - if !remote_limit + @debug "debug stop" iter (time()-start_time) + if !isready(s.rc_stop) s.status = :solution_limit return false end - if !iter_limit + + iter_sat = get_option(s, "iteration")[1] && has_solution(s) + iter_limit = iter > get_option(s, "iteration")[2] + if (iter_sat && iter_limit) || iter_limit s.status = :iteration_limit return false end - if !time_limit + + time_sat = get_option(s, "time_limit")[1] && has_solution(s) + time_limit = time() - start_time > get_option(s, "time_limit")[2] + if (time_sat && time_limit) || time_limit s.status = :time_limit return false end + return true end diff --git a/src/solvers/sub.jl b/src/solvers/sub.jl index b6c883f..fb9d7f1 100644 --- a/src/solvers/sub.jl +++ b/src/solvers/sub.jl @@ -21,7 +21,7 @@ end function solver(mlid, model, options, pool, ::RemoteChannel, ::RemoteChannel, ::RemoteChannel, strats, ::Val{:sub}) sub_options = deepcopy(options) - set_option!(options, "print_level", :silent) + set_option!(sub_options, "print_level", :silent) return _SubSolver(mlid, model, sub_options, pool, state(), strats) end From 10ddc90ef026a2a1de43ce6ad7f38585d3184b41 Mon Sep 17 00:00:00 2001 From: Azzaare Date: Thu, 15 Aug 2024 04:19:18 +0000 Subject: [PATCH 2/3] Enforce a non-empty pool at initialization of an optimization run --- src/configuration.jl | 1 - src/model.jl | 6 ++---- src/pool.jl | 4 ++++ src/solver.jl | 4 +++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/configuration.jl b/src/configuration.jl index a457352..8afc24a 100644 --- a/src/configuration.jl +++ b/src/configuration.jl @@ -12,7 +12,6 @@ get_values(c) = c.values get_value(c, x) = get_values(c)[x] set_value!(c, val) = c.value = val -# set_value!(c, x, val) = get_values(c)[x] = val set_values!(c, values) = c.values = values set_sat!(c, b) = c.solution = b diff --git a/src/model.jl b/src/model.jl index 9244ab6..0086a2e 100644 --- a/src/model.jl +++ b/src/model.jl @@ -250,13 +250,11 @@ Add `x` to the constraint `c` list of restricted variables. """ add_var_to_cons!(m::_Model, c, x) = _add!(get_constraint(m, c), x) -""" mts = - get_time_stamp(model) -return TimeStamps(mts, mts, mts, mts, mts, mts, mts) -end - +""" add!(m::M, x) where M <: Union{Model, AbstractSolver} add!(m::M, c) where M <: Union{Model, AbstractSolver} add!(m::M, o) where M <: Union{Model, AbstractSolver} + Add a variable `x`, a constraint `c`, or an objective `o` to `m`. """ function add!(m::_Model, x::Variable) diff --git a/src/pool.jl b/src/pool.jl index f50d99c..3dd7267 100644 --- a/src/pool.jl +++ b/src/pool.jl @@ -21,6 +21,10 @@ function pool(config::Configuration) value = get_value(config) return _Pool(best, configs, status, value) end +function pool!(s) + has_solution(s) || _draw!(s) + s.pool = pool(s.state.configuration) +end is_empty(::EmptyPool) = true is_empty(pool) = isempty(pool.configurations) diff --git a/src/solver.jl b/src/solver.jl index 7aa2ea4..c57414f 100644 --- a/src/solver.jl +++ b/src/solver.jl @@ -238,13 +238,15 @@ function _init!(s, ::Val{:remote}) end end -function _init!(s, ::Val{:local}; pool = pool()) +function _init!(s, ::Val{:local}) get_option(s, "tabu_time") == 0 && set_option!(s, "tabu_time", length_vars(s) ÷ 2) # 10? get_option(s, "tabu_local") == 0 && set_option!(s, "tabu_local", get_option(s, "tabu_time") ÷ 2) get_option(s, "tabu_delta") == 0 && set_option!( s, "tabu_delta", get_option(s, "tabu_time") - get_option(s, "tabu_local")) # 20-30 state!(s) + @warn "Debug" typeof(s) s + pool!(s) return has_solution(s) end From 1d6580d4f7a31da4dfb93b5514ae013d11c0de6d Mon Sep 17 00:00:00 2001 From: Azzaare Date: Thu, 15 Aug 2024 08:21:54 +0000 Subject: [PATCH 3/3] Fix collecting pools of solution for // computing. Fix termination of remote processes --- src/solver.jl | 1 - src/solvers/lead.jl | 12 ++---------- src/solvers/main.jl | 23 +++++++++++++++++++++++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/solver.jl b/src/solver.jl index c57414f..0dd4925 100644 --- a/src/solver.jl +++ b/src/solver.jl @@ -245,7 +245,6 @@ function _init!(s, ::Val{:local}) get_option(s, "tabu_delta") == 0 && set_option!( s, "tabu_delta", get_option(s, "tabu_time") - get_option(s, "tabu_local")) # 20-30 state!(s) - @warn "Debug" typeof(s) s pool!(s) return has_solution(s) end diff --git a/src/solvers/lead.jl b/src/solvers/lead.jl index 90e366f..801d702 100644 --- a/src/solvers/lead.jl +++ b/src/solvers/lead.jl @@ -33,14 +33,6 @@ stop_while_loop(s::LeadSolver, ::Atomic{Bool}, ::Int, ::Float64) = isready(s.rc_ function remote_stop!(s::LeadSolver) isready(s.rc_stop) && take!(s.rc_stop) - sat = is_sat(s) - if !sat || !has_solution(s) - while isready(s.rc_report) - wait(s.rc_sol) - t = take!(s.rc_sol) - update_pool!(s, t) - sat && has_solution(t) && break - take!(s.rc_report) - end - end + put!(s.rc_sol, s.pool) + take!(s.rc_report) end diff --git a/src/solvers/main.jl b/src/solvers/main.jl index abe8f30..ff5e08f 100644 --- a/src/solvers/main.jl +++ b/src/solvers/main.jl @@ -116,3 +116,26 @@ function post_process(s::MainSolver) write(path, JSON.json(info)) end end + +function remote_stop!(s::MainSolver) + isready(s.rc_stop) && take!(s.rc_stop) + sat = is_sat(s) + @info "Remote stop: report main pool" best_values(s.pool) has_solution(s) s.rc_report s.rc_sol s.rc_stop length(s.remotes) + if !sat || !has_solution(s) + @warn "debugging remote stop" nworkers() length(s.remotes) + while isready(s.rc_report) || isready(s.rc_sol) + wait(s.rc_sol) + t = take!(s.rc_sol) + @info "Remote stop: report remote pool" best_values(t) length(s.remotes) + update_pool!(s, t) + if sat && has_solution(t) + empty!(s.rc_report) + break + end + @info "mark 1" + isready(s.rc_report) && take!(s.rc_report) + @info "mark 2" + end + end + @info "Remote stop: report best pool" best_values(s.pool) length(s.remotes) +end