From ec6e978994f644a3e4b464d74dffab826759d457 Mon Sep 17 00:00:00 2001 From: Freark van der Berg Date: Thu, 28 May 2020 11:24:31 +0200 Subject: [PATCH] Adds support for disconnected graphs to the sloan ordering algorithm --- include/boost/graph/sloan_ordering.hpp | 133 +++++++++++++++++++------ test/sloan_disconnected.cpp | 43 ++++++++ 2 files changed, 148 insertions(+), 28 deletions(-) create mode 100644 test/sloan_disconnected.cpp diff --git a/include/boost/graph/sloan_ordering.hpp b/include/boost/graph/sloan_ordering.hpp index 88f845b81..92d919db7 100644 --- a/include/boost/graph/sloan_ordering.hpp +++ b/include/boost/graph/sloan_ordering.hpp @@ -34,7 +34,7 @@ //////////////////////////////////////////////////////////// // // Sloan-Algorithm for graph reordering -//(optimzes profile and wavefront, not primiraly bandwidth +//(optimizes profile and wavefront, not primarily bandwidth) // //////////////////////////////////////////////////////////// @@ -43,7 +43,7 @@ namespace boost ///////////////////////////////////////////////////////////////////////// // Function that returns the maximum depth of -// a rooted level strucutre (RLS) +// a rooted level structure (RLS) // ///////////////////////////////////////////////////////////////////////// template < class Distance > typename Distance::value_type RLS_depth(Distance& d) @@ -64,7 +64,7 @@ template < class Distance > typename Distance::value_type RLS_depth(Distance& d) ///////////////////////////////////////////////////////////////////////// // Function that returns the width of the largest level of -// a rooted level strucutre (RLS) +// a rooted level structure (RLS) // ///////////////////////////////////////////////////////////////////////// template < class Distance, class my_int > @@ -112,7 +112,9 @@ typename graph_traits< Graph >::vertex_descriptor sloan_start_end_vertices( typedef typename property_map< Graph, vertex_index_t >::const_type VertexID; - s = *(vertices(G).first); + typedef typename property_traits< ColorMap >::value_type ColorValue; + typedef color_traits< ColorValue > Color; + Vertex e = s; Vertex i; Degree my_degree = get(degree, s); @@ -146,7 +148,10 @@ typename graph_traits< Graph >::vertex_descriptor sloan_start_end_vertices( { dummy = get(degree, *ui); - if (dummy < my_degree) + // Only consider white nodes, i.e. nodes that are not yet partitioned + // into a connected component. This allows the algorithm to find the + // optimal start node amongst all the remaining (white) nodes. + if (dummy < my_degree && get(color, *ui) == Color::white()) { my_degree = dummy; s = *ui; @@ -159,12 +164,16 @@ typename graph_traits< Graph >::vertex_descriptor sloan_start_end_vertices( } // end 1 + // Mark all nodes in the current connected component black. The current + // connected component is the connected component where s is a part of. + depth_first_visit(G, s, dfs_visitor<>(), color); + do { new_start = false; // Setting the loop repetition status to false // step 2 - // initialize the the disance std-vector with 0 + // initialize the the distance std-vector with 0 for (typename std::vector< typename graph_traits< Graph >::vertices_size_type >::iterator iter = dist.begin(); @@ -210,7 +219,7 @@ typename graph_traits< Graph >::vertex_descriptor sloan_start_end_vertices( { i = degree_queue.top(); // getting the node with the lowest degree // from the degree queue - degree_queue.pop(); // ereasing the node with the lowest degree from + degree_queue.pop(); // erasing the node with the lowest degree from // the degree queue // generating a RLS @@ -224,23 +233,31 @@ typename graph_traits< Graph >::vertex_descriptor sloan_start_end_vertices( boost::visitor(make_bfs_visitor( record_distances(dist_pmap, on_tree_edge())))); - // Calculating depth and width of the rooted level - h_i = RLS_depth(dist); - w_i = RLS_max_width(dist, h_i); - - // Testing for termination - if ((h_i > h_s) && (w_i < w_e)) - { - h_s = h_i; - s = i; - while (!degree_queue.empty()) - degree_queue.pop(); - new_start = true; - } - else if (w_i < w_e) + // Only consider nodes that are a part of the current connected + // component. These nodes will be black due to the DFS performed + // earlier. Other nodes are green or white. Green is for a connected + // component that has already been visited and white for nodes that + // are yet to be visited. + if (get(color, i) == Color::black()) { - w_e = w_i; - e = i; + // Calculating depth and width of the rooted level + h_i = RLS_depth(dist); + w_i = RLS_max_width(dist, h_i); + + // Testing for termination + if ((h_i > h_s) && (w_i < w_e)) + { + h_s = h_i; + s = i; + while (!degree_queue.empty()) + degree_queue.pop(); + new_start = true; + } + else if (w_i < w_e) + { + w_e = w_i; + e = i; + } } } // end 6 @@ -361,7 +378,7 @@ OutputIterator sloan_ordering(Graph& g, Color::red()); // giving the vertex an active status put(priority, v, get(priority, v) + W2); // updates the priority - // for loop over alll adjacent vertices of v + // for loop over all adjacent vertices of v for (boost::tie(ei2, ei2_end) = out_edges(v, g); ei2 != ei2_end; ++ei2) { @@ -425,11 +442,71 @@ inline OutputIterator sloan_ordering(Graph& G, OutputIterator permutation, { typedef typename boost::graph_traits< Graph >::vertex_descriptor Vertex; - Vertex s, e; - e = sloan_start_end_vertices(G, s, color, degree); + std::deque< Vertex > vertex_queue; + typedef typename property_traits< Color >::value_type ColorValue; + typedef color_traits< ColorValue > ColorForStart; + + // Mark all nodes white + BGL_FORALL_VERTICES_T(v, G, Graph) put(color, v, ColorForStart::white()); + + // Find the start and end nodes for the sloan algorithm for each connected + // component. + // The outer loop is needed because sloan_start_end_vertices() can + // change the start node and thus the component. This may cause a component + // to be unpermutated. This happens for example in a graph with 4 nodes and + // a single edge between node 0 and 1: the start node will change twice, + // from 0 to 2 and from 1 to 3, thus the nodes 0 and 1 will not be + // considered again, if not for this outer loop. + bool foundComponent; + do + { + foundComponent = false; + BGL_FORALL_VERTICES_T(v, G, Graph) + { + if (get(color, v) == ColorForStart::white()) + { + Vertex s, e; + s = v; + + foundComponent = true; + + // Find the start and end edge for the current connected + // component. The current connected component is the connected + // where s is a part of. Note that this call could change s when + // a better start node was determined from all remaining nodes + // (the white nodes). The node s is only used when there is no + // better start node. Due to the DFS within this call, after the + // call all nodes in the connected component are marked black. + e = sloan_start_end_vertices(G, s, color, degree); + + // To make the nodes unavailable for subsequent calls to + // sloan_start_end_vertices(), change all black nodes to green. + for (int n = 0; n < num_vertices(G); ++n) + { + if (get(color, n) == ColorForStart::black()) + { + put(color, n, ColorForStart::green()); + } + } + + // Remember the start and end nodes + vertex_queue.push_back(s); + vertex_queue.push_back(e); + } + } + } while (foundComponent); - return sloan_ordering( - G, s, e, permutation, color, degree, priority, W1, W2); + // Perform the sloan ordering per connected component + for (typename std::deque< Vertex >::iterator i = vertex_queue.begin(); + i != vertex_queue.end();) + { + Vertex s = *i++; + Vertex e = *i++; + permutation = sloan_ordering( + G, s, e, permutation, color, degree, priority, W1, W2); + } + + return permutation; } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/test/sloan_disconnected.cpp b/test/sloan_disconnected.cpp new file mode 100644 index 000000000..856ff411f --- /dev/null +++ b/test/sloan_disconnected.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +using namespace std; +using namespace boost; + +int main(int argc, char**) +{ + typedef adjacency_list< setS, vecS, undirectedS, + property< vertex_color_t, default_color_type, + property< vertex_degree_t, int, + property< vertex_priority_t, double > > > > + Graph; + + typedef graph_traits< Graph >::vertex_descriptor Vertex; + typedef graph_traits< Graph >::vertices_size_type size_type; + + Graph g = Graph(4); + property_map< Graph, vertex_index_t >::type index_map + = get(vertex_index, g); + + std::vector< Vertex > inv_perm(num_vertices(g)); + std::vector< size_type > perm(num_vertices(g)); + + add_edge(0, 1, g); + add_edge(0, 2, g); + + sloan_ordering(g, inv_perm.begin(), get(vertex_color, g), + make_degree_map(g), get(vertex_priority, g), 1, 2); + + int correct[] = { 3, 1, 0, 2 }; + + size_t idx = 0; + for (typename std::vector< Vertex >::const_iterator i = inv_perm.begin(); + i != inv_perm.end(); ++i) + { + BOOST_ASSERT(correct[idx] == *i); + ++idx; + } +}