From f45fd830ffe385e964b82f1b799c1dcb09f872f5 Mon Sep 17 00:00:00 2001 From: p-hamann <p.hamann@dareit.de> Date: Tue, 23 Apr 2019 17:45:42 +0200 Subject: [PATCH] Refactor bnb --- bnb/bnb.cpp | 78 ++++++++++------------------------------- include/gp-bnb/bnb.hpp | 79 ++++++++++-------------------------------- 2 files changed, 36 insertions(+), 121 deletions(-) diff --git a/bnb/bnb.cpp b/bnb/bnb.cpp index 7975382..66e1bbd 100644 --- a/bnb/bnb.cpp +++ b/bnb/bnb.cpp @@ -7,46 +7,11 @@ static constexpr bool verbose = false; namespace gp_bnb { -// -------------------------------------------------------------------------------------- -// assignment_state implementation. -// -------------------------------------------------------------------------------------- - -void assignment_state::resize_nodes(size_t count) { - assigned_partition_.resize(count, illegal_partition); - //fill_state_.resize(count); -} - -void assignment_state::assign(vertex_id node, partition_index p, std::vector<unsigned int> neighbors) { - assert(assigned_partition_[node] == illegal_partition); - assert(p >= 0); - - assigned_partition_[node] = p; - //for each neighbor of node in other partitions: current_objective++ - for(auto neighbor: neighbors){ - if(assigned_partition_[neighbor] == (p xor 1)) - current_objective_++; - } - node_count[p]++; -} - -void assignment_state::unassign(vertex_id node, std::vector<unsigned int> neighbors) { - assert(assigned_partition_[node] != illegal_partition); - auto p = assigned_partition_[node]; - - assigned_partition_[node] = illegal_partition; - //for each neighbor of node in other partitions: current_objective-- - for(vertex_id neighbor : neighbors){ - if(assigned_partition_[neighbor] == (p xor 1)) - current_objective_--; - } - node_count[p]--; -} - // -------------------------------------------------------------------------------------- // trail_state implementation. // -------------------------------------------------------------------------------------- -void trail_state::push_node(vertex_id node, partition_index alt) { +void trail_state::push_node(vertex_id node, subgraph alt) { stack_.push_back({node, alt}); } @@ -58,14 +23,7 @@ void trail_state::pop() { // solver implementation. // -------------------------------------------------------------------------------------- - -void solver::resize_nodes(size_t count) { - //nodes_.resize_nodes(count); - assignment_.resize_nodes(count); -} - -void solver::define_graph(graph& g){ - nodes_ = g; +solver::solver(graph& g) : nodes_(g), partition_(partition{g}) { } void solver::solve() { @@ -79,13 +37,13 @@ void solver::solve() { while(true) { //falls current sol schlechter als obere grenze: //zähle schritte bis zur nächsten alternative und - if(assignment_.current_objective() >= best_objective_) { + if(partition_.current_objective() >= best_objective_) { int i = trail_.length() - 1; while(true) { if(i < 0) return; // Only backtrack to assignments that have an alternative. - if(trail_.alternative_at(i) != illegal_partition) + if(trail_.alternative_at(i) != subgraph::none) break; i--; } @@ -103,30 +61,30 @@ void solver::solve() { // Memorize the new solution. best_solution_.resize(nodes_.num_vertices()); for(vertex_id node = 0; node < nodes_.num_vertices(); node++){ - best_solution_[node] = assignment_.assigned_partition_of(node); + best_solution_[node] = partition_.assigned_subgraph_of(node); } - best_objective_ = assignment_.current_objective(); + best_objective_ = partition_.current_objective(); std::cerr << "Solution improved to k = " << best_objective_ << std::endl; }else{ //sonst expandiere suchbaum weiter int node = trail_.length(); - expand(node, next_possible_partition(node, 0)); + expand(node, next_possible_subgraph(node, subgraph::sg_a)); } } } -void solver::expand(vertex_id node, partition_index p) { +void solver::expand(vertex_id node, subgraph sg) { // Search for an alternative BEFORE assigning the node. // Because the node is not assigned, this calculation is easy. - auto alt = next_possible_partition(node, p + 1); + auto alt = next_possible_subgraph(node, static_cast<subgraph>(-sg)); if(verbose) { - std::cerr << "Assign node " << node << " to partition " << p << std::endl; + std::cerr << "Assign node " << node << " to subgraph " << sg << std::endl; std::cerr << " Alternative " << alt << std::endl; } std::vector<unsigned int> neighbors = nodes_.get_adjacency(node); - assignment_.assign(node, p, neighbors); + partition_.assign_vertex(node, sg); trail_.push_node(node, alt); } @@ -138,23 +96,23 @@ void solver::backtrack() { std::cout << "Unassign node " << node << std::endl; trail_.pop(); - assignment_.unassign(node, nodes_.get_adjacency(node)); + partition_.unassign_vertex(node); } // Finds the next partition in which the given node can be placed. -partition_index solver::next_possible_partition(vertex_id node, partition_index m) { +subgraph solver::next_possible_subgraph(vertex_id node, subgraph m) { // This function is only correct if the node is not assigned yet. - assert(assignment_.assigned_partition_of(node) == illegal_partition); + assert(partition_.assigned_subgraph_of(node) == subgraph::none); // partition_count_: Index+1 of last partition that we will try. - partition_index p = m; + subgraph sg = m; //falls in einer partition schon die hälfte der knoten: nicht als alt wählen - if((assignment_.node_count_of(p) * 2) < nodes_.num_vertices()){ - return p; + if((partition_.num_vertices_of(sg) * 2) < nodes_.num_vertices()){ + return sg; } else{ - return (p xor 1); + return subgraph::none; } } diff --git a/include/gp-bnb/bnb.hpp b/include/gp-bnb/bnb.hpp index b5ece68..d5220fd 100644 --- a/include/gp-bnb/bnb.hpp +++ b/include/gp-bnb/bnb.hpp @@ -5,53 +5,11 @@ #pragma once #include <gp-bnb/graph.hpp> +#include <gp-bnb/partition.hpp> namespace gp_bnb { -using partition_index = unsigned int; - -// We use (-1) as an indicator for non-existing (or otherwise illegal) partition. -// Note that because this is cast to unsigned int, it becomes 0xFFFF... (i.e., the highest -// possible number). We do not use zero as that is a valid partition index. -static constexpr partition_index illegal_partition = static_cast<partition_index>(-1); - -// Represents a partial assignment. -struct assignment_state { - // Change the number of existing nodes. - void resize_nodes(size_t count); - - // Assigns an node to a partition. - void assign(vertex_id node, partition_index p, std::vector<unsigned int> neighbors); - - // Unassigns an node from its partition. - void unassign(vertex_id node, std::vector<unsigned int> neigbors); - - partition_index assigned_partition_of(vertex_id node) const { - return assigned_partition_[node]; - } - - - unsigned int node_count_of(partition_index p) const { - return node_count[p]; - } - - int current_objective() const { - return current_objective_; - } - -private: - // For each node: index of the partition it is placed into. - std::vector<partition_index> assigned_partition_; - - // Value of objective function for current partial solution. - int current_objective_ = 0; - - //for each partition: fill count - std::vector<unsigned int> node_count; - - //number of partitions - int partition_count_ = 2; -}; +using subgraph = partition::subgraph; // Represents the current path throught the search tree. struct trail_state { @@ -60,18 +18,18 @@ private: // Index of node that is assigned at a certain level of the search tree. vertex_id node; - // Next alternative (or illegal_partition if no alternative exists). - partition_index alt; + // Next alternative (or none if no alternative exists). + subgraph alt; }; public: // Extends the current path by adding another node. - void push_node(vertex_id node, partition_index alt); + void push_node(vertex_id node, subgraph alt); // Reduces the current path by removing the last node. void pop(); - int length() const { + unsigned int length() const { return stack_.size(); } @@ -79,7 +37,7 @@ public: return stack_[n].node; } - partition_index alternative_at(size_t n) const { + subgraph alternative_at(size_t n) const { return stack_[n].alt; } @@ -90,24 +48,22 @@ private: // Main solver structure. Puts everything together. struct solver { + + // Constructor + solver(graph& g); + // Read-only access to the nodes. const graph &nodes() const { return nodes_; } // Read-only access to the optimal solution. - const std::vector<partition_index> &best_solution() const { + const std::vector<subgraph> &best_solution() const { return best_solution_; } - // Change the number of existing nodes. - void resize_nodes(size_t count); - // Expand a search tree node, i.e., assigns an node to a partition and update all data structures. - void expand(vertex_id node, partition_index p); - - //associates graph with the solver - void define_graph(graph& g); + void expand(vertex_id node, subgraph sg); // Performs backtracking after the solver ran into a dead end, // i.e., the current branch has been pruned. @@ -117,15 +73,16 @@ struct solver { void solve(); private: - partition_index next_possible_partition(vertex_id node, partition_index p); + subgraph next_possible_subgraph(vertex_id node, subgraph sg); graph nodes_; - assignment_state assignment_; + + partition partition_; trail_state trail_; // Value of best solution seen so far. - std::vector<partition_index> best_solution_; - int best_objective_ = 0; + std::vector<subgraph> best_solution_; + unsigned int best_objective_ = 0; }; } // namespace gp_bnb -- GitLab