Skip to content
Snippets Groups Projects
bnb.cpp 5.59 KiB
Newer Older
#include <algorithm>
#include <cassert>
#include <iostream>
#include <gp-bnb/bnb.hpp>

static constexpr bool verbose = false;

namespace gp_bnb {

// --------------------------------------------------------------------------------------
// trail_state implementation.
// --------------------------------------------------------------------------------------

p-hamann's avatar
p-hamann committed
void trail_state::push_node(node_id node, subgraph alt) {
	stack_.push_back({node, alt});
}

void trail_state::pop() {
	stack_.pop_back();
}

// --------------------------------------------------------------------------------------
// solver implementation.
// --------------------------------------------------------------------------------------

p-hamann's avatar
p-hamann committed
solver::solver(graph& g, lb lb_algorithm) : graph_(g), partition_(partition{g}), lb_algorithm_(lb_algorithm), i_bfs_(incremental_bfs(g)) {
unsigned int solver::get_lower(){
    std::vector<node_id> sources, sinks;
	for(node_id node = 1; node <= graph_.num_nodes(); node++){
		if(partition_.assigned_subgraph_of(node) == partition::sg_a)
			sources.push_back(node);
		else if(partition_.assigned_subgraph_of(node) == partition::sg_b)
			sinks.push_back(node);
	}
    if (sources.empty() || sinks.empty()) {
        return partition_.current_objective();
    }

    

	if(lb_algorithm_ == lb::ek){
		auto ek = edmonds_karp(graph_, sources, sinks);
		ek.run();
	    return ek.get_max_flow();
	else if(lb_algorithm_ == lb::ibfs){
p-hamann's avatar
p-hamann committed
		i_bfs_.reset(sources, sinks);
		i_bfs_.run();
		return i_bfs_.get_max_flow(); 
	else if(lb_algorithm_ == lb::pr){
p-hamann's avatar
p-hamann committed
        auto pr = push_relabel(graph_, sources, sinks);
        pr.run();
        return pr.get_max_flow();
	else if(lb_algorithm_ == lb::gp){
		bool with_flow = true;
		auto g_p = greedy_packing(graph_, sources, sinks, i_bfs_, with_flow);
		if(with_flow)
			return g_p.get_max_flow();
		return g_p.get_max_flow() + partition_.current_objective();
    return partition_.current_objective();
void solver::solve() {
p-hamann's avatar
p-hamann committed
	best_objective_ = graph_.num_nodes();
	clock_t begin = clock();
    // builds a vector of node ids with descending degree
p-hamann's avatar
p-hamann committed
    std::vector<node_id> sorted_nodes;
    for (node_id i = 1; i <= graph_.num_nodes(); ++i) {
p-hamann's avatar
p-hamann committed
        sorted_nodes.push_back(i);
p-hamann's avatar
p-hamann committed
    std::sort(sorted_nodes.begin(), sorted_nodes.end(), [this](node_id a, node_id b) {
        return graph_.get_adjacency(a).size() > graph_.get_adjacency(b).size();
    });

	while(true) {
		//falls current sol schlechter als bisher beste lösung: 
		//zähle schritte bis zur nächsten alternative und

		if(get_lower() >= best_objective_) {
			int i = trail_.length() - 1;
			while(true) {
				if(i < 0){
					std::cerr << "visited nodes: " << visited_nodes << std::endl;
				// Only backtrack to assignments that have an alternative.
p-hamann's avatar
p-hamann committed
				if(trail_.alternative_at(i) != subgraph::none)
					break;
				i--;
			}

			auto node = trail_.node_at(i);
			auto alt = trail_.alternative_at(i);
			//backtracke soviele schritte und
				backtrack();
			}
			//wende dann die entsprechende alternative an
			expand(node, alt);
p-hamann's avatar
p-hamann committed
		}else if(trail_.length() == graph_.num_nodes()) {
			//falls wir an einem blatt im suchbaum sind
			// Memorize the new solution.
p-hamann's avatar
p-hamann committed
			best_solution_.resize(graph_.num_nodes());
			for(node_id node = 0; node < graph_.num_nodes(); node++){
				best_solution_[node] = partition_.assigned_subgraph_of(node+1);
p-hamann's avatar
p-hamann committed
			best_objective_ = partition_.current_objective();
			clock_t end = clock();
			double time = (double)(end -begin) / CLOCKS_PER_SEC;
			std::cerr << "Solution improved to k = " << best_objective_ << " after : " << time << " seconds and: " << visited_nodes << " besuchten knoten" << std::endl;
		}else{
			//sonst expandiere suchbaum weiter
			int next_node;

			//sort after degree
			/*int node_deg = 0;
			for(node_id node = 1; node <= graph_.num_nodes(); node++){
				if(partition_.assigned_subgraph_of(node) == subgraph::none){
					if(graph_.get_adjacency(node).size() > node_deg){
						node_deg = graph_.get_adjacency(node).size();
						next_node = node;
					}
				}
			}
			*/
			

p-hamann's avatar
p-hamann committed
			next_node = sorted_nodes[trail_.length()];

			expand(next_node, next_possible_subgraph(next_node, subgraph::sg_a));
p-hamann's avatar
p-hamann committed
void solver::expand(node_id node, subgraph sg) {
	assert(sg == subgraph::sg_a || sg == subgraph::sg_b);
	// Search for an alternative BEFORE assigning the node.
	// Because the node is not assigned, this calculation is easy.
	if(partition_.num_nodes_of(subgraph::sg_a) == 0 && partition_.num_nodes_of(subgraph::sg_b)){
		alt = subgraph::none;
	}else{
		alt = next_possible_subgraph(node, static_cast<subgraph>(sg+1));
	if(verbose) {
p-hamann's avatar
p-hamann committed
		std::cerr << "Assign node " << node << " to subgraph " << sg << std::endl;
		std::cerr << "    Alternative " << alt << std::endl;
	}
	
p-hamann's avatar
p-hamann committed
	partition_.assign_node(node, sg);
	trail_.push_node(node, alt);
}

void solver::backtrack() {
	assert(trail_.length());

	auto node = trail_.node_at(trail_.length() - 1);
	if(verbose)
		std::cout << "Unassign node " << node << std::endl;	
p-hamann's avatar
p-hamann committed
	partition_.unassign_node(node);
}

// Finds the next partition in which the given node can be placed.
p-hamann's avatar
p-hamann committed
subgraph solver::next_possible_subgraph(node_id node, subgraph m) {
	// This function is only correct if the node is not assigned yet.
p-hamann's avatar
p-hamann committed
	assert(partition_.assigned_subgraph_of(node) == subgraph::none);
p-hamann's avatar
p-hamann committed
	subgraph sg = m;
	
	while(sg <= 1){
		if((partition_.num_nodes_of(sg) * 2) < graph_.num_nodes())
			return sg;
		else
		{
			sg = static_cast<subgraph>(sg+1);
}

} // namespace gp_bnb