Skip to content
Snippets Groups Projects
bnb.cpp 6 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.
// --------------------------------------------------------------------------------------

Florian Heinrichs's avatar
Florian Heinrichs committed
solver::solver(graph& g, lb lb_algorithm) : graph_(g), partition_(partition{g}), lb_algorithm_(lb_algorithm), i_bfs_(incremental_bfs(g)), gp_(greedy_packing(g, i_bfs_, true)) {
unsigned int solver::get_lower(){
Florian Heinrichs's avatar
Florian Heinrichs committed
    if (sources_.empty() || sinks_.empty()) {
        return partition_.current_objective();
    }

    

	if(lb_algorithm_ == lb::ek){
Florian Heinrichs's avatar
Florian Heinrichs committed
		auto ek = edmonds_karp(graph_, sources_, sinks_);
	    return ek.get_max_flow();
	else if(lb_algorithm_ == lb::ibfs){
Florian Heinrichs's avatar
Florian Heinrichs committed
		i_bfs_.reset(sources_, sinks_);
p-hamann's avatar
p-hamann committed
		i_bfs_.run();
		return i_bfs_.get_max_flow(); 
	else if(lb_algorithm_ == lb::pr){
Florian Heinrichs's avatar
Florian Heinrichs committed
        auto pr = push_relabel(graph_, sources_, sinks_);
p-hamann's avatar
p-hamann committed
        pr.run();
        return pr.get_max_flow();
	else if(lb_algorithm_ == lb::gp){
Florian Heinrichs's avatar
Florian Heinrichs committed
		gp_.reset(sources_, sinks_);
		gp_.run();
Florian Heinrichs's avatar
Florian Heinrichs committed
			return gp_.get_max_flow();
		return gp_.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.
Florian Heinrichs's avatar
Florian Heinrichs committed
	bool fa = true;

Florian Heinrichs's avatar
Florian Heinrichs committed
	if(partition_.num_nodes_of(subgraph::none) == graph_.num_nodes()){
		alt = next_possible_subgraph(node, static_cast<subgraph>(sg+1));
Florian Heinrichs's avatar
Florian Heinrichs committed

	if(lb_algorithm_ == lb::gp && fa && !(sources_.empty() || sinks_.empty())){
		auto x = gp_.forced_assignment(node);
		if(x.second){
			if(x.first > best_objective_){
				sg = subgraph::sg_b;
				alt = subgraph::none;
			}
		}
		else{
			if(!(x.first > best_objective_)){
				sg = subgraph::sg_b;
			}
			//else{
			//alt = subgraph::none;
			//}			
		}
	}
	
	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;
	}
Florian Heinrichs's avatar
Florian Heinrichs committed

	//std::cerr << "expand: " << node << " to: " << sg << std::endl;
p-hamann's avatar
p-hamann committed
	partition_.assign_node(node, sg);
	trail_.push_node(node, alt);
Florian Heinrichs's avatar
Florian Heinrichs committed
	if(sg == subgraph::sg_a) sources_.push_back(node);
	else sinks_.push_back(node);

}

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);
Florian Heinrichs's avatar
Florian Heinrichs committed
	if (sources_.back() == node) sources_.erase(sources_.begin() + sources_.size() - 1);
	else if (sinks_.back() == node) sinks_.erase(sinks_.begin() + sinks_.size() - 1);
	//std::cerr << "backtrack" << std::endl;
}

// 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