Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • scherzej/psco-2019-gp
  • heinrifx/psco-2019-gp
2 results
Show changes
Showing
with 1644 additions and 70 deletions
96 273
93 85 71 59 9
91 79 70 38 87
56 73 8 86 68 57 27 80
24 66 47 48 68
72 18 54
89 22 51 31
41 54 36 33 13 18 95
57 3 60 45 52 96 86
59 71 76 1
49 14 20 88
79 74 37 91 94 83
77 61 36 90 95 29
18 41 40 7 92
49 88 83 23 30 10
65 71 31 22
17 30 87 22 46 34 78 89
38 87 45 46 16
7 13 5 54 53 92 72
72 69 50 53 63
26 39 49 10 88
84 66 47 67 35
65 89 46 16 31 6 15
34 78 83 30 14 91
28 48 4 42 47
75 40 73 58
39 20 88
61 80 3 57 37 74 44
32 56 42 24 81 48
36 44 39 94 61 12
23 34 89 14 16 51 88
6 71 76 51 15 22
63 82 62 56 81 28 50
75 7 40 95 77 41
30 23 78 16
96 67 64 21 65 60 66
54 12 7 95 29 39
27 70 57 79 74 11
45 70 43 87 2 17
54 36 49 94 29 20 26
41 55 33 92 13 73 25 75
7 40 13 33
24 62 84 47 28 81
57 38 45 70
61 27 29 94 74
38 8 96 43 46 57 17
17 16 96 22 65 45
4 24 84 42 21 66
56 24 4 28 68
10 20 14 39 94 83
63 19 69 56 32
88 30 76 31 6 59 89
86 66 60 8
18 19 69 72 92
39 36 7 18 5
92 40 69 56 73
69 3 55 73 48 68 28 50 32
8 43 3 45 37 70 27
90 25 80 75 77 73
93 9 51 76 1
52 8 35 96 66
12 80 90 27 44 29
81 84 82 32 42
72 32 82 50 19
67 65 35 85 93
35 46 15 96 85 71 64 22
4 47 60 68 35 52 86 21
21 93 84 64 35
56 4 48 3 86 66
19 55 50 56 92 53
37 38 43 2 57 79
15 85 1 65 76 31 9
53 18 5 82 63 19
40 55 25 80 3 58 56
11 37 27 94 44
25 40 33 58 77
51 71 31 59 9
33 75 90 95 58 12
23 34 87 91 16
11 91 70 37 2
73 58 3 27 61 90
32 62 42 28
63 72 62 32
49 23 11 91 14 94
62 67 47 42 93 21
65 93 64 1 71
52 66 68 8 3
91 78 38 16 2 17
26 10 20 30 14 51
30 22 16 51 6
77 12 61 80 58
11 78 23 83 87 79 2
13 53 18 40 55 69
84 64 59 85 1 67
29 74 11 44 49 39 83
33 7 77 12 36
8 65 45 46 35 60
97 277
53 68 13 28 33 7 36
56 34 62 68 88
8 66 21 44
28 78 91 36
97 20 10 51
39 35 34 89 30 52 92 55
33 1 36 31 19
66 78 14 3 91 21
48 26 65 40 71 27
90 83 51 16 5 77 20 42
23 43 76 92 55 69
38 18 15 46 26
1 14 44 66 16 28
66 13 28 78 8
65 26 12 59 38
13 83 50 95 10 44
86 58 22 67 83 50
40 63 12 46 26
72 7 62 31 36 91
58 83 10 5 97 22
8 44 95 86 3 91 67
17 67 20 97 81 24 58
27 54 69 63 48 55 11 40
32 74 70 81 22 67
75 70 37 43 32 76
9 12 15 65 40 18
73 9 87 54 71 48 23
4 1 78 13 14 36
74 90 51 41
49 82 55 35 61 6
88 33 19 62 7
75 24 84 70 25 67
68 88 1 31 7
2 62 52 47 56 6 39
30 93 61 6 89
1 4 19 91 28 7
76 63 70 69 25 46
12 96 46 79 94 59 15
47 6 89 34
18 63 23 48 26 9
97 74 29 81 51
77 60 90 80 10
75 76 11 52 92 25
3 13 66 21 16 95
53 85 57 47
63 12 38 18 94 37 70
53 45 56 34 89 39 85
27 9 40 23
30 55 54 82 87
95 86 16 17 83
41 5 10 90 97 29
34 6 75 43 92 84 62
57 68 47 56 1 45
27 87 49 23 55
30 49 92 11 6 23 54
53 68 34 2 47
61 53 93 45 85
20 83 22 17
15 80 65 77 79 38
80 42 96 74 90 79
57 35 30 93 82 64
34 31 2 84 19 52 72 88
69 37 46 23 40 18
82 87 61 71 73
71 9 77 59 15 26
14 44 8 3 13
91 84 22 72 17 21 32 24 86
33 88 53 1 56 2
11 76 23 63 37
32 25 74 94 24 46 37
73 65 64 9 27
91 19 84 62 67
87 27 71 64
94 29 24 90 60 81 70 41 96
43 25 84 32 52
25 37 69 11 43
59 65 80 10 42
91 28 8 4 14
38 96 59 60 80
60 42 77 79 59
24 74 41 22 97
61 87 64 49 30
16 10 20 58 50 17
62 52 32 67 72 75
45 93 89 57 47
21 95 50 67 17
54 64 82 49 27 73
31 68 33 62 2
93 35 85 6 39 47
74 10 60 42 51 29
36 4 19 8 21 72 78 67
52 43 6 11 55
89 57 61 85 35
70 74 38 46 96
44 16 21 86 50
38 60 94 79 74
22 5 20 51 41 81
98 277
83 60 35 88 8 19
72 63 71 61 6
77 70 62 10 87 68
57 31 84 60 69 25 17
78 12 84 39 55
61 2 10 77 82 74 63
30 55 9 13
88 1 91 19 9
13 7 55 88 91 8 19 39
3 6 70 77 82
94 23 26 45 65
81 84 5 80 78 53
56 30 9 49 18 7
48 79 72 71 16
86 34 41 96 66 95
23 33 72 14 98 54
20 75 25 4 70 57 51
41 13 24 34 49
91 1 9 8 39 83
17 70 25 73
61 48 79 74 59
59 37 92 43 40 74
98 94 24 16 27 11 45
23 18 27 34 66
31 73 20 4 17
11 94 28 46 95 87 65
23 94 24 86 66
87 62 73 46 26 36
38 83 39 60
7 55 56 13
73 25 80 4 84
76 47 42 67
54 93 98 16
24 18 66 41 15
52 60 90 88 1 89
28 73 80 81 96 46
48 59 67 22 92
60 83 29
55 5 60 84 29 9 19 83
43 75 22 92
34 97 49 96 18 15
67 32 47 44 50
74 82 22 75 40
67 92 69 57 42 52 50
23 11 58 93 65 98
95 28 26 96 36
50 32 42 52
14 79 67 37 59 76 21
18 13 41 56 97
44 47 52 42
75 92 17 57
35 50 89 47 69 44
81 64 78 12
16 33 93 68 72
78 56 5 30 39 9 7
64 97 13 78 30 55 49
44 69 92 4 17 51
45 65 87 93 68
21 74 22 37 48
4 69 90 35 1 83 39 84 29 38
6 21 71 74 79 2
87 70 3 28 73
6 2 72 77 85
81 96 56 78 53 97
58 87 45 26 11
27 24 34 15 86
42 48 37 92 44 32 76
93 77 3 58 54 87 72 85
52 44 4 89 60 90 57
3 10 75 20 17 82 62 73
2 72 61 14 79
54 14 85 63 68 2 16 71
62 28 36 80 25 31 20 70
61 6 82 22 21 43 59
82 43 17 92 70 40 51
48 67 32
68 6 10 3 85 63
5 55 12 56 64 53
14 48 21 71 61
36 31 81 12 84 73
96 12 64 53 80 36
6 70 75 10 43 74
39 1 19 29 38 60
4 31 39 5 60 80 12
63 68 77 72
27 94 66 95 15
65 58 3 68 28 62 26
35 9 8 1
52 69 90 35
69 89 60 35
19 9 8
37 67 22 44 57 75 51 40
33 45 58 68 98 54
11 95 86 26 27 23
46 96 86 26 15 94
95 41 64 97 15 81 36 46
64 49 41 96 56
45 23 93 33 16
99 283
95 23 24 15 77 55 83
91 98 37 57
67 82 38 17 39 74
33 73 34 86 61
73 40 44 11 42 86
88 51 84 35 27 16
81 45 69 39 49 82 21
18 79 9 94
79 59 50 94 8 56
45 57 12 32 87
5 40 84 20 86 61
53 75 10 87 57
41 51 16 90 25
43 64 89 76
77 1 30 55
13 51 6 90 35
29 78 67 47 3 43 33 74
53 51 79 94 87 8 41
62 92 65 70
47 34 61 11
49 52 7 81
98 91 97 52
87 32 56 1 95 28 83 94
83 63 31 1 54 44 77
41 13 48 90 50
76 89 29 78
80 70 35 88 6 96
32 23 45 95 55
17 89 43 78 26
69 77 45 55 15
60 54 24 93 63
87 10 45 23 28
17 47 67 34 4 85 73
20 61 4 33 47
90 80 27 16 6
40 65 68 44 66 71
75 98 53 57 2
39 42 67 77 44 3
7 77 38 82 3 69
5 36 44 11 46 68 84
50 25 18 51 13 79
67 85 44 73 5 38
64 14 17 82 74 29 89
24 77 63 42 40 38 5 71 36
81 57 55 91 69 30 7 10 32 28
40 84 66 58 68
76 33 34 78 20 17
59 25 50 90 80
7 64 99 82 52 21
79 9 59 48 25 41
6 41 16 18 13
97 22 99 49 81 21 91
75 12 37 98 87 18
83 24 59 31 56 60
15 30 95 45 1 28
9 54 59 94 83 23
2 37 91 10 75 45 12
65 66 46 84 92
48 50 9 80 96 56 93 60 54
59 54 93 31
20 34 4 86 11
72 19 70 65 71
24 72 31 93 71 44
97 99 14 49 82 43 76
19 66 71 36 58 92 62
65 36 46 58 68
33 42 17 38 3 85
40 36 66 46
45 30 7 77 39
72 96 19 92 27 84 62 88
72 62 65 36 44 63
96 63 93 71 62 70
5 4 85 33 86 42
82 17 3 43
53 37 12 57
47 14 97 64 26 89 78
30 15 69 38 44 24 39 1
47 17 29 76 26
9 18 8 41 50
96 27 35 90 48 59
45 52 7 91 21
49 64 43 3 74 39 7
23 1 56 54 24
6 70 92 58 46 88 11 40
67 42 73 33
73 4 5 61 11
53 12 23 18 94 32 10
27 70 84 6
43 14 29 76 26
16 80 25 48 35 13
98 2 57 52 22 45 81
70 65 19 84 58
60 72 31 63 96 59
18 9 8 23 56 87
1 55 23 28
80 72 93 27 59 70
64 99 22 52 76 98
53 97 22 37 2 91
64 49 97 52
#include <algorithm>
#include <cassert>
#include <iostream>
#include <time.h>
#include <gp-bnb/bnb.hpp>
static constexpr bool verbose = false;
unsigned long visited_nodes = 0;
namespace gp_bnb {
......@@ -23,25 +26,64 @@ void trail_state::pop() {
// solver implementation.
// --------------------------------------------------------------------------------------
solver::solver(graph& g) : graph_(g), partition_(partition{g}) {
solver::solver(graph& g, lb lb_algorithm) : graph_(g), partition_(partition{g}), lb_algorithm_(lb_algorithm), i_bfs_(incremental_bfs(g)), ek_(edmonds_karp(g)), pr_(push_relabel(g)), gp_(greedy_packing(g, i_bfs_, true)) {
}
void solver::solve() {
//anfangs upper bound?
best_objective_ = graph_.num_nodes();
unsigned int solver::get_lower(){
if (current_sources_.empty() || current_sinks_.empty()) {
return partition_.current_objective();
}
if(lb_algorithm_ == lb::ek){
ek_.reset(current_sources_, current_sinks_);
ek_.run();
return ek_.get_max_flow();
}
else if(lb_algorithm_ == lb::ibfs){
i_bfs_.reset(current_sources_, current_sinks_);
i_bfs_.run();
return i_bfs_.get_max_flow();
}
else if(lb_algorithm_ == lb::pr){
pr_.reset(current_sources_, current_sinks_);
pr_.run();
return pr_.get_max_flow();
}
else if(lb_algorithm_ == lb::gp || lb_algorithm_ == lb::fa){
gp_.reset(current_sources_, current_sinks_);
gp_.run();
return gp_.get_max_flow();
}
return partition_.current_objective();
}
//partition vector initializieren
void solver::solve() {
//anfangs lower bound?
best_objective_ = graph_.num_nodes();
clock_t begin = clock();
int next_node;
// builds a vector of node ids with descending degree
std::vector<node_id> sorted_nodes;
for (node_id i = 1; i <= graph_.num_nodes(); ++i) {
sorted_nodes.push_back(i);
}
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 obere grenze:
//falls current sol schlechter als bisher beste lösung:
//zähle schritte bis zur nächsten alternative und
if(partition_.current_objective() >= best_objective_) {
if(get_lower() >= best_objective_) {
int i = trail_.length() - 1;
while(true) {
if(i < 0)
if(i < 0){
std::cerr << "visited nodes: " << visited_nodes << std::endl;
return;
}
// Only backtrack to assignments that have an alternative.
if(trail_.alternative_at(i) != subgraph::none)
break;
......@@ -51,41 +93,61 @@ void solver::solve() {
auto node = trail_.node_at(i);
auto alt = trail_.alternative_at(i);
//backtracke soviele schritte und
while(trail_.length() > i){
while((int)trail_.length() > i){
backtrack();
}
//wende dann die entsprechende alternative an
expand(node, alt);
expand(node, alt, subgraph::none);
}else if(trail_.length() == graph_.num_nodes()) {
//falls wir an einem blatt im suchbaum sind
// Memorize the new solution.
best_solution_.resize(graph_.num_nodes());
for(node_id node = 0; node < graph_.num_nodes(); node++){
best_solution_[node] = partition_.assigned_subgraph_of(node);
best_solution_[node] = partition_.assigned_subgraph_of(node+1);
}
best_objective_ = partition_.current_objective();
std::cerr << "Solution improved to k = " << best_objective_ << std::endl;
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 << " visited nodes" << std::endl;
}else{
//sonst expandiere suchbaum weiter
int node = trail_.length();
expand(node, next_possible_subgraph(node, subgraph::sg_a));
next_node = sorted_nodes[trail_.length()];
subgraph next_sub, alt;
next_sub = next_possible_subgraph(next_node, subgraph::sg_a);
alt = next_possible_subgraph(next_node, static_cast<subgraph>(next_sub+1));
if(lb_algorithm_ == lb::fa && !(current_sources_.empty() || current_sinks_.empty())){
subgraph x = gp_.forced_assignment(next_node, best_objective_);
if(x != subgraph::none && ((partition_.num_nodes_of(x)*2) < graph_.num_nodes())){
next_sub = x;
alt = subgraph::none;
}
}
expand(next_node, next_sub, alt);
}
}
}
void solver::expand(node_id node, subgraph sg) {
void solver::expand(node_id node, subgraph sg, subgraph alt) {
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.
auto alt = next_possible_subgraph(node, static_cast<subgraph>(-sg));
visited_nodes++;
if(partition_.num_nodes_of(subgraph::none) == graph_.num_nodes()){
alt = subgraph::none;
}else{
//alt = next_possible_subgraph(node, static_cast<subgraph>(sg+1));
}
if(verbose) {
std::cerr << "Assign node " << node << " to subgraph " << sg << std::endl;
std::cerr << " Alternative " << alt << std::endl;
}
std::vector<unsigned int> neighbors = graph_.get_adjacency(node);
partition_.assign_node(node, sg);
trail_.push_node(node, alt);
if (sg == partition::sg_a) current_sources_.push_back(node);
else current_sinks_.push_back(node);
}
void solver::backtrack() {
......@@ -93,10 +155,12 @@ void solver::backtrack() {
auto node = trail_.node_at(trail_.length() - 1);
if(verbose)
std::cout << "Unassign node " << node << std::endl;
std::cout << "Unassign node " << node << std::endl;
trail_.pop();
partition_.unassign_node(node);
if (current_sources_.back() == node) current_sources_.erase(current_sources_.begin() + current_sources_.size() - 1);
else if (current_sinks_.back() == node) current_sinks_.erase(current_sinks_.begin() + current_sinks_.size() - 1);
}
// Finds the next partition in which the given node can be placed.
......@@ -104,16 +168,18 @@ subgraph solver::next_possible_subgraph(node_id node, subgraph m) {
// This function is only correct if the node is not assigned yet.
assert(partition_.assigned_subgraph_of(node) == subgraph::none);
// partition_count_: Index+1 of last partition that we will try.
subgraph sg = m;
//falls in einer partition schon die hälfte der knoten: nicht als alt wählen
if((partition_.num_nodes_of(sg) * 2) < graph_.num_nodes()){
return sg;
}
else{
return subgraph::none;
while(sg <= 1){
if((partition_.num_nodes_of(sg) * 2) < graph_.num_nodes())
return sg;
else
{
sg = static_cast<subgraph>(sg+1);
}
}
return subgraph::none;
}
} // namespace gp_bnb
......
#include <limits>
#include <queue>
#include <cassert>
#include <iostream>
#include <gp-bnb/edmonds_karp.hpp>
edmonds_karp::edmonds_karp(const graph &g)
: g_(g) {
};
void edmonds_karp::reset(std::vector<node_id>& sources, std::vector<node_id>& sinks) {
sources_ = &sources;
sinks_ = &sinks;
// Initial flow value
flow_ = 0;
// Initialize vectors
sources_and_sinks_.assign(g_.num_nodes() + 1, 0);
flow_edges_.assign(g_.num_edges(), false);
// Sources marked as 1, sinks marked as -1. All other nodes are 0.
for (unsigned int i = 0; i < sources_->size(); ++i) {
sources_and_sinks_[sources_->operator[](i)] = 1;
}
for (unsigned int i = 0; i < sinks_->size(); ++i) {
sources_and_sinks_[sinks_->operator[](i)] = -1;
}
};
/* Breadth-first search in the graph from source nodes to sink nodes */
node_id edmonds_karp::bfs(std::vector<std::pair<node_id, edge_id>> &pred) const {
pred.clear();
pred.assign(g_.num_nodes() + 1, std::make_pair(0, 0)); // undiscovered nodes are marked with 0
// Push all source nodes to the queue
std::queue<node_id> q;
for (unsigned int i = 0; i < sources_->size(); ++i) {
node_id s = sources_->operator[](i);
q.push(s);
pred[s] = std::make_pair(s, 0);
}
// Perform BFS from each source node and stop when the sink was reached
// or there was no path found from the source to the sink
while (!q.empty()) {
node_id u = q.front();
q.pop();
const auto& adjacency = g_.get_adjacency(u);
const auto& edge_ids = g_.get_edge_ids(u);
// iterate through neighbors of u
for (node_id i = 0; i < adjacency.size(); ++i) {
node_id v = adjacency[i];
edge_id eid = edge_ids[i];
if(!flow_edges_[eid-1] && pred[v].first == 0) {
pred[v] = std::make_pair(u, eid);
if (sources_and_sinks_[v] == -1) return v;
q.push(v);
}
}
}
return 0;
};
// Edmonds-Karp Algorithm for unweighted, undirected graphs
void edmonds_karp::run() {
while (true) {
std::vector<std::pair<node_id, edge_id>> pred;
// BFS from source nodes to sink nodes
node_id n = bfs(pred);
if (n == 0) break;
flow_++;
while (true) {
flow_edges_[pred[n].second-1] = true;
if (sources_and_sinks_[(n = pred[n].first)] == 1) break;
}
}
};
#include <gp-bnb/graph.hpp>
graph::graph(std::vector<std::vector<unsigned int>> a) : nodes_(a.size()), adjacency_list_(a) {
}
graph::graph(std::vector<std::vector<unsigned int>> a) : nodes_(a.size()), adjacency_list_(a), indexed_edges_(a) {
// indexes the edges
std::vector<std::pair<node_id,node_id>> edge_list;
for (node_id u = 1; u <= nodes_; u++) {
for (node_id v : get_adjacency(u)) {
if (u < v) {
edge_list.push_back(std::make_pair(u,v));
}
}
}
edges_ = edge_list.size();
for (edge_id e = 1; e <= edges_; e++) {
node_id u = edge_list[e-1].first;
node_id v = edge_list[e-1].second;
const std::vector<node_id>& u_neighbors = get_adjacency(u);
const std::vector<node_id>& v_neighbors = get_adjacency(v);
for (unsigned int i = 0; i < u_neighbors.size(); i++) {
if (u_neighbors[i] == v) {
indexed_edges_[u-1][i] = e;
break;
}
}
for (unsigned int i = 0; i < v_neighbors.size(); i++) {
if (v_neighbors[i] == u) {
indexed_edges_[v-1][i] = e;
break;
}
}
}
unsigned int graph::num_nodes() const {
return nodes_;
}
std::vector<unsigned int> graph::get_adjacency(node_id v) const {
return adjacency_list_[v-1];
edge_id graph::get_edge_id(node_id u, node_id v) const {
const std::vector<node_id>& neighbors = get_adjacency(u);
for (unsigned int i = 0; i < neighbors.size(); ++i) {
if (neighbors[i] == v) return indexed_edges_[u-1][i];
}
return 0;
}
#include <algorithm>
#include <gp-bnb/greedy_packing.hpp>
#include <iostream>
bool do_swap = true;
greedy_packing::greedy_packing(graph& g, incremental_bfs& ibfs, bool with_flow)
: graph_(g), i_bfs(ibfs), with_flow_(with_flow){
max_a = (graph_.num_nodes())/2;
};
void greedy_packing::reset(std::vector<node_id>& a, std::vector<node_id>& b){
a_ = &a;
b_ = &b;
x_.clear();
partitioning.clear();
in_part.assign(graph_.num_nodes()+2, -1);
a_count = a_->size();
flow_ = bound = 0;
visited.assign(graph_.num_nodes() +1, false);
if(do_swap && a.size() > b.size()){
swapped = true;
std::swap(a_, b_);
//std::cerr << "swapped" << std::endl;
}
else{
swapped = false;
}
}
//breadth-first-search to determine neighbors of B
void greedy_packing::bfs(){
for (node_id i = 0; i < b_->size(); ++i) {
node_id node = b_->operator[](i);
q.push(node);
visited[node] = true;
}
for (node_id i = 0; i < a_->size(); ++i) {
visited[a_->operator[](i)] = true;
}
while(!q.empty()){
node_id node = q.front();
q.pop();
const auto& adjacency = graph_.get_adjacency(node);
const auto& edge_ids = graph_.get_edge_ids(node);
for(node_id i = 0; i < adjacency.size(); ++i){
node_id v = adjacency[i];
if(visited[v] == false){
//falls nicht(mit_flow angegeben und knoten unter den flow_edges ist)dann push in zu x
if(!with_flow_ || !flow_edges_->operator[](edge_ids[i]-1) ){
x_.push_back(v);
visited[v] = true;
}
}
}
}
return;
};
void greedy_packing::run(){
if(with_flow_){
//get all flow edges and the flow
i_bfs.reset(*a_, *b_);
i_bfs.run();
flow_ = i_bfs.get_max_flow();
flow_edges_ = &i_bfs.get_flow_edges();
}
a_count = a_->size();
if(a_count >= max_a)
return;
//x per bfs konstruieren
bfs();
//P konstruieren
partitioning.resize(x_.size());
//dafür für jeden nachbarn von B einen eigenen Block
for(unsigned int i = 0; i <x_.size(); i++){
partitioning[i].push_back(x_[i]);
in_part[x_[i]] = i;
}
//dann jeweils kleinsten block um einen nachbarn erweitern
//baue mit B zusammenhängende Partitionen (noch ohne lokale Suche) und sortiere nach Größe absteigend
bool found_new_element = true;
while (found_new_element) {
found_new_element = false;
for (unsigned int i = 0; i < partitioning.size(); i++){
node_id v = partitioning[i].back();
const auto& adjacency = graph_.get_adjacency(v);
const auto& edge_ids = graph_.get_edge_ids(v);
for(node_id u = 0; u < adjacency.size(); ++u){
node_id node = adjacency[u];
if (!visited[node]) {
if(!with_flow_ || !(flow_edges_->operator[](edge_ids[u]-1) )){
partitioning[i].push_back(node);
visited[node] = true;
in_part[node] = i;
found_new_element = true;
break;
}
}
}
}
}
//danach lokale suche um balance zu verbessern ?
std::sort(partitioning.begin(), partitioning.end(), [](std::vector<node_id>& x, std::vector<node_id>& y) {
return x.size() > y.size();
});
// behandle von B aus unnerreichbare Knoten
for (node_id i = 1; i <= graph_.num_nodes(); i++) {
if (!visited[i]) {
a_count++;
if (a_count >= max_a){
return;
}
}
}
// packe greedy (erst hier wird flow erhöht)
for (auto& partition : partitioning) {
bound++;
a_count += partition.size();
if (a_count >= max_a){
return;
}
}
return;
};
partition::subgraph greedy_packing::forced_assignment(node_id node, unsigned int best){
unsigned int new_bound, x_v, p, index, neighbors;
x_v = p = neighbors = 0;
a_count = a_->size();
//fall 1: node in nicht trivialem block
if(visited[node]){
//return partition::subgraph::none;
const auto& adjacency = graph_.get_adjacency(node);
//für jeden nachbarn von node
for(unsigned int i = 0; i < adjacency.size(); ++i){
node_id u = adjacency[i];
//std::cerr << "node: " << u << std::endl;
//knoten im selben block wie node ignorieren?!
if(in_part[u] != -1 && in_part[u] != in_part[node]){
//falls er in einem noch nicht betrachteten block liegt erhöhe x_v
x_v++;
index = in_part[u];
//dieser block ist nun nicht trivial (jeden knoten nichtmehr
//als visited markieren)
for(node_id v : partitioning[index]){
//std::cerr << v << " ";
visited[v] = false;
in_part[v] = -1;
}
partitioning[index].clear();
}
}
//x_v++;
//neues eingeschränktes packing-bound berechnen
std::sort(partitioning.begin(), partitioning.end(), [](std::vector<node_id> a, std::vector<node_id> b) {
return a.size() > b.size();
});
// behandle von B aus unnerreichbare Knoten
for (node_id i = 1; i <= graph_.num_nodes(); i++) {
if (!visited[i]) {
a_count++;
if (a_count >= max_a){
break;
}
}
}
// packe greedy (erst hier wird flow erhöht)
for (std::vector<node_id> partition : partitioning) {
if (a_count >= max_a){
break;
}
if(!partition.empty())
p++;
a_count += partition.size();
}
new_bound = flow_ + x_v + p;
if(new_bound >= best){
if(swapped)
return partition::sg_a;
else
return partition::sg_b;
}
return partition::subgraph::none;
}
else{
//return partition::subgraph::none;
//fall2: v in trivialem block
//bound erhöht sich um anzahl der nachbarn von v
/*std::cerr << "a: ";
for (node_id i = 0; i < a_->size(); ++i) {
node_id d = a_->operator[](i);
std::cerr << d << " ";
}
std::cerr << "b: ";
for (node_id i = 0; i < b_->size(); ++i) {
node_id d = b_->operator[](i);
std::cerr << d << " ";
}
*/
const auto& edge_ids = graph_.get_edge_ids(node);
// std::cerr << "node " << node << " : ";
const auto& adjacency = graph_.get_adjacency(node);
for(unsigned int i = 0; i < adjacency.size(); i++){
node_id v = adjacency[i];
//flow_edge test resolves loop
if(!visited[v] && (!with_flow_ || !(flow_edges_->operator[](edge_ids[i]-1))) ){
//std::cerr << " " << v;
neighbors++;
}
}
// std::cerr << std::endl;
new_bound = flow_ + bound + neighbors ;
// std::cerr << "new bound: " << flow_ << " + " << bound << " + " << neighbors << " = " << new_bound << std::endl;
if(new_bound >= best){
if(swapped)
return partition::sg_b;
else
return partition::sg_a;
}
return partition::subgraph::none;
}
return partition::subgraph::none;
}
#include <gp-bnb/ibfs_subtree.hpp>
#include <cassert>
ibfs_subtree::ibfs_subtree(int id, const graph& g, std::vector<bool>& flow_edges) : id_(id),
g_(g), unassigned_(g.num_nodes()), labels_(std::vector<label>(g.num_nodes())), pred_(std::vector<node_id>(g.num_nodes())), flow_edges_(flow_edges) {
}
void ibfs_subtree::reset(std::vector<node_id>& roots) {
labels_.assign(g_.num_nodes(), unassigned_);
pred_.assign(g_.num_nodes(), 0);
for (const auto& n : roots) {
labels_[n-1] = 0;
current_front_.push_back(n);
}
current_max_ = 0;
max_adoption_label_ = 0;
last_resid_orphans_.clear();
}
void ibfs_subtree::add_node(label l, node_id node, node_id pred) {
assert(l == labels_[pred-1]+1);
labels_[node-1] = l;
pred_[node-1] = pred;
if (l == max_adoption_label_) current_front_.push_back(node);
}
std::vector<node_id> ibfs_subtree::get_front() {
std::vector<node_id> front = current_front_;
current_front_.clear();
return front;
}
std::vector<node_id> ibfs_subtree::reduce_path(node_id leaf) {
// Assertion: augmentation paths are exclusively found on the leaves
assert(labels_[leaf-1] == current_max_);
last_resid_orphans_.clear();
std::vector<node_id> flow_nodes;
node_id current = leaf;
// build a vector with all nodes of the flow from the leaf to the immediate child of the root
for (label l = labels_[current-1]; l > 0; --l) {
node_id pred = pred_[current-1];
pred_[current-1] = 0;
assert(labels_[current-1] == labels_[pred-1]+1);
flow_nodes.push_back(current);
flow_edges_[g_.get_edge_id(current, pred)-1] = true;
current = pred;
}
std::vector<node_id> new_front;
for (label l = flow_nodes.size(); l > 0; l--) {
node_id orphan = flow_nodes[l-1];
label old_label = labels_[orphan-1];
label new_label = adopt(orphan);
// change pred but do not adopt childs of this orphan
if (new_label == old_label) {
if (new_label == current_max_) new_front.push_back(orphan);
}
// processes all successors as orphans if this orphan can't be adopted on origin label
else {
if (new_label == 0) last_resid_orphans_.push_back(orphan);
else if (new_label == current_max_) new_front.push_back(orphan);
std::vector<node_id> parents { orphan };
std::vector<node_id> childs;
while (!parents.empty()) {
// searches all childs of the current parents
for (auto& parent : parents) {
for (node_id potential_child : g_.get_adjacency(parent)) {
if (pred_[potential_child-1] == parent) childs.push_back(potential_child);
}
}
// tries to adopt all found childs
for (auto& child : childs) {
bool is_front = false;
if (labels_[child-1] == current_max_) is_front = true;
label new_child_label = adopt(child);
if (new_child_label == 0) last_resid_orphans_.push_back(child);
else if (new_child_label == current_max_ && !is_front) new_front.push_back(orphan);
}
parents = childs;
childs.clear();
}
}
}
return new_front;
}
// tries to insert orphans with minimum label
// if they could have been inserted with label <= min,
// they would have happened because of BFS
label ibfs_subtree::adopt(node_id orphan) {
label min = labels_[orphan-1];
label current_min = unassigned_;
node_id new_pred = 0;
const auto& adjacency = g_.get_adjacency(orphan);
const auto& edge_ids = g_.get_edge_ids(orphan);
for (node_id i = 0; i < adjacency.size(); ++i) {
node_id n = adjacency[i];
if (labels_[n-1] == min-1 && !flow_edges_[edge_ids[i]-1]) {
add_node(min, orphan, n);
return min;
} else if (labels_[n-1]+1 < current_min
&& labels_[n-1] < max_adoption_label_
&& !flow_edges_[edge_ids[i]-1]) {
current_min = labels_[n-1]+1;
new_pred = n;
}
}
if (new_pred != 0) {
add_node(current_min, orphan, new_pred);
return current_min;
} else {
labels_[orphan-1] = unassigned_;
pred_[orphan-1] = 0;
return 0;
}
}
#include <cassert>
#include <queue>
#include <iostream>
#include <gp-bnb/incremental_bfs.hpp>
incremental_bfs::incremental_bfs(const graph& g)
: g_(g), s_(ibfs_subtree(subtree::s, g, flow_edges_)), t_(ibfs_subtree(subtree::t, g, flow_edges_)), flow_edges_(std::vector<bool> (g.num_edges())) {
}
void incremental_bfs::reset(std::vector<node_id>& sources, std::vector<node_id>& sinks) {
assert(!sources.empty());
assert(!sinks.empty());
flow_edges_.assign(g_.num_edges(), false);
flow_ = 0;
node_assignments_.assign(g_.num_nodes(), none);
for (const auto& node : sources) {
node_assignments_[node-1] = s_root;
}
for (const auto& node : sinks) {
node_assignments_[node-1] = t_root;
// increments the flow value to the number of pairwise neighbors of sources and sinks
const auto& adjacency = g_.get_adjacency(node);
const auto& edge_ids = g_.get_edge_ids(node);
for (node_id i = 0; i < adjacency.size(); ++i) {
if (node_assignments_[adjacency[i]-1] == s_root) {
flow_edges_[edge_ids[i]-1] = true;
flow_++;
}
}
}
s_.reset(sources);
t_.reset(sinks);
}
void incremental_bfs::run() {
// grows the subtrees alternating until one subtree cannot grow anymore
for (int i = 0; ; ++i) {
if (i%2 == 0) {
if (!grow(s_)) break;
} else {
if (!grow(t_)) break;
}
}
}
bool incremental_bfs::grow(ibfs_subtree& st) {
// ensures that only st can adopt on current_max+1
st.set_max_adoption_label(st.get_current_max()+1);
// creates a queue of candidate nodes for extending
std::queue<node_id> q;
for (auto& n : st.get_front()) {
q.push(n);
}
if (q.empty()) return false;
while (!q.empty()) {
node_id node = q.front();
q.pop();
// takes into account the case that node in this grow was already orphaned and not re-inserted in the front
if (!st.is_front_element(node)) continue;
const auto& adjacency = g_.get_adjacency(node);
const auto& edge_ids = g_.get_edge_ids(node);
// searches for neighbors of candidate nodes
for (node_id i = 0; i < adjacency.size(); ++i) {
node_id neighbor = adjacency[i];
if (!flow_edges_[edge_ids[i]-1]) {
// performs augmentation ...
if (-st.get_id() == node_assignments_[neighbor-1]) {
flow_edges_[edge_ids[i]-1] = true;
if (st.get_id() == subtree::s) {
if (s_.get_current_max() > 0) {
for (node_id n : s_.reduce_path(node)) {
q.push(n);
}
}
if (t_.get_current_max() > 0) {
t_.reduce_path(neighbor);
}
} else {
if (t_.get_current_max() > 0) {
for (node_id n : t_.reduce_path(node)) {
q.push(n);
}
}
if (s_.get_current_max() > 0) {
s_.reduce_path(neighbor);
}
}
// orphan nodes can be inserted again
for (const auto& n : s_.get_last_resid_orphans()) {
node_assignments_[n-1] = none;
}
for (const auto& n : t_.get_last_resid_orphans()) {
node_assignments_[n-1] = none;
}
flow_++;
if (st.get_current_max() > 0) break;
// ... or extends st
} else if (node_assignments_[neighbor-1] == none) {
node_assignments_[neighbor-1] = (st.get_id() == subtree::s) ? s : t;
st.add_node(st.get_current_max()+1, neighbor, node);
}
}
}
}
st.increment_current_max();
return true;
}
#include <cassert>
#include <iostream>
#include <vector>
#include <gp-bnb/bnb.hpp>
#include <gp-bnb/graph.hpp>
#include <gp-bnb/partition.hpp>
#include <gp-bnb/metis_reader.hpp>
int main() {
int main(int argc, char** argv) {
assert(argc > 1);
std::vector<std::string> args(argv, argv+argc);
// MetisReader example
std::string graphFile = "../test/inputs/delaunay_n10.graph";
std::string graphFile = args[1];
auto g = metis_reader().read(graphFile);
std::cout << "Number of nodes: " << g.num_nodes() << std::endl;
std::cerr << "Number of nodes: " << g.num_nodes() << std::endl;
std::string current_option;
gp_bnb::lb lb_algo = gp_bnb::lb::none;
for (int i = 2; i < argc; ++i) {
if (i%2 == 0) {
current_option = args[i];
} else {
if (current_option == "-l") {
if (args[i] == "ek") {
lb_algo = gp_bnb::lb::ek;
} else if (args[i] == "ibfs") {
lb_algo = gp_bnb::lb::ibfs;
} else if (args[i] == "pr") {
lb_algo = gp_bnb::lb::pr;
} else if (args[i] == "gp") {
lb_algo = gp_bnb::lb::gp;
} else if (args[i] == "fa") {
lb_algo = gp_bnb::lb::fa;
}
}
}
}
auto sol = gp_bnb::solver(g, lb_algo);
sol.solve();
/*
int i = 1;
for(auto g : sol.best_solution()){
std::cerr << i++ << ": " << g << std::endl;
}
*/
}
......@@ -7,29 +7,15 @@ partition::partition(graph& g) : graph_(g) {
node_assignments_ = std::vector<partition::subgraph>(g.num_nodes(), none);
// Initializes node counting map
nodes_[sg_a] = 0;
nodes_[sg_b] = 0;
nodes_[none] = g.num_nodes();
}
unsigned int partition::num_nodes_of(subgraph sg) const {
return nodes_.at(sg);
}
unsigned int partition::current_objective() const {
return current_objective_;
}
partition::subgraph partition::assigned_subgraph_of(node_id v) const {
return node_assignments_[v-1];
nodes_ = std::vector<unsigned int> { 0, 0, g.num_nodes() };
}
void partition::assign_node(node_id v, subgraph sg) {
assert(node_assignments_[v-1] != none);
assert(node_assignments_[v-1] == none);
// Increments current objectives
for (auto const& target : graph_.get_adjacency(v)) {
if (node_assignments_[target-1] == -sg) {
if (node_assignments_[target-1] == (sg+1)%2) {
current_objective_++;
}
}
......@@ -43,11 +29,11 @@ void partition::assign_node(node_id v, subgraph sg) {
void partition::unassign_node(node_id v) {
subgraph sg = node_assignments_[v-1];
assert(sg == none);
assert(sg != none);
// Decrements current objectives
for (auto const& target : graph_.get_adjacency(v)) {
if (node_assignments_[target-1] == -sg) {
if (node_assignments_[target-1] == (sg+1)%2) {
current_objective_--;
}
}
......
#include <limits>
#include <gp-bnb/push_relabel.hpp>
// initialization of sources and sinks not elegant, but useful
push_relabel::push_relabel(const graph &g)
: g_(g) {
};
void push_relabel::reset(std::vector<node_id>& sources, std::vector<node_id>& sinks) {
sources_ = &sources;
sinks_ = &sinks;
// Initial flow value
flow_value_ = 0;
// Initialize all vectors
labels_.assign(g_.num_nodes() + 1, 0);
flow_.assign(g_.num_nodes() + 1, std::vector<int>(g_.num_nodes() + 1, 0));
excess_.assign(g_.num_nodes() + 1, 0);
sources_and_sinks_.assign(g_.num_nodes() + 1, 0);
// Sources marked as 1, sinks marked as -1. All the other nodes are 0.
for (unsigned int i = 0; i < sources_->size(); ++i) {
sources_and_sinks_[sources_->operator[](i)] = 1;
}
for (unsigned int i = 0; i < sinks_->size(); ++i) {
sources_and_sinks_[sinks_->operator[](i)] = -1;
}
};
void push_relabel::push(node_id u, node_id v) {
int d = std::min(excess_[u], 1 - flow_[u][v]);
flow_[u][v] += d;
flow_[v][u] -= d;
excess_[u] -= d;
excess_[v] += d;
if (d && excess_[v] == d) {
excess_nodes_.push(v);
}
}
void push_relabel::relabel(node_id u) {
int d = std::numeric_limits<int>::max();
const std::vector<node_id> & neighbors = g_.get_adjacency(u);
for (auto v : neighbors) {
if (1 - flow_[u][v] > 0)
d = std::min(d, labels_[v]);
}
if (d < std::numeric_limits<int>::max())
labels_[u] = d + 1;
}
void push_relabel::discharge(node_id u) {
while (excess_[u] > 0) {
const std::vector<node_id> & neighbors = g_.get_adjacency(u);
bool push_possible = false;
for (auto v : neighbors) {
if (1 - flow_[u][v] > 0 && labels_[u] > labels_[v]) {
push(u, v);
push_possible = true;
}
}
if (!push_possible)
relabel(u);
}
}
/* Preflow: Labels for source nodes - |V|.
Excess for source nodes - inf.
Push all outgoing edges from source nodes. */
void push_relabel::preflow() {
int num_nodes = g_.num_nodes();
for (unsigned int i = 0; i < sources_->size(); ++i) {
node_id s = sources_->operator[](i);
labels_[s] = num_nodes;
excess_[s] = std::numeric_limits<int>::max();
}
for (unsigned int i = 0; i < sources_->size(); ++i) {
node_id s = sources_->operator[](i);
const std::vector<node_id> & neighbors = g_.get_adjacency(s);
for (auto n : neighbors) {
if (sources_and_sinks_[n] != 1) // if n is not a source node
push(s, n);
}
}
}
void push_relabel::run() {
preflow();
while (!excess_nodes_.empty()) {
int u = excess_nodes_.front();
excess_nodes_.pop();
// if u is not a source and not a sink
if (sources_and_sinks_[u] == 0)
discharge(u);
}
// Flow value is the sum of excesses in sinks
for (unsigned int i = 0; i < sinks_->size(); ++i) {
flow_value_ += excess_[sinks_->operator[](i)];
}
}
......@@ -6,11 +6,17 @@
#include <gp-bnb/graph.hpp>
#include <gp-bnb/partition.hpp>
#include <gp-bnb/edmonds_karp.hpp>
#include <gp-bnb/incremental_bfs.hpp>
#include <gp-bnb/push_relabel.hpp>
#include <gp-bnb/greedy_packing.hpp>
namespace gp_bnb {
using subgraph = partition::subgraph;
enum class lb : char { ek, ibfs, pr, gp, fa, none };
// Represents the current path throught the search tree.
struct trail_state {
private:
......@@ -47,10 +53,10 @@ private:
};
// Main solver structure. Puts everything together.
struct solver {
class solver {
public:
// Constructor
solver(graph& g);
solver(graph& g, lb lb_algorithm);
// Read-only access to the nodes.
const graph &nodes() const {
......@@ -62,8 +68,10 @@ struct solver {
return best_solution_;
}
unsigned int get_lower();
// Expand a search tree node, i.e., assigns an node to a partition and update all data structures.
void expand(node_id node, subgraph sg);
void expand(node_id node, subgraph sg, subgraph alt);
// Performs backtracking after the solver ran into a dead end,
// i.e., the current branch has been pruned.
......@@ -80,9 +88,18 @@ private:
partition partition_;
trail_state trail_;
lb lb_algorithm_;
incremental_bfs i_bfs_;
edmonds_karp ek_;
push_relabel pr_;
greedy_packing gp_;
std::vector<node_id> current_sources_;
std::vector<node_id> current_sinks_;
// Value of best solution seen so far.
std::vector<subgraph> best_solution_;
unsigned int best_objective_ = 0;
std::vector<node_id> sources_, sinks_;
};
} // namespace gp_bnb
......
#ifndef EDMONDSKARP_H_
#define EDMONDSKARP_H_
#include <vector>
#include <gp-bnb/graph.hpp>
class edmonds_karp {
private:
const graph &g_;
std::vector<node_id>* sources_;
std::vector<node_id>* sinks_;
std::vector<int> sources_and_sinks_;
unsigned int flow_;
std::vector<bool> flow_edges_;
/**
* Performs a breadth-first search on the graph from the source node to find an augmenting path to the sink node respecting the flow values
* @param pred Used to store the path from the source to the sink.
* @return The sink node.
*/
node_id bfs(std::vector<std::pair<node_id ,edge_id>> &pred) const;
public:
/**
* Constructs an instance of the EdmondsKarp algorithm for the given graph
* @param graph The graph.
*/
edmonds_karp(const graph &g);
/** @brief Resets the members and the subtrees
* @param List of new sources for S-T-cut
* @param List of new sinks for S-T-cut
*/
void reset(std::vector<node_id>& sources, std::vector<node_id>& sinks);
/**
* Computes the maximum flow, executes the EdmondsKarp algorithm.
* For unweighted, undirected Graphs.
*/
void run();
/**
* Returns the value of the maximum flow from source to sink.
*
* @return The maximum flow value
*/
int get_max_flow() const {
return flow_;
};
};
#endif /* EDMONDSKARP_H_ */
......@@ -4,6 +4,7 @@
#include <vector>
using node_id = unsigned int;
using edge_id = unsigned int;
// Represents the input graph to be partitioned
class graph {
......@@ -17,17 +18,44 @@ public:
/** @brief Returns the number of nodes of the graph
* @return Number of nodes
*/
unsigned int num_nodes() const;
unsigned int num_nodes() const {
return nodes_;
};
/** @brief Returns the number of edges in the graph
* @return Number of edges after have been indexed
*/
unsigned int num_edges() const {
return edges_;
};
/** @brief Provides access to the adjacency of a node
* @param Node Id
* @return Adjacency of the node
*/
std::vector<unsigned int> get_adjacency(node_id v) const;
const std::vector<unsigned int>& get_adjacency(node_id v) const {
return adjacency_list_[v-1];
};
/** @brief Provides access to the edge ids of a node
* @param Node Id
* @return Edge ids of the node
*/
const std::vector<unsigned int>& get_edge_ids(node_id v) const {
return indexed_edges_[v-1];
};
/** @brief Returns the id of an edge after calling index_edges()
* @param Two Node ids (u, v)
* @return Edge id
*/
edge_id get_edge_id(node_id u, node_id v) const;
private:
unsigned int nodes_;
unsigned int edges_;
std::vector<std::vector<unsigned int>> adjacency_list_;
std::vector<std::vector<edge_id>> indexed_edges_;
};
#endif
#ifndef GREEDYPACKING_H_
#define GREEDYPACKING_H_
#include <queue>
#include <vector>
#include <gp-bnb/graph.hpp>
#include <gp-bnb/incremental_bfs.hpp>
#include <gp-bnb/partition.hpp>
#include <iostream>
class greedy_packing{
public:
/** @brief Initializes a greedy-packing instance
* @param Graph to be partitioned
* @param iBFS instance to be used
* @param bool, if bound with flow should be used
*/
greedy_packing(graph& g, incremental_bfs& ibfs, bool with_flow);
/** @brief executes the GP algortihm
*/
void run();
/** @brief resets the already partitioned sets a and b
* @param vector of nodes in set a
* @param vector of nodes in set b
*/
void reset(std::vector<node_id>& a, std::vector<node_id>& b);
/** @brief executes the forced assignments algorithm
* @param node for which we decide the next branch
* @return pair of bool and int where bool represents if node
* was in trivial block or not
* int: new upper bound if we would branch
*/
partition::subgraph forced_assignment(node_id node, unsigned int best);
/** @brief return the bound after execution
* @return packing-bound
*/
int get_max_flow() const{
return flow_ + bound;
};
private:
void bfs();
graph& graph_;
//partial partition into blocks a and b
//x is block with the neighbors of B
std::vector<node_id>* a_;
std::vector<node_id>* b_;
std::vector<node_id> x_;
std::vector<int> in_part;
incremental_bfs& i_bfs;
bool with_flow_, swapped;
std::vector<std::vector<node_id>> partitioning;
std::queue<node_id> q;
std::vector<bool>* flow_edges_;
std::vector<bool> visited;
unsigned int a_count, max_a, flow_, bound;
};
#endif /* GREEDY_PACKING_H_ */
#ifndef IBFSSUBTREE_HPP_
#define IBFSSUBTREE_HPP_
#include <unordered_set>
#include <vector>
#include "graph.hpp"
using label = unsigned int;
using node_id = unsigned int;
class ibfs_subtree {
public:
/** @brief Initializes a subtree for incremental bfs
* @param List of roots (sources or sinks)
*/
ibfs_subtree(int id, const graph& g, std::vector<bool>& flow_edges);
/** @brief Resets the subtree with new roots
* @param List of new roots
*/
void reset(std::vector<node_id>& roots);
/** @brief Deletes the path of the new flow of this subtree
* Part of the augmentation of this subtree
* @param Leaf with edge to the leaf of the other tree along the augmenting path
* @return List of inserted orphans with label current_max_
*/
std::vector<node_id> reduce_path(node_id leaf);
/** @brief Adds a node to the subtree with label l as a child of pred
* @param Label of the node to be added
* @param Node to be added
* @param Predecessor of the node to be added
*/
void add_node(label l, node_id node, node_id pred);
std::vector<node_id> get_front();
label get_current_max() {
return current_max_;
};
void set_max_adoption_label(label l) {
max_adoption_label_ = l;
};
int get_id() const {
return id_;
};
void increment_current_max() {
current_max_++;
};
const std::vector<node_id>& get_last_resid_orphans() const {
return last_resid_orphans_;
};
bool is_front_element(node_id node) const {
return labels_[node-1] == current_max_;
};
private:
int id_;
const graph& g_;
const label unassigned_;
std::vector<label> labels_;
std::vector<node_id> pred_;
std::vector<node_id> current_front_;
label current_max_ = 0;
label max_adoption_label_ = 0;
std::vector<bool>& flow_edges_;
std::vector<node_id> last_resid_orphans_;
label adopt(node_id orphan);
};
#endif /* IBFSSUBTREE_HPP_ */
#ifndef INCREMENTALBFS_H_
#define INCREMENTALBFS_H_
#include <vector>
#include "ibfs_subtree.hpp"
#include "graph.hpp"
class incremental_bfs {
public:
/** @brief Initializes an incremental BFS instance
* @param Graph to be partitioned
*/
incremental_bfs(const graph& g);
/** @brief Resets the members and the subtrees
* @param List of new sources for S-T-cut
* @param List of new sinks for S-T-cut
*/
void reset(std::vector<node_id>& sources, std::vector<node_id>& sinks);
/** @brief Executes the IBFS algorithm
*/
void run();
/** @brief Returns the flow value after execution, which corresponds to the minimal S-T-cut
*/
unsigned int get_max_flow() const {
return flow_;
};
/** @brief Returns edges with flow > 0
*/
std::vector<bool>& get_flow_edges() {
return flow_edges_;
};
private:
enum subtree { s = -1, t = 1, none, s_root, t_root };
const graph& g_;
ibfs_subtree s_;
ibfs_subtree t_;
std::vector<subtree> node_assignments_;
unsigned int flow_ = 0;
std::vector<bool> flow_edges_;
bool grow(ibfs_subtree& st);
};
#endif /* INCREMENTALBFS_H_ */
#ifndef PARTITION_HPP
#define PARTITION_HPP
#include <map>
#include <vector>
#include <gp-bnb/graph.hpp>
......@@ -10,7 +9,7 @@ using node_id = unsigned int;
// Represents potential solutions
class partition {
public:
enum subgraph { sg_a = -1, sg_b = 1, none = 0 };
enum subgraph { sg_a = 0, sg_b = 1, none = 2 };
/** @brief Initializes an empty partition
* @param Pointer to the graph to be partitioned
......@@ -21,18 +20,24 @@ public:
* @param Subgraph A, B or none
* @return Number of nodes of sg
*/
unsigned int num_nodes_of(subgraph sg) const;
unsigned int num_nodes_of(subgraph sg) const {
return nodes_.at(sg);
};
/** @brief Gets the number of edges between subgraph A and B
* @return Objective to be minimized
*/
unsigned int current_objective() const;
unsigned int current_objective() const {
return current_objective_;
};
/** @brief Gets the assignment of a node
* @param Node Id
* @return Subgraph A, B or none
*/
subgraph assigned_subgraph_of(node_id v) const;
subgraph assigned_subgraph_of(node_id v) const {
return node_assignments_[v-1];
};
/** @brief Assigns a node to a subgraph
* @param Node Id
......@@ -48,7 +53,7 @@ public:
private:
graph graph_;
std::vector<subgraph> node_assignments_;
std::map<subgraph,unsigned int> nodes_;
std::vector<unsigned int> nodes_;
unsigned int current_objective_ = 0;
};
......