diff --git a/include/boost/graph/minimum_degree_ordering.hpp b/include/boost/graph/minimum_degree_ordering.hpp index 26cbf108..680d2faa 100644 --- a/include/boost/graph/minimum_degree_ordering.hpp +++ b/include/boost/graph/minimum_degree_ordering.hpp @@ -114,7 +114,7 @@ namespace boost { Marker(size_type _num, VertexIndexMap index_map) : tag(1 - std::numeric_limits::max()), data(_num, - std::numeric_limits::max()), - id(index_map) {} + id(index_map) {} void mark_done(Vertex node) { data[id[node]] = done(); } @@ -195,7 +195,7 @@ namespace boost { typedef SignedInteger value_type; typedef typename std::vector::size_type size_type; degreelists_marker(size_type n, VertexIndexMap id) - : marks(n, 0), id(id) {} + : marks(n, 0), id(id) {} void mark_need_update(Vertex i) { marks[id[i]] = 1; } bool need_update(Vertex i) { return marks[id[i]] == 1; } bool outmatched_or_done (Vertex i) { return marks[id[i]] == -1; } @@ -259,10 +259,10 @@ namespace boost { }; template + class InversePermutationMap, + class PermutationMap, + class SuperNodeMap, + class VertexIndexMap> class mmd_impl { // Typedefs @@ -273,14 +273,14 @@ namespace boost { typedef typename Traits::vertex_descriptor vertex_t; typedef typename Traits::adjacency_iterator adj_iter; typedef iterator_property_map::iterator, - identity_property_map, vertex_t, vertex_t&> IndexVertexMap; + identity_property_map, vertex_t, vertex_t&> IndexVertexMap; typedef detail::Stacks Workspace; typedef bucket_sorter - DegreeLists; + DegreeLists; typedef Numbering - NumberingD; + NumberingD; typedef degreelists_marker - DegreeListsMarker; + DegreeListsMarker; typedef Marker MarkerP; // Data Members @@ -305,324 +305,324 @@ namespace boost { Workspace work_space; public: mmd_impl(Graph& g, size_type n_, int delta, DegreeMap degree, - InversePermutationMap inverse_perm, - PermutationMap perm, - SuperNodeMap supernode_size, - VertexIndexMap id) - : G(g), delta(delta), degree(degree), - inverse_perm(inverse_perm), - perm(perm), - supernode_size(supernode_size), - vertex_index_map(id), - index_vertex_vec(n_), - n(n_), - degreelists(n_ + 1, n_, degree, id), - numbering(inverse_perm, n_, vertex_index_map), - degree_lists_marker(n_, vertex_index_map), - marker(n_, vertex_index_map), - work_space(n_) + InversePermutationMap inverse_perm, + PermutationMap perm, + SuperNodeMap supernode_size, + VertexIndexMap id) + : G(g), delta(delta), degree(degree), + inverse_perm(inverse_perm), + perm(perm), + supernode_size(supernode_size), + vertex_index_map(id), + index_vertex_vec(n_), + n(n_), + degreelists(n_ + 1, n_, degree, id), + numbering(inverse_perm, n_, vertex_index_map), + degree_lists_marker(n_, vertex_index_map), + marker(n_, vertex_index_map), + work_space(n_) { - typename graph_traits::vertex_iterator v, vend; - size_type vid = 0; - for (tie(v, vend) = vertices(G); v != vend; ++v, ++vid) - index_vertex_vec[vid] = *v; - index_vertex_map = IndexVertexMap(&index_vertex_vec[0]); + typename graph_traits::vertex_iterator v, vend; + size_type vid = 0; + for (tie(v, vend) = vertices(G); v != vend; ++v, ++vid) + index_vertex_vec[vid] = *v; + index_vertex_map = IndexVertexMap(&index_vertex_vec[0]); - // Initialize degreelists. Degreelists organizes the nodes - // according to their degree. - for (tie(v, vend) = vertices(G); v != vend; ++v) { - put(degree, *v, out_degree(*v, G)); - degreelists.push(*v); - } + // Initialize degreelists. Degreelists organizes the nodes + // according to their degree. + for (tie(v, vend) = vertices(G); v != vend; ++v) { + put(degree, *v, out_degree(*v, G)); + degreelists.push(*v); + } } void do_mmd() { - // Eliminate the isolated nodes -- these are simply the nodes - // with no neighbors, which are accessible as a list (really, a - // stack) at location 0. Since these don't affect any other - // nodes, we can eliminate them without doing degree updates. - typename DegreeLists::stack list_isolated = degreelists[0]; - while (!list_isolated.empty()) { - vertex_t node = list_isolated.top(); - marker.mark_done(node); - numbering(node); - numbering.increment(); - list_isolated.pop(); - } - size_type min_degree = 1; - typename DegreeLists::stack list_min_degree = degreelists[min_degree]; + // Eliminate the isolated nodes -- these are simply the nodes + // with no neighbors, which are accessible as a list (really, a + // stack) at location 0. Since these don't affect any other + // nodes, we can eliminate them without doing degree updates. + typename DegreeLists::stack list_isolated = degreelists[0]; + while (!list_isolated.empty()) { + vertex_t node = list_isolated.top(); + marker.mark_done(node); + numbering(node); + numbering.increment(); + list_isolated.pop(); + } + size_type min_degree = 1; + typename DegreeLists::stack list_min_degree = degreelists[min_degree]; - while (list_min_degree.empty()) { - ++min_degree; - list_min_degree = degreelists[min_degree]; - } + while (list_min_degree.empty()) { + ++min_degree; + list_min_degree = degreelists[min_degree]; + } - // check if the whole eliminating process is done - while (!numbering.all_done()) { + // check if the whole eliminating process is done + while (!numbering.all_done()) { - size_type min_degree_limit = min_degree + delta; // WARNING - typename Workspace::stack llist = work_space.make_stack(); + size_type min_degree_limit = min_degree + delta; // WARNING + typename Workspace::stack llist = work_space.make_stack(); - // multiple elimination - while (delta >= 0) { + // multiple elimination + while (delta >= 0) { - // Find the next non-empty degree - for (list_min_degree = degreelists[min_degree]; - list_min_degree.empty() && min_degree <= min_degree_limit; - ++min_degree, list_min_degree = degreelists[min_degree]) - ; - if (min_degree > min_degree_limit) - break; + // Find the next non-empty degree + for (list_min_degree = degreelists[min_degree]; + list_min_degree.empty() && min_degree <= min_degree_limit; + ++min_degree, list_min_degree = degreelists[min_degree]) + ; + if (min_degree > min_degree_limit) + break; - const vertex_t node = list_min_degree.top(); - const size_type node_id = vertex_index_map[node]; - list_min_degree.pop(); - numbering(node); + const vertex_t node = list_min_degree.top(); + const size_type node_id = vertex_index_map[node]; + list_min_degree.pop(); + numbering(node); - // check if node is the last one - if (numbering.all_done(supernode_size[node])) { - numbering.increment(supernode_size[node]); - break; - } - marker.increment_tag(); - marker.mark_tagged(node); + // check if node is the last one + if (numbering.all_done(supernode_size[node])) { + numbering.increment(supernode_size[node]); + break; + } + marker.increment_tag(); + marker.mark_tagged(node); - this->eliminate(node); + this->eliminate(node); - numbering.increment(supernode_size[node]); - llist.push(node_id); - } // multiple elimination + numbering.increment(supernode_size[node]); + llist.push(node_id); + } // multiple elimination - if (numbering.all_done()) - break; + if (numbering.all_done()) + break; - this->update( llist, min_degree); - } + this->update( llist, min_degree); + } } // do_mmd() void eliminate(vertex_t node) { - typename Workspace::stack element_neighbor = work_space.make_stack(); + typename Workspace::stack element_neighbor = work_space.make_stack(); - // Create two function objects for edge removal - predicateRemoveEdge1 - p(G, marker, numbering, element_neighbor, vertex_index_map); + // Create two function objects for edge removal + predicateRemoveEdge1 + p(G, marker, numbering, element_neighbor, vertex_index_map); - predicate_remove_tagged_edges p2(G, marker); + predicate_remove_tagged_edges p2(G, marker); - // Reconstruct the adjacent node list, push element neighbor in a List. - remove_out_edge_if(node, p, G); - //during removal element neighbors are collected. + // Reconstruct the adjacent node list, push element neighbor in a List. + remove_out_edge_if(node, p, G); + //during removal element neighbors are collected. - while (!element_neighbor.empty()) { - // element absorb - size_type e_id = element_neighbor.top(); - vertex_t element = index_vertex_map[e_id]; - adj_iter i, i_end; - for (tie(i, i_end) = adjacent_vertices(element, G); i != i_end; ++i){ - vertex_t i_node = *i; - if (!marker.is_tagged(i_node) && !numbering.is_numbered(i_node)) { - marker.mark_tagged(i_node); - add_edge(node, i_node, G); - } - } - element_neighbor.pop(); - } - adj_iter v, ve; - for (tie(v, ve) = adjacent_vertices(node, G); v != ve; ++v) { - vertex_t v_node = *v; - if (!degree_lists_marker.need_update(v_node) - && !degree_lists_marker.outmatched_or_done(v_node)) { - degreelists.remove(v_node); - } - //update out edges of v_node - remove_out_edge_if(v_node, p2, G); + while (!element_neighbor.empty()) { + // element absorb + size_type e_id = element_neighbor.top(); + vertex_t element = index_vertex_map[e_id]; + adj_iter i, i_end; + for (tie(i, i_end) = adjacent_vertices(element, G); i != i_end; ++i){ + vertex_t i_node = *i; + if (!marker.is_tagged(i_node) && !numbering.is_numbered(i_node)) { + marker.mark_tagged(i_node); + add_edge(node, i_node, G); + } + } + element_neighbor.pop(); + } + adj_iter v, ve; + for (tie(v, ve) = adjacent_vertices(node, G); v != ve; ++v) { + vertex_t v_node = *v; + if (!degree_lists_marker.need_update(v_node) + && !degree_lists_marker.outmatched_or_done(v_node)) { + degreelists.remove(v_node); + } + //update out edges of v_node + remove_out_edge_if(v_node, p2, G); - if ( out_degree(v_node, G) == 0 ) { // indistinguishable nodes - supernode_size[node] += supernode_size[v_node]; - supernode_size[v_node] = 0; - numbering.indistinguishable(v_node, node); - marker.mark_done(v_node); - degree_lists_marker.mark(v_node); - } else { // not indistinguishable nodes - add_edge(v_node, node, G); - degree_lists_marker.mark_need_update(v_node); - } - } + if ( out_degree(v_node, G) == 0 ) { // indistinguishable nodes + supernode_size[node] += supernode_size[v_node]; + supernode_size[v_node] = 0; + numbering.indistinguishable(v_node, node); + marker.mark_done(v_node); + degree_lists_marker.mark(v_node); + } else { // not indistinguishable nodes + add_edge(v_node, node, G); + degree_lists_marker.mark_need_update(v_node); + } + } } // eliminate() template void update(Stack llist, size_type& min_degree) { - size_type min_degree0 = min_degree + delta + 1; + size_type min_degree0 = min_degree + delta + 1; - while (! llist.empty()) { - size_type deg, deg0 = 0; + while (! llist.empty()) { + size_type deg, deg0 = 0; - marker.set_multiple_tag(min_degree0); - typename Workspace::stack q2list = work_space.make_stack(); - typename Workspace::stack qxlist = work_space.make_stack(); + marker.set_multiple_tag(min_degree0); + typename Workspace::stack q2list = work_space.make_stack(); + typename Workspace::stack qxlist = work_space.make_stack(); - vertex_t current = index_vertex_map[llist.top()]; - adj_iter i, ie; - for (tie(i,ie) = adjacent_vertices(current, G); i != ie; ++i) { - vertex_t i_node = *i; - const size_type i_id = vertex_index_map[i_node]; - if (supernode_size[i_node] != 0) { - deg0 += supernode_size[i_node]; - marker.mark_multiple_tagged(i_node); - if (degree_lists_marker.need_update(i_node)) { - if (out_degree(i_node, G) == 2) - q2list.push(i_id); - else - qxlist.push(i_id); - } - } - } + vertex_t current = index_vertex_map[llist.top()]; + adj_iter i, ie; + for (tie(i,ie) = adjacent_vertices(current, G); i != ie; ++i) { + vertex_t i_node = *i; + const size_type i_id = vertex_index_map[i_node]; + if (supernode_size[i_node] != 0) { + deg0 += supernode_size[i_node]; + marker.mark_multiple_tagged(i_node); + if (degree_lists_marker.need_update(i_node)) { + if (out_degree(i_node, G) == 2) + q2list.push(i_id); + else + qxlist.push(i_id); + } + } + } - while (!q2list.empty()) { - const size_type u_id = q2list.top(); - vertex_t u_node = index_vertex_map[u_id]; - // if u_id is outmatched by others, no need to update degree - if (degree_lists_marker.outmatched_or_done(u_node)) { - q2list.pop(); - continue; - } - marker.increment_tag(); - deg = deg0; + while (!q2list.empty()) { + const size_type u_id = q2list.top(); + vertex_t u_node = index_vertex_map[u_id]; + // if u_id is outmatched by others, no need to update degree + if (degree_lists_marker.outmatched_or_done(u_node)) { + q2list.pop(); + continue; + } + marker.increment_tag(); + deg = deg0; - adj_iter nu = adjacent_vertices(u_node, G).first; - vertex_t neighbor = *nu; - if (neighbor == u_node) { - ++nu; - neighbor = *nu; - } - if (numbering.is_numbered(neighbor)) { - adj_iter i, ie; - for (tie(i,ie) = adjacent_vertices(neighbor, G); - i != ie; ++i) { - const vertex_t i_node = *i; - if (i_node == u_node || supernode_size[i_node] == 0) - continue; - if (marker.is_tagged(i_node)) { - if (degree_lists_marker.need_update(i_node)) { - if ( out_degree(i_node, G) == 2 ) { // is indistinguishable - supernode_size[u_node] += supernode_size[i_node]; - supernode_size[i_node] = 0; - numbering.indistinguishable(i_node, u_node); - marker.mark_done(i_node); - degree_lists_marker.mark(i_node); - } else // is outmatched - degree_lists_marker.mark(i_node); - } - } else { - marker.mark_tagged(i_node); - deg += supernode_size[i_node]; - } - } - } else - deg += supernode_size[neighbor]; + adj_iter nu = adjacent_vertices(u_node, G).first; + vertex_t neighbor = *nu; + if (neighbor == u_node) { + ++nu; + neighbor = *nu; + } + if (numbering.is_numbered(neighbor)) { + adj_iter i, ie; + for (tie(i,ie) = adjacent_vertices(neighbor, G); + i != ie; ++i) { + const vertex_t i_node = *i; + if (i_node == u_node || supernode_size[i_node] == 0) + continue; + if (marker.is_tagged(i_node)) { + if (degree_lists_marker.need_update(i_node)) { + if ( out_degree(i_node, G) == 2 ) { // is indistinguishable + supernode_size[u_node] += supernode_size[i_node]; + supernode_size[i_node] = 0; + numbering.indistinguishable(i_node, u_node); + marker.mark_done(i_node); + degree_lists_marker.mark(i_node); + } else // is outmatched + degree_lists_marker.mark(i_node); + } + } else { + marker.mark_tagged(i_node); + deg += supernode_size[i_node]; + } + } + } else + deg += supernode_size[neighbor]; - deg -= supernode_size[u_node]; - degree[u_node] = deg; //update degree - degreelists[deg].push(u_node); - //u_id has been pushed back into degreelists - degree_lists_marker.unmark(u_node); - if (min_degree > deg) - min_degree = deg; - q2list.pop(); - } // while (!q2list.empty()) + deg -= supernode_size[u_node]; + degree[u_node] = deg; //update degree + degreelists[deg].push(u_node); + //u_id has been pushed back into degreelists + degree_lists_marker.unmark(u_node); + if (min_degree > deg) + min_degree = deg; + q2list.pop(); + } // while (!q2list.empty()) - while (!qxlist.empty()) { - const size_type u_id = qxlist.top(); - const vertex_t u_node = index_vertex_map[u_id]; + while (!qxlist.empty()) { + const size_type u_id = qxlist.top(); + const vertex_t u_node = index_vertex_map[u_id]; - // if u_id is outmatched by others, no need to update degree - if (degree_lists_marker.outmatched_or_done(u_node)) { - qxlist.pop(); - continue; - } - marker.increment_tag(); - deg = deg0; - adj_iter i, ie; - for (tie(i, ie) = adjacent_vertices(u_node, G); i != ie; ++i) { - vertex_t i_node = *i; - if (marker.is_tagged(i_node)) - continue; - marker.mark_tagged(i_node); + // if u_id is outmatched by others, no need to update degree + if (degree_lists_marker.outmatched_or_done(u_node)) { + qxlist.pop(); + continue; + } + marker.increment_tag(); + deg = deg0; + adj_iter i, ie; + for (tie(i, ie) = adjacent_vertices(u_node, G); i != ie; ++i) { + vertex_t i_node = *i; + if (marker.is_tagged(i_node)) + continue; + marker.mark_tagged(i_node); - if (numbering.is_numbered(i_node)) { - adj_iter j, je; - for (tie(j, je) = adjacent_vertices(i_node, G); j != je; ++j) { - const vertex_t j_node = *j; - if (marker.is_not_tagged(j_node)) { - marker.mark_tagged(j_node); - deg += supernode_size[j_node]; - } - } - } else - deg += supernode_size[i_node]; - } // for adjacent vertices of u_node - deg -= supernode_size[u_node]; - degree[u_node] = deg; - degreelists[deg].push(u_node); - // u_id has been pushed back into degreelists - degree_lists_marker.unmark(u_node); - if (min_degree > deg) - min_degree = deg; - qxlist.pop(); - } // while (!qxlist.empty()) { + if (numbering.is_numbered(i_node)) { + adj_iter j, je; + for (tie(j, je) = adjacent_vertices(i_node, G); j != je; ++j) { + const vertex_t j_node = *j; + if (marker.is_not_tagged(j_node)) { + marker.mark_tagged(j_node); + deg += supernode_size[j_node]; + } + } + } else + deg += supernode_size[i_node]; + } // for adjacent vertices of u_node + deg -= supernode_size[u_node]; + degree[u_node] = deg; + degreelists[deg].push(u_node); + // u_id has been pushed back into degreelists + degree_lists_marker.unmark(u_node); + if (min_degree > deg) + min_degree = deg; + qxlist.pop(); + } // while (!qxlist.empty()) { - marker.set_tag_as_multiple_tag(); - llist.pop(); - } // while (! llist.empty()) + marker.set_tag_as_multiple_tag(); + llist.pop(); + } // while (! llist.empty()) } // update() void build_permutation(InversePermutationMap next, - PermutationMap prev) + PermutationMap prev) { - // collect the permutation info - for (size_type i = 0; i < n; ++i) { - diff_t size = supernode_size[index_vertex_map[i]]; - if ( size <= 0 ) { - prev[i] = next[i]; - supernode_size[index_vertex_map[i]] - = next[i] + 1; // record the supernode info - } else - prev[i] = - next[i]; - } - for (size_type i = 1; i < n + 1; ++i) { - if ( prev[i-1] > 0 ) - continue; - diff_t parent = i; - while ( prev[parent - 1] < 0 ) { - parent = - prev[parent - 1]; - } + // collect the permutation info + for (size_type i = 0; i < n; ++i) { + diff_t size = supernode_size[index_vertex_map[i]]; + if ( size <= 0 ) { + prev[i] = next[i]; + supernode_size[index_vertex_map[i]] + = next[i] + 1; // record the supernode info + } else + prev[i] = - next[i]; + } + for (size_type i = 1; i < n + 1; ++i) { + if ( prev[i-1] > 0 ) + continue; + diff_t parent = i; + while ( prev[parent - 1] < 0 ) { + parent = - prev[parent - 1]; + } - diff_t root = parent; - diff_t num = prev[root - 1] + 1; - next[i-1] = - num; - prev[root-1] = num; + diff_t root = parent; + diff_t num = prev[root - 1] + 1; + next[i-1] = - num; + prev[root-1] = num; - parent = i; - diff_t next_node = - prev[parent - 1]; - while (next_node > 0) { - prev[parent-1] = - root; - parent = next_node; - next_node = - prev[parent - 1]; - } - } - for (size_type i = 0; i < n; i++) { - diff_t num = - next[i] - 1; - next[i] = num; - prev[num] = i; - } + parent = i; + diff_t next_node = - prev[parent - 1]; + while (next_node > 0) { + prev[parent-1] = - root; + parent = next_node; + next_node = - prev[parent - 1]; + } + } + for (size_type i = 0; i < n; i++) { + diff_t num = - next[i] - 1; + next[i] = num; + prev[num] = i; + } } // build_permutation() }; @@ -657,7 +657,7 @@ namespace boost { detail::mmd_impl impl(G, num_vertices(G), delta, degree, inverse_perm, - perm, supernode_size, vertex_index_map); + perm, supernode_size, vertex_index_map); impl.do_mmd(); impl.build_permutation(inverse_perm, perm); }