Skip to content

Commit

Permalink
Synced the source code
Browse files Browse the repository at this point in the history
  • Loading branch information
alberto-santini committed Oct 27, 2017
1 parent 209d04c commit f902a3a
Show file tree
Hide file tree
Showing 16 changed files with 186 additions and 40 deletions.
4 changes: 2 additions & 2 deletions source-code/branch-and-price/bb_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,15 +208,15 @@ 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) {
ub = std::min(ub, mip_sol->obj_value);
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;
Expand Down
2 changes: 1 addition & 1 deletion source-code/branch-and-price/branching_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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!");
Expand Down
2 changes: 1 addition & 1 deletion source-code/branch-and-price/branching_rules.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace sgcp {
public:
EmptyRule(std::shared_ptr<const Graph> g) : BranchingRule{g} {}
std::shared_ptr<const Graph> 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
Expand Down
2 changes: 1 addition & 1 deletion source-code/branch-and-price/mp_solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<double>(eps)) { columns[c.at(cid)] = val; }
}

if(lp) { for(auto k = 0u; k < g.n_partitions; k++) { duals[k] = cplex.getDual(colour[k]); } }
Expand Down
4 changes: 2 additions & 2 deletions source-code/decomposition/decomposition_model_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<IloNum>(eps)) {
cp[c].push_back(k);
}
}
Expand Down Expand Up @@ -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<IloNumVarArray>& x, IloNumVarArray& z) const {
void DecompositionModelHelper::set_initial_solution(const MpSolution& init, IloCplex& cplex, IloArray<IloNumVarArray>& x, IloNumVarArray& z) const {
IloNumVarArray initial_vars(env);
IloNumArray initial_vals(env);

Expand Down
2 changes: 1 addition & 1 deletion source-code/decomposition/decomposition_model_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace sgcp {
std::vector<IloRange> generate_constraint_for(IloArray<IloNumVarArray>& x, const PartitionsIdVec& p) const;
void add_all_3incompatible_cuts(IloArray<IloNumVarArray>& x);
void add_best_3incompatible_cuts(IloArray<IloNumVarArray>& x);
void set_initial_solution(const MpSolution& init, IloCplex& cplex, IloRangeArray& link, IloRangeArray& col, IloRangeArray& clique, IloArray<IloNumVarArray>& x, IloNumVarArray& z) const;
void set_initial_solution(const MpSolution& init, IloCplex& cplex, IloArray<IloNumVarArray>& x, IloNumVarArray& z) const;
void try_initial_solution_from_file(std::string filename, IloCplex& cplex, IloRangeArray& link, IloRangeArray& col, IloRangeArray& clique, IloArray<IloNumVarArray>& 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} {}
Expand Down
2 changes: 1 addition & 1 deletion source-code/decomposition/decomposition_solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
10 changes: 8 additions & 2 deletions source-code/heuristics/alns/acceptance.cpp
Original file line number Diff line number Diff line change
@@ -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();
}

Expand Down
38 changes: 28 additions & 10 deletions source-code/heuristics/alns/alns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<StableSetCollection> initial, float* elapsed_time) {
ALNSColouring ALNSSolver::solve(boost::optional<StableSetCollection> initial, float* elapsed_time, ALNSStats* stats) {
// Iteration counter.
uint32_t current_iteration = 0;

Expand All @@ -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);
Expand All @@ -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.
Expand All @@ -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.
Expand Down
13 changes: 8 additions & 5 deletions source-code/heuristics/alns/alns.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "repair.hpp"
#include "acceptance.hpp"
#include "local_search.hpp"
#include "alns_stats.h"

#include <vector>
#include <random>
Expand Down Expand Up @@ -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<StableSetCollection> 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<StableSetCollection> 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
Expand Down
79 changes: 79 additions & 0 deletions source-code/heuristics/alns/alns_stats.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//
// Created by alberto on 14/09/17.
//

#include "alns_stats.h"

#include <iostream>
#include <cassert>

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<uint32_t, float> destroy_tot;
std::map<uint32_t, float> 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);
}
}
31 changes: 31 additions & 0 deletions source-code/heuristics/alns/alns_stats.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// Created by alberto on 14/09/17.
//

#ifndef SGCP_ALNS_STATS_H
#define SGCP_ALNS_STATS_H

#include <vector>
#include <map>
#include <cstdint>

namespace sgcp {
class ALNSStats {
std::vector<uint32_t> destroy_methods;
std::vector<uint32_t> repair_methods;
std::vector<bool> accepted;
std::map<uint32_t, float> destroy_pct_accept;
std::map<uint32_t, float> 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
30 changes: 19 additions & 11 deletions source-code/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
#include <chrono>
#include <utils/cache.hpp>

std::array<std::string, 9> solvers = {
std::array<std::string, 10> 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
Expand Down Expand Up @@ -72,17 +73,22 @@ void solve_greedy(std::shared_ptr<sgcp::Graph> g) {
std::cout << g->data_filename << "," << sol.size() << std::endl;
}

void solve_alns(std::shared_ptr<sgcp::Graph> g) {
void solve_alns(std::shared_ptr<sgcp::Graph> 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);
}
Expand Down Expand Up @@ -119,7 +125,7 @@ void solve_decomposition(std::shared_ptr<sgcp::Graph> 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];
Expand Down Expand Up @@ -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") {
Expand Down
4 changes: 2 additions & 2 deletions source-code/mwss/sewell_mwss_solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,14 @@ namespace sgcp {

// DEBUG_ONLY(std::cout << "Sewell MWSS Solution: " << static_cast<float>(m_data.best_z) / static_cast<float>(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++) {
Expand Down
Loading

0 comments on commit f902a3a

Please sign in to comment.