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