From f902a3abc8792d633888b1715977c05f360e15db Mon Sep 17 00:00:00 2001 From: alberto-santini Date: Fri, 27 Oct 2017 22:33:22 +0200 Subject: [PATCH] Synced the source code --- source-code/branch-and-price/bb_node.cpp | 4 +- .../branch-and-price/branching_helper.cpp | 2 +- .../branch-and-price/branching_rules.hpp | 2 +- source-code/branch-and-price/mp_solver.cpp | 2 +- .../decomposition_model_helper.cpp | 4 +- .../decomposition_model_helper.hpp | 2 +- .../decomposition/decomposition_solver.cpp | 2 +- source-code/heuristics/alns/acceptance.cpp | 10 ++- source-code/heuristics/alns/alns.cpp | 38 ++++++--- source-code/heuristics/alns/alns.hpp | 13 +-- source-code/heuristics/alns/alns_stats.cpp | 79 +++++++++++++++++++ source-code/heuristics/alns/alns_stats.h | 31 ++++++++ source-code/main.cpp | 30 ++++--- source-code/mwss/sewell_mwss_solver.cpp | 4 +- source-code/mwss/sewell_mwss_solver.hpp | 2 +- source-code/stable_set.cpp | 1 + 16 files changed, 186 insertions(+), 40 deletions(-) create mode 100755 source-code/heuristics/alns/alns_stats.cpp create mode 100755 source-code/heuristics/alns/alns_stats.h diff --git a/source-code/branch-and-price/bb_node.cpp b/source-code/branch-and-price/bb_node.cpp index 0f18264..79cd6a3 100644 --- a/source-code/branch-and-price/bb_node.cpp +++ b/source-code/branch-and-price/bb_node.cpp @@ -208,7 +208,7 @@ namespace sgcp { std::all_of( mip_cols.begin(), mip_cols.end(), - [this] (const auto& id_coeff) { return (id_coeff.second < 0.5 || !c.get().at(id_coeff.first).dummy); } + [this] (const auto& id_coeff) { return (id_coeff.second < 0.5f || !c.get().at(id_coeff.first).dummy); } ); if(mip_sol_feasible) { @@ -216,7 +216,7 @@ namespace sgcp { integer_solution_columns = mip_cols; if( g->params.mip_heur_alns && - ub - std::ceil(lb) > .5 // Otherwise we just found the optimal solution with MIP, no need for ALNS + ub - std::ceil(lb) > 0.5f // Otherwise we just found the optimal solution with MIP, no need for ALNS ) { // Try to improve on the MIP solution with ALNS ColumnPool initial_solution; diff --git a/source-code/branch-and-price/branching_helper.cpp b/source-code/branch-and-price/branching_helper.cpp index e2285b8..3ec0c0f 100644 --- a/source-code/branch-and-price/branching_helper.cpp +++ b/source-code/branch-and-price/branching_helper.cpp @@ -147,7 +147,7 @@ namespace sgcp { for(const auto& cidval : sol.lp_solution_columns) { const StableSet& s = column_pool.at(cidval.first); - float fractionality = std::abs(cidval.second - 0.5); + float fractionality = std::abs(cidval.second - 0.5f); if(s.dummy) { throw std::runtime_error("vertex_in_most_fractional_column_that_covers_partition: Base solution contains dummy column!"); diff --git a/source-code/branch-and-price/branching_rules.hpp b/source-code/branch-and-price/branching_rules.hpp index 04cbc14..e800497 100644 --- a/source-code/branch-and-price/branching_rules.hpp +++ b/source-code/branch-and-price/branching_rules.hpp @@ -33,7 +33,7 @@ namespace sgcp { public: EmptyRule(std::shared_ptr g) : BranchingRule{g} {} std::shared_ptr apply() const { return g; } - bool is_compatible(const StableSet& s) const { return true; } + bool is_compatible(const StableSet& s [[maybe_unused]]) const { return true; } }; // Removes certain vertices from the graph diff --git a/source-code/branch-and-price/mp_solver.cpp b/source-code/branch-and-price/mp_solver.cpp index e2dd0a1..4f22dd8 100644 --- a/source-code/branch-and-price/mp_solver.cpp +++ b/source-code/branch-and-price/mp_solver.cpp @@ -66,7 +66,7 @@ namespace sgcp { for(auto cid = 0u; cid < c.size(); cid++) { auto val = cplex.getValue(x[cid]); - if(val > eps) { columns[c.at(cid)] = val; } + if(val > static_cast(eps)) { columns[c.at(cid)] = val; } } if(lp) { for(auto k = 0u; k < g.n_partitions; k++) { duals[k] = cplex.getDual(colour[k]); } } diff --git a/source-code/decomposition/decomposition_model_helper.cpp b/source-code/decomposition/decomposition_model_helper.cpp index 3b7f51f..bc889aa 100644 --- a/source-code/decomposition/decomposition_model_helper.cpp +++ b/source-code/decomposition/decomposition_model_helper.cpp @@ -134,7 +134,7 @@ namespace sgcp { for(auto k = 0u; k < g.n_partitions; k++) { for(auto c = 0u; c < std::min(k+1, ub); c++) { - if(cplex.getValue(x[k][c]) > eps) { + if(cplex.getValue(x[k][c]) > static_cast(eps)) { cp[c].push_back(k); } } @@ -267,7 +267,7 @@ namespace sgcp { initial_vals.end(); } - void DecompositionModelHelper::set_initial_solution(const MpSolution& init, IloCplex& cplex, IloRangeArray& link, IloRangeArray& col, IloRangeArray& clique, IloArray& x, IloNumVarArray& z) const { + void DecompositionModelHelper::set_initial_solution(const MpSolution& init, IloCplex& cplex, IloArray& x, IloNumVarArray& z) const { IloNumVarArray initial_vars(env); IloNumArray initial_vals(env); diff --git a/source-code/decomposition/decomposition_model_helper.hpp b/source-code/decomposition/decomposition_model_helper.hpp index bea9e23..8a3df06 100644 --- a/source-code/decomposition/decomposition_model_helper.hpp +++ b/source-code/decomposition/decomposition_model_helper.hpp @@ -30,7 +30,7 @@ namespace sgcp { std::vector generate_constraint_for(IloArray& x, const PartitionsIdVec& p) const; void add_all_3incompatible_cuts(IloArray& x); void add_best_3incompatible_cuts(IloArray& x); - void set_initial_solution(const MpSolution& init, IloCplex& cplex, IloRangeArray& link, IloRangeArray& col, IloRangeArray& clique, IloArray& x, IloNumVarArray& z) const; + void set_initial_solution(const MpSolution& init, IloCplex& cplex, IloArray& x, IloNumVarArray& z) const; void try_initial_solution_from_file(std::string filename, IloCplex& cplex, IloRangeArray& link, IloRangeArray& col, IloRangeArray& clique, IloArray& x, IloNumVarArray& z) const; DecompositionModelHelper(const Graph& g, IloEnv& env, IloModel& model, const DecompositionGraphHelper& gh, uint32_t ub) : g{g}, env{env}, model{model}, gh{gh}, ub{ub} {} diff --git a/source-code/decomposition/decomposition_solver.cpp b/source-code/decomposition/decomposition_solver.cpp index fd21849..5e81b89 100644 --- a/source-code/decomposition/decomposition_solver.cpp +++ b/source-code/decomposition/decomposition_solver.cpp @@ -160,7 +160,7 @@ namespace sgcp { cplex.setWarning(env.getNullStream()); if(initial_solution) { - mh.set_initial_solution(*initial_solution, cplex, link, col, clique, x, z); + mh.set_initial_solution(*initial_solution, cplex, x, z); } while(true) { diff --git a/source-code/heuristics/alns/acceptance.cpp b/source-code/heuristics/alns/acceptance.cpp index e0ed887..b3a19cf 100644 --- a/source-code/heuristics/alns/acceptance.cpp +++ b/source-code/heuristics/alns/acceptance.cpp @@ -1,11 +1,17 @@ #include "acceptance.hpp" namespace sgcp { - bool AcceptEverything::operator()(const ALNSColouring& current, const ALNSColouring& incumbent, uint32_t iteration_number) const { + bool AcceptEverything::operator()( + const ALNSColouring& current [[maybe_unused]], + const ALNSColouring& incumbent [[maybe_unused]], + uint32_t iteration_number [[maybe_unused]]) const { return true; } - bool AcceptNonDeteriorating::operator()(const ALNSColouring& current, const ALNSColouring& incumbent, uint32_t iteration_number) const { + bool AcceptNonDeteriorating::operator()( + const ALNSColouring& current, + const ALNSColouring& incumbent, + uint32_t iteration_number [[maybe_unused]]) const { return incumbent.score() <= current.score(); } diff --git a/source-code/heuristics/alns/alns.cpp b/source-code/heuristics/alns/alns.cpp index c85e26e..8542250 100644 --- a/source-code/heuristics/alns/alns.cpp +++ b/source-code/heuristics/alns/alns.cpp @@ -67,18 +67,18 @@ namespace sgcp { acceptance = nullptr; } - if(g.params.alns_acceptance == "accept_everything") { + if(ac_description == "accept_everything") { acceptance = new AcceptEverything{}; - } else if(g.params.alns_acceptance == "accept_non_deteriorating") { + } else if(ac_description == "accept_non_deteriorating") { acceptance = new AcceptNonDeteriorating{}; - } else if(g.params.alns_acceptance == "worse_accept") { + } else if(ac_description == "worse_accept") { acceptance = new WorseAccept{g.params.alns_wa_initial_probability, max_iterations}; } else { throw "Acceptance criterion not recognised!"; } } - ALNSColouring ALNSSolver::solve(boost::optional initial, float* elapsed_time) { + ALNSColouring ALNSSolver::solve(boost::optional initial, float* elapsed_time, ALNSStats* stats) { // Iteration counter. uint32_t current_iteration = 0; @@ -105,6 +105,12 @@ namespace sgcp { auto destroy_id = roulette_wheel(destroy_score); auto repair_id = roulette_wheel(repair_score); + // Record statistics on the chosen methods. + if(stats) { + stats->add_destroy(destroy_id); + stats->add_repair(repair_id); + } + // Apply the destroy and repair methods, to obtain a new // solution. (*destroy[destroy_id])(incumbent); @@ -115,6 +121,11 @@ namespace sgcp { // If the new solution is accepted: if((*acceptance)(current, incumbent, current_iteration)) { + // Record statistics on acceptance + if(stats) { + stats->add_accepted(); + } + // If the new solution improves on the best currently known: if(incumbent.score() < best.score()) { // Update best and scores accordingly. @@ -131,12 +142,19 @@ namespace sgcp { // In any case, since the new move was accepted, it will // replace the current. current = incumbent; - } else if(incumbent.score() > current.score()) { - // If the new move was not accepted and it actually has - // a worse score than the current: - // Update the scores accordingly. - update_score_found_worse(destroy_id, destroy_score); - update_score_found_worse(repair_id, repair_score); + } else { + // Record statistics on acceptance + if(stats) { + stats->add_rejected(); + } + + if(incumbent.score() > current.score()) { + // If the new move was not accepted and it actually has + // a worse score than the current: + // Update the scores accordingly. + update_score_found_worse(destroy_id, destroy_score); + update_score_found_worse(repair_id, repair_score); + } } // Check if there is any move that should get out of the tabu list. diff --git a/source-code/heuristics/alns/alns.hpp b/source-code/heuristics/alns/alns.hpp index 3e43183..b80a40b 100644 --- a/source-code/heuristics/alns/alns.hpp +++ b/source-code/heuristics/alns/alns.hpp @@ -9,6 +9,7 @@ #include "repair.hpp" #include "acceptance.hpp" #include "local_search.hpp" +#include "alns_stats.h" #include #include @@ -68,12 +69,14 @@ namespace sgcp { // Creates an initial solution, by first calling the constructive heuristics. ALNSColouring initial_solution() const; - // Runs the ALNS for ``max_iterations'' iterations and returns the best colouring. - // You can optionally pass an initial solution. If you don't (i.e. pass nullptr - // as the second argument), the constructive heuristics are called to generate - // the initial solution. You can also pass a pointer to a float where we will store + // Runs ALNS and returns the best colouring. + // You can optionally pass an initial solution. If you don't, the constructive + // heuristics are called to generate the initial solution. + // You can also pass a pointer to a float where we will store // the elapsed time in seconds (this is optional). - ALNSColouring solve(boost::optional initial = boost::none, float* elapsed_time = nullptr); + // You can also pass a pointer to an ALNSStats object to record + // statistics about the solution process (this is optional). + ALNSColouring solve(boost::optional initial = boost::none, float* elapsed_time = nullptr, ALNSStats* stats = nullptr); // Gives the index of an element of vec, selected according to roulette // wheel selection, where the probabilities are proportional to the values diff --git a/source-code/heuristics/alns/alns_stats.cpp b/source-code/heuristics/alns/alns_stats.cpp new file mode 100755 index 0000000..40d8e17 --- /dev/null +++ b/source-code/heuristics/alns/alns_stats.cpp @@ -0,0 +1,79 @@ +// +// Created by alberto on 14/09/17. +// + +#include "alns_stats.h" + +#include +#include + +namespace sgcp { + void ALNSStats::print_stats() { + compute_maps(); + + std::cout << "Repair methods:" << std::endl; + for (auto [key, val] : repair_pct_accept) { + std::cout << key << ", " << val << std::endl; + } + std::cout << "Destroy methods:" << std::endl; + for (auto [key, val] : destroy_pct_accept) { + std::cout << key << ", " << val << std::endl; + } + } + + void ALNSStats::compute_maps() { + assert(repair_methods.size() == destroy_methods.size()); + assert(accepted.size() == destroy_methods.size()); + + auto has_key = [] (const auto& map, uint32_t key) -> bool { + return map.find(key) != map.end(); + }; + + auto set_val = [&has_key] (auto& map, uint32_t key, float val) -> void { + if (!has_key(map, key)) { map[key] = 0.0f; } + map[key] += val; + }; + + std::map destroy_tot; + std::map repair_tot; + + for (auto i = 0u; i < accepted.size(); ++i) { + auto destroy = destroy_methods[i]; + auto repair = repair_methods[i]; + + set_val(destroy_tot, destroy, 1.0); + set_val(repair_tot, repair, 1.0); + + if (accepted[i]) { + set_val(destroy_pct_accept, destroy, 1.0); + set_val(repair_pct_accept, repair, 1.0); + } + } + + for(auto [key, val] : destroy_pct_accept) { + std::cout << "destroy method " << key << " was called " << destroy_tot[key] << " times, and the solution was accepted " << val << " times." << std::endl; + destroy_pct_accept[key] = val / destroy_tot[key]; + } + + for(auto [key, val] : repair_pct_accept) { + std::cout << "repair method " << key << " was called " << repair_tot[key] << " times, and the solution was accepted " << val << " times." << std::endl; + repair_pct_accept[key] = val / repair_tot[key]; + } + } + + void ALNSStats::add_destroy(uint32_t method_id) { + destroy_methods.push_back(method_id); + } + + void ALNSStats::add_repair(uint32_t method_id) { + repair_methods.push_back(method_id); + } + + void ALNSStats::add_accepted() { + accepted.push_back(true); + } + + void ALNSStats::add_rejected() { + accepted.push_back(false); + } +} \ No newline at end of file diff --git a/source-code/heuristics/alns/alns_stats.h b/source-code/heuristics/alns/alns_stats.h new file mode 100755 index 0000000..9cb921b --- /dev/null +++ b/source-code/heuristics/alns/alns_stats.h @@ -0,0 +1,31 @@ +// +// Created by alberto on 14/09/17. +// + +#ifndef SGCP_ALNS_STATS_H +#define SGCP_ALNS_STATS_H + +#include +#include +#include + +namespace sgcp { + class ALNSStats { + std::vector destroy_methods; + std::vector repair_methods; + std::vector accepted; + std::map destroy_pct_accept; + std::map repair_pct_accept; + + void compute_maps(); + + public: + void add_destroy(uint32_t method_id); + void add_repair(uint32_t method_id); + void add_accepted(); + void add_rejected(); + void print_stats(); + }; +} + +#endif //SGCP_ALNS_STATS_H diff --git a/source-code/main.cpp b/source-code/main.cpp index b40b78b..9a5ccc5 100644 --- a/source-code/main.cpp +++ b/source-code/main.cpp @@ -13,12 +13,13 @@ #include #include -std::array solvers = { +std::array solvers = { "bp", // Branch-and-price "campelo", // Campelo's representatives model "compact", // Compact formulation without representatives "greedy", // Greedy initial heuristics "alns", // ALNS heuristic + "alns-stats", // ALNS heuristic with stats "tabu", // TABU Search heuristic "grasp", // GRASP heuristic "decomposition", // Benders-like decomposition solver @@ -72,17 +73,22 @@ void solve_greedy(std::shared_ptr g) { std::cout << g->data_filename << "," << sol.size() << std::endl; } -void solve_alns(std::shared_ptr g) { +void solve_alns(std::shared_ptr g, bool print_stats) { sgcp::ALNSSolver solver{*g}; + sgcp::ALNSStats stats; float elapsed_time = 0; - auto sol = solver.solve(boost::none, &elapsed_time); + auto sol = solver.solve(boost::none, &elapsed_time, print_stats ? &stats : nullptr); - std::cout << g->data_filename << "," - << g->params.alns_acceptance << "," - << g->params.tabu_tenure << "," - << g->params.alns_wa_initial_probability << "," - << elapsed_time << "," - << sol.n_colours << std::endl; + if(print_stats) { + stats.print_stats(); + } else { + std::cout << g->data_filename << "," + << g->params.alns_acceptance << "," + << g->params.tabu_tenure << "," + << g->params.alns_wa_initial_probability << "," + << elapsed_time << "," + << sol.n_colours << std::endl; + } sgcp::cache::bks_update_cache(sol.to_column_pool(), *g); } @@ -119,7 +125,7 @@ void solve_decomposition(std::shared_ptr g) { c.solve(); } -int main(int argc, char* argv[]) { +int main(int argc [[maybe_unused]], char* argv[]) { using namespace sgcp; std::string params_file = argv[1]; @@ -152,7 +158,9 @@ int main(int argc, char* argv[]) { } else if(solver == "greedy") { solve_greedy(g); } else if(solver == "alns") { - solve_alns(g); + solve_alns(g, false); + } else if(solver == "alns-stats") { + solve_alns(g, true); } else if(solver == "tabu") { solve_tabu(g); } else if(solver == "grasp") { diff --git a/source-code/mwss/sewell_mwss_solver.cpp b/source-code/mwss/sewell_mwss_solver.cpp index 7fc1681..08653c2 100644 --- a/source-code/mwss/sewell_mwss_solver.cpp +++ b/source-code/mwss/sewell_mwss_solver.cpp @@ -77,14 +77,14 @@ namespace sgcp { // DEBUG_ONLY(std::cout << "Sewell MWSS Solution: " << static_cast(m_data.best_z) / static_cast(multiplier) << std::endl;) - s = make_stable_set(m_graph, m_data); + s = make_stable_set(m_data); CLEANUP: free_max_wstable(&m_graph, &m_data, &m_info); return s; } - StableSet SewellMwssSolver::make_stable_set(const MWSSgraph& m_graph, const MWSSdata& m_data) const { + StableSet SewellMwssSolver::make_stable_set(const MWSSdata& m_data) const { VertexIdSet s; for(auto i = 1; i <= m_data.n_best; i++) { diff --git a/source-code/mwss/sewell_mwss_solver.hpp b/source-code/mwss/sewell_mwss_solver.hpp index 6fec43c..e50716a 100644 --- a/source-code/mwss/sewell_mwss_solver.hpp +++ b/source-code/mwss/sewell_mwss_solver.hpp @@ -27,7 +27,7 @@ namespace sgcp { static constexpr float eps = 1e-6; void calculate_int_weights(const WeightMap& w); - StableSet make_stable_set(const MWSSgraph& m_graph, const MWSSdata& m_data) const; + StableSet make_stable_set(const MWSSdata& m_data) const; public: SewellMwssSolver(const Graph& o, const Graph& g, WeightMap w); diff --git a/source-code/stable_set.cpp b/source-code/stable_set.cpp index c36ccc9..910709b 100644 --- a/source-code/stable_set.cpp +++ b/source-code/stable_set.cpp @@ -73,6 +73,7 @@ namespace sgcp { } ); + assert(it != s.end()); return *it; }