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
#ifndef PUSHRELABEL_H_
#define PUSHRELABEL_H_
#include <vector>
#include <map>
#include <queue>
#include <gp-bnb/graph.hpp>
class push_relabel {
private:
const graph &g_;
std::vector<node_id>* sources_;
std::vector<node_id>* sinks_;
std::vector<int> sources_and_sinks_;
std::vector<int> labels_, excess_;
std::vector<std::vector<int>> flow_;
std::queue<node_id> excess_nodes_;
int flow_value_;
void push(node_id u, node_id v);
void preflow();
void relabel(node_id u);
void discharge(node_id u);
public:
/**
* Constructs an instance of the Push-Relabel algorithm for the given graph, sources and sinks
* @param graph The graph.
* @param sources Vector of source nodes.
* @param sinks Vector of sink nodes.
*/
push_relabel(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 Push-Relabel algorithm with discharge.
* For unweighted, undirected Graphs.
*/
void run();
/**
* Returns the value of the maximum flow from sources to sinks.
* @return The maximum flow value
*/
int get_max_flow() const {
return flow_value_;
};
};
#endif /* PUSHRELABEL_H_ */
......@@ -13,7 +13,11 @@ executable('gp-bnb',
'bnb/partition.cpp',
'bnb/metis_reader.cpp',
'bnb/edmonds_karp.cpp',
'bnb/incremental_bfs.cpp',
'bnb/ibfs_subtree.cpp',
'bnb/push_relabel.cpp',
'bnb/bnb.cpp',
'bnb/greedy_packing.cpp',
include_directories: inc)
......
......@@ -8,21 +8,105 @@
TEST_CASE("BnbTest") {
//test partitioning of tiny graph
std::string graph = "../test/inputs/tiny_01.graph";
auto g = metis_reader().read(graph);
auto sol = gp_bnb::solver(g);
auto sol = gp_bnb::solver(g, gp_bnb::lb::none);
sol.solve();
std::vector<partition::subgraph> f= sol.best_solution();
//node 1, 2,3 and 5 in one partition
REQUIRE(f[0] == f[1]);
REQUIRE(f[1] == f[2]);
REQUIRE(f[2] == f[4]);
//node 4, 6, 7 in the other one
REQUIRE(f[3] == f[5]);
REQUIRE(f[5] == f[6]);
//test solver
//
//test expand-function
//test backtrack-function
//test next_possible_subgraph
//tests partition functions
//
node_id node;
node = 2;
partition::subgraph sg;
sg = partition::subgraph::sg_a;
partition par(g);
REQUIRE(par.num_nodes_of(partition::sg_a) == 0);
REQUIRE(par.num_nodes_of(partition::sg_b) == 0);
REQUIRE(par.num_nodes_of(partition::none) == 7);
REQUIRE(par.assigned_subgraph_of(node) == partition::subgraph::none);
//test partition::assign_node
par.assign_node(node, sg);
REQUIRE(par.assigned_subgraph_of(node) == partition::subgraph::sg_a);
REQUIRE(par.num_nodes_of(partition::sg_a) == 1);
REQUIRE(par.num_nodes_of(partition::none) == 6);
REQUIRE(par.num_nodes_of(partition::sg_b) == 0);
node = 4;
sg = partition::subgraph::sg_b;
par.assign_node(node, sg);
REQUIRE(par.assigned_subgraph_of(node) == partition::subgraph::sg_b);
REQUIRE(par.num_nodes_of(partition::sg_a) == 1);
REQUIRE(par.num_nodes_of(partition::none) == 5);
REQUIRE(par.num_nodes_of(partition::sg_b) == 1);
//REQUIRE_THROWS(par.assign_node(node, partition::subgraph::none));
//REQUIRE_THROWS(par.unassign_node(3));
//test partition::unassign_node
node = 2;
par.unassign_node(node);
REQUIRE(par.assigned_subgraph_of(node) == partition::subgraph::none);
REQUIRE(par.num_nodes_of(partition::sg_a) == 0);
REQUIRE(par.num_nodes_of(partition::none) == 6);
REQUIRE(par.num_nodes_of(partition::sg_b) == 1);
node = 4;
par.unassign_node(node);
REQUIRE(par.assigned_subgraph_of(node) == partition::subgraph::none);
REQUIRE(par.num_nodes_of(partition::sg_a) == 0);
REQUIRE(par.num_nodes_of(partition::none) == 7);
REQUIRE(par.num_nodes_of(partition::sg_b) == 0);
//trail_state
//
auto tr = gp_bnb::trail_state();
node = 2;
REQUIRE(tr.length() == 0);
//test trail_state::push_node
tr.push_node(node, partition::subgraph::sg_a);
REQUIRE(tr.length() == 1);
REQUIRE(tr.node_at(0) == 2);
REQUIRE(tr.alternative_at(0) == partition::sg_a);
node = 3;
tr.push_node(node, partition::subgraph::sg_b);
REQUIRE(tr.length() == 2);
REQUIRE(tr.node_at(1) == 3);
REQUIRE(tr.alternative_at(1) == partition::sg_b);
REQUIRE(f[0] == -1);
REQUIRE(f[1] == -1);
REQUIRE(f[2] == -1);
REQUIRE(f[3] == 1);
REQUIRE(f[4] == -1);
REQUIRE(f[5] == 1);
REQUIRE(f[6] == 1);
//test trail_state::pop
tr.pop();
REQUIRE(tr.length() == 1);
REQUIRE(tr.node_at(0) == 2);
REQUIRE(tr.alternative_at(0) == partition::sg_a);
tr.pop();
REQUIRE(tr.length() == 0);
}
\ No newline at end of file
}
......@@ -7,16 +7,115 @@
// Tests for Edmonds-Karp Max Flow algorithm
TEST_CASE("EdmondsKarpMaxFlow") {
std::string graph_file = "../test/inputs/tiny_01.graph";
graph g = metis_reader().read(graph_file);
// Same graph instance as in IBFS test
std::vector<std::vector<node_id>> adjacency_list {
{ 2, 7 }, // 1
{ 1, 3, 4 }, // 2
{ 2, 5 }, // 3
{ 2, 5 }, // 4
{ 3, 4, 6}, // 5
{ 5, 8 }, // 6
{ 1, 8 }, // 7
{ 6, 7 } // 8
};
node_id source = 1;
node_id sink = 7;
edmonds_karp ek = edmonds_karp(g, source, sink);
graph g(adjacency_list);
std::vector<node_id> sources { 1 };
std::vector<node_id> sinks { 8 };
edmonds_karp ek = edmonds_karp(g);
ek.reset(sources, sinks);
ek.run();
int max_flow = ek.get_max_flow();
REQUIRE(max_flow == 2);
}
\ No newline at end of file
//Testing multiple sources and sinks
std::vector<std::vector<node_id>> adjacency_list2 {
{ 5, 2, 3 },
{ 1, 3, 4 },
{ 5, 4, 2, 1 },
{ 2, 3, 6, 7 },
{ 1, 3, 6 },
{ 5, 4, 7 },
{ 6, 4 }
};
graph g2(adjacency_list2);
// 1 Case for g2
std::vector<node_id> sources2 { 1 };
std::vector<node_id> sinks2 { 6, 7 };
edmonds_karp ek2 = edmonds_karp(g2);
ek2.reset(sources2, sinks2);
ek2.run();
int max_flow2 = ek2.get_max_flow();
REQUIRE(max_flow2 == 3);
// 2 Case for g2
std::vector<node_id> sources3 { 2, 3 };
std::vector<node_id> sinks3 { 5, 6 };
edmonds_karp ek3 = edmonds_karp(g2);
ek3.reset(sources3, sinks3);
ek3.run();
int max_flow3 = ek3.get_max_flow();
REQUIRE(max_flow3 == 4);
// 3 Case for g2 (balanced 2-partition)
std::vector<node_id> sources4 { 1, 4, 6 };
std::vector<node_id> sinks4 { 2, 3, 5, 7 };
edmonds_karp ek4 = edmonds_karp(g2);
ek4.reset(sources4, sinks4);
ek4.run();
int max_flow4 = ek4.get_max_flow();
REQUIRE(max_flow4 == 8);
// 4 Case for g2 (balanced 2-partition)
std::vector<node_id> sources5 { 1, 2, 3, 5 };
std::vector<node_id> sinks5 { 4, 6, 7 };
edmonds_karp ek5 = edmonds_karp(g2);
ek5.reset(sources5, sinks5);
ek5.run();
int max_flow5 = ek5.get_max_flow();
REQUIRE(max_flow5 == 3);
// Testing on a graph with ~1000 nodes
std::string graph_file = "../test/inputs/delaunay_n10.graph";
graph g3 = metis_reader().read(graph_file);
std::vector<node_id> sources6 = {1, 3, 8, 9, 100};
std::vector<node_id> sinks6 = {50, 60, 88};
edmonds_karp ek6 = edmonds_karp(g3);
ek6.reset(sources6, sinks6);
ek6.run();
int max_flow6 = ek6.get_max_flow();
REQUIRE(max_flow6 == 18);
// Testing add_source() function with delaunay_n10.graph
std::vector<node_id> sources7 = {1, 3, 8, 9, 100};
std::vector<node_id> sinks7 = {50, 60, 88};
edmonds_karp ek7 = edmonds_karp(g3);
ek7.reset(sources7, sinks7);
ek7.run();
int max_flow7 = ek7.get_max_flow();
REQUIRE(max_flow7 == 18);
}
......@@ -8,16 +8,18 @@
// Example 1.
TEST_CASE("GraphStructureTest") {
// Petersen Graph
std::vector<std::vector<unsigned int>> adjacencies {
{2, 3, 4}, {1, 3, 7},
{2, 4, 8}, {3, 5, 9},
{1, 4, 10}, {1, 8, 9},
{2, 9, 10}, {3, 6, 10},
{4, 6, 7}, {5, 7, 8}
{2, 3}, //1
{1, 3, 4}, //2
{1, 2}, //3
{2} //4
};
graph g = graph(adjacencies);
REQUIRE(g.num_nodes() == 10);
}
\ No newline at end of file
REQUIRE(g.num_nodes() == 4);
REQUIRE(g.get_edge_id(1,2) == g.get_edge_id(2,1));
REQUIRE(g.get_edge_id(1,3) == g.get_edge_id(3,1));
REQUIRE(g.get_edge_id(2,4) == g.get_edge_id(4,2));
}
#include <vector>
#include <catch2/catch.hpp>
#include <gp-bnb/incremental_bfs.hpp>
#include <gp-bnb/graph.hpp>
#include <gp-bnb/metis_reader.hpp>
// Tests for Incremental BFS Max Flow algorithm
TEST_CASE("IncrementalBFSMaxFlow") {
std::vector<std::vector<node_id>> adjacency_list {
{ 2, 7 }, // 1
{ 1, 3, 4 }, // 2
{ 2, 5 }, // 3
{ 2, 5 }, // 4
{ 3, 4, 6}, // 5
{ 5, 8 }, // 6
{ 1, 8 }, // 7
{ 6, 7 } // 8
};
graph g (adjacency_list) ;
std::vector<node_id> sources { 1 };
std::vector<node_id> sinks { 8 };
incremental_bfs ibfs = incremental_bfs(g);
ibfs.reset(sources, sinks);
ibfs.run();
int max_flow = ibfs.get_max_flow();
REQUIRE(max_flow == 2);
std::string graph_file = "../test/inputs/tiny_01.graph";
graph g2 = metis_reader().read(graph_file);
std::vector<node_id> sources2 { 1 };
std::vector<node_id> sinks2 { 7 };
incremental_bfs ibfs2 = incremental_bfs(g2);
ibfs2.reset(sources2, sinks2);
ibfs2.run();
int max_flow2 = ibfs2.get_max_flow();
REQUIRE(max_flow2 == 2);
graph_file = "../test/inputs/delaunay_n10.graph";
graph g3 = metis_reader().read(graph_file);
std::vector<node_id> sources3 = {1, 3, 8, 9, 100};
std::vector<node_id> sinks3 = {50, 60, 88};
incremental_bfs ibfs3 = incremental_bfs(g3);
ibfs3.reset(sources3, sinks3);
ibfs3.run();
int max_flow3 = ibfs3.get_max_flow();
REQUIRE(max_flow3 == 18);
}
40 92
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
1 3 21
1 2 4 22
1 3 5 23
1 4 6 24
1 5 7 25
1 6 8 26
1 7 9 27
1 8 10 28
1 9 11 29
1 10 12 30
1 11 13 31
1 12 14 32
1 13 15 33
1 14 16 34
1 15 17 35
1 16 18 36
1 17 19 37
1 18 20 38
1 19 39
40 2 22
40 3 21 23
40 4 22 24
40 5 23 25
40 6 24 26
40 7 25 27
40 8 26 28
40 9 27 28
40 10 28 30
40 11 29 31
40 12 30 32
40 13 31 33
40 14 32 34
40 15 33 35
40 16 34 36
40 17 35 37
40 18 36 38
40 19 37 39
40 20 38
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
\ No newline at end of file
......@@ -3,12 +3,17 @@ testexe = executable(
'graph_test.cpp',
'reader_test.cpp',
'edmonds_karp_test.cpp',
'incremental_bfs_test.cpp',
'bnb_test.cpp', # tests source files to be compiled
'../bnb/graph.cpp',
'../bnb/partition.cpp',
'../bnb/metis_reader.cpp',
'../bnb/edmonds_karp.cpp',
'../bnb/incremental_bfs.cpp',
'../bnb/ibfs_subtree.cpp',
'../bnb/push_relabel.cpp',
'../bnb/bnb.cpp',
'../bnb/greedy_packing.cpp',
include_directories : inc) # declared include directories in root :code:`meson.build`
# test execution
......