diff --git a/doc/isomorphism-impl-v2.w b/doc/isomorphism-impl-v2.w index f00e1fd4..eaaffd54 100644 --- a/doc/isomorphism-impl-v2.w +++ b/doc/isomorphism-impl-v2.w @@ -289,7 +289,7 @@ struct ordered_edge { } int source; int target; - int order; + int k_num; }; @} @@ -335,10 +335,8 @@ struct record_dfs_order : default_dfs_visitor { invar2_array.push_back(invariant2(v)); std::sort(invar2_array.begin(), invar2_array.end()); - if (!std::equal(invar1_array.begin(), invar1_array.end(), invar2_array.begin())) { - std::cout << "invariants don't match" << std::endl; + if (!std::equal(invar1_array.begin(), invar1_array.end(), invar2_array.begin())) return false; - } } @} @@ -353,40 +351,37 @@ BGL_FORALL_VERTICES_T(v, G1, Graph1) ++multiplicity[invariant1(v)]; std::sort(V_mult.begin(), V_mult.end(), cmp_multiplicity(*this, &multiplicity[0])); - - std::cout << "V_mult="; - std::copy(V_mult.begin(), V_mult.end(), - std::ostream_iterator(std::cout, " ")); - std::cout << std::endl; } @} @d Order vertices and edges by DFS @{ -{ - dfs_order order(dfs_vertices, ordered_edges); - std::vector color_vec(num_vertices(G1)); - record_dfs_order dfs_visitor(order); - typedef color_traits Color; - for (vertex_iter u = V_mult.begin(); u != V_mult.end(); ++u) { - if (color_vec[*u] == Color::white()) { - dfs_visitor.start_vertex(*u, G1); - depth_first_visit(G1, *u, dfs_visitor, &color_vec[0]); - } - } - // Create the dfs_number array - size_type n = 0; - dfs_number.resize(num_vertices(G1)); - for (vertex_iter v = dfs_vertices.begin(); v != dfs_vertices.end(); ++v) - dfs_number[*v] = n++; - - // Renumber ordered_edges array according to DFS number - for (edge_iter e = ordered_edges.begin(); e != ordered_edges.end(); ++e) { - if (e->source >= 0) - e->source = dfs_number[e->source]; - e->target = dfs_number[e->target]; +dfs_order order(dfs_vertices, ordered_edges); +std::vector color_vec(num_vertices(G1)); +safe_iterator_property_map::iterator, IndexMap1> + color_map(color_vec.begin(), color_vec.size(), index_map1); +record_dfs_order dfs_visitor(order); +typedef color_traits Color; +for (vertex_iter u = V_mult.begin(); u != V_mult.end(); ++u) { + if (color_map[*u] == Color::white()) { + dfs_visitor.start_vertex(*u, G1); + depth_first_visit(G1, *u, dfs_visitor, color_map); } } +// Create the dfs_number array and dfs_number_map +dfs_number_vec.resize(num_vertices(G1)); +dfs_number = make_safe_iterator_property_map(dfs_number_vec.begin(), + dfs_number_vec.size(), index_map1); +size_type n = 0; +for (vertex_iter v = dfs_vertices.begin(); v != dfs_vertices.end(); ++v) + dfs_number[*v] = n++; + +// Renumber ordered_edges array according to DFS number +for (edge_iter e = ordered_edges.begin(); e != ordered_edges.end(); ++e) { + if (e->source >= 0) + e->source = dfs_number_vec[e->source]; + e->target = dfs_number_vec[e->target]; +} @} Reorder the edges so that all edges belonging to $G_1[k]$ @@ -396,12 +391,12 @@ The order field needs a better name. How about k? @d Sort edges according to vertex DFS order @{ -{ - std::stable_sort(ordered_edges.begin(), ordered_edges.end()); - // Fill in i->order field - ordered_edges[0].order = 0; - for (edge_iter i = next(ordered_edges.begin()); i != ordered_edges.end(); ++i) - i->order = std::max(prior(i)->source, prior(i)->target); +std::stable_sort(ordered_edges.begin(), ordered_edges.end()); +// Fill in i->k_num field +if (!ordered_edges.empty()) { + ordered_edges[0].k_num = 0; + for (edge_iter i = next(ordered_edges.begin()); i != ordered_edges.end(); ++i) + i->k_num = std::max(prior(i)->source, prior(i)->target); } @} @@ -410,25 +405,18 @@ The order field needs a better name. How about k? - @d Match function @{ bool match(edge_iter iter) { -std::cout << "*** entering match" << std::endl; if (iter != ordered_edges.end()) { ordered_edge edge = *iter; - size_type edge_order_num = edge.order; + size_type k_num = edge.k_num; + vertex1_t k = dfs_vertices[k_num]; vertex1_t u; if (edge.source != -1) // might be a ficticious edge u = dfs_vertices[edge.source]; vertex1_t v = dfs_vertices[edge.target]; - std::cout << "edge: ("; - if (edge.source == -1) - std::cout << "root"; - else - std::cout << name_map1[dfs_vertices[edge.source]]; - std::cout << "," << name_map1[dfs_vertices[edge.target]] << ")" << std::endl; if (edge.source == -1) { // root node @<$v$ is a DFS tree root@> } else if (f_assigned[v] == false) { @@ -438,7 +426,6 @@ if (iter != ordered_edges.end()) { } } else return true; -std::cout << "returning false" << std::endl; return false; } // match() @} @@ -447,23 +434,17 @@ return false; @d $v$ is a DFS tree root @{ -std::cout << "** case 1" << std::endl; // Try all possible mappings BGL_FORALL_VERTICES_T(y, G2, Graph2) { - std::cout << "y: " << name_map2[y] << std::endl; if (invariant1(v) == invariant2(y) && f_inv_assigned[y] == false) { - std::cout << "f(" << name_map1[v] << ")=" < @ - -std::cout << "mc: " << mc << std::endl; -if (mc != 0) // make sure out/in edges for k and f(k) add up +if (num_edges_incident_on_k != 0) return false; @ @} @d Count out-edges of $f(k)$ in $G_2[S]$ @{ -BGL_FORALL_ADJACENT_T(f[k], w, G2, Graph2) { - if (f_inv_assigned[w] == true) { - --mc; - std::cout << "--mc: " << mc << std::endl; - std::cout << "(" << name_map2[f[k]] << "," << name_map2[w] << ")\n"; - } -} +BGL_FORALL_ADJACENT_T(f[k], w, G2, Graph2) + if (f_inv_assigned[w] == true) + --num_edges_incident_on_k; @} @d Count in-edges of $f(k)$ in $G_2[S]$ @{ -for (std::size_t ji = 0; ji < edge_order_num; ++ji) { - vertex1_t j = dfs_vertices[ji]; - BGL_FORALL_ADJACENT_T(f[j], w, G2, Graph2) { - if (w == f[k]) { - --mc; - std::cout << "--mc: " << mc << std::endl; - std::cout << "(" << name_map2[f[j]] << "," << name_map2[w] << ")\n"; - } - } +for (std::size_t jj = 0; jj < k_num; ++jj) { + vertex1_t j = dfs_vertices[jj]; + BGL_FORALL_ADJACENT_T(f[j], w, G2, Graph2) + if (w == f[k]) + --num_edges_incident_on_k; } @} @d Assign $v$ to some vertex in $V_2 - S$ @{ -BGL_FORALL_ADJACENT_T(f[u], y, G2, Graph2) { +BGL_FORALL_ADJACENT_T(f[u], y, G2, Graph2) if (invariant1(v) == invariant2(y) && f_inv_assigned[y] == false) { f[v] = y; f_assigned[v] = true; - std::cout << "f(" << name_map1[v] << ")=" << name_map2[y] << std::endl;; f_inv[y] = v; f_inv_assigned[y] = true; - mc = 1; - std::cout << "(f(u),y): (" << name_map2[f[u]] << "," << name_map2[y] - << ")" << std::endl; - std::cout << "mc = 1" << std::endl; + num_edges_incident_on_k = 1; if (match(next(iter))) return true; f_assigned[v] = false; f_inv_assigned[y] = false; } -} @} @d Check to see if there is an edge in $G_2$ to match $(u,v)$ @{ -std::cout << "** case 3" << std::endl; bool verify = false; assert(f_assigned[u] == true); BGL_FORALL_ADJACENT_T(f[u], y, G2, Graph2) { - std::cout << "y: " << name_map2[y] << std::endl; - assert(f_assigned[v] == true); if (y == f[v]) { - std::cout << "found match, (" << name_map2[f[u]] - << "," << name_map2[y] << ")" << std::endl; verify = true; break; } } if (verify == true) { - ++mc; // out or in edge of k - std::cout << "++mc: " << mc << std::endl; + ++num_edges_incident_on_k; if (match(next(iter))) - return true; + return true; } @} @@ -574,7 +528,6 @@ if (verify == true) { #ifndef BOOST_GRAPH_ISOMORPHISM_HPP #define BOOST_GRAPH_ISOMORPHISM_HPP -#include #include #include #include @@ -590,8 +543,7 @@ namespace detail { template + typename IndexMap1, typename IndexMap2> class isomorphism_algo { typedef isomorphism_algo self; @@ -611,14 +563,14 @@ class isomorphism_algo std::size_t max_invariant; IndexMap1 index_map1; IndexMap2 index_map2; - NameMap1 name_map1; - NameMap2 name_map2; @ std::vector dfs_vertices; typedef std::vector::iterator vertex_iter; - std::vector dfs_number; + std::vector dfs_number_vec; + safe_iterator_property_map::iterator, IndexMap1> + dfs_number; std::vector ordered_edges; typedef std::vector::iterator edge_iter; @@ -630,12 +582,22 @@ public: isomorphism_algo(const Graph1& G1, const Graph2& G2, IsoMapping f, Invariant1 invariant1, Invariant2 invariant2, std::size_t max_invariant, - IndexMap1 index_map1, IndexMap2 index_map2, - NameMap1 name_map1, NameMap2 name_map2) + IndexMap1 index_map1, IndexMap2 index_map2) : G1(G1), G2(G2), f(f), invariant1(invariant1), invariant2(invariant2), max_invariant(max_invariant), - index_map1(index_map1), index_map2(index_map2), - name_map1(name_map1), name_map2(name_map2) { } + index_map1(index_map1), index_map2(index_map2) + { + f_assigned_vec.resize(num_vertices(G1)); + f_assigned = make_safe_iterator_property_map + (f_assigned_vec.begin(), f_assigned_vec.size(), index_map1); + f_inv_vec.resize(num_vertices(G1)); + f_inv = make_safe_iterator_property_map + (f_inv_vec.begin(), f_inv_vec.size(), index_map2); + + f_inv_assigned_vec.resize(num_vertices(G1)); + f_inv_assigned = make_safe_iterator_property_map + (f_inv_assigned_vec.begin(), f_inv_assigned_vec.size(), index_map2); + } bool test_isomorphism() { @@ -644,38 +606,26 @@ public: @ @ - f_assigned.resize(num_vertices(G1)); - f_inv.resize(num_vertices(G1)); - f_inv_assigned.resize(num_vertices(G1)); - return this->match(ordered_edges.begin()); } // test_isomorphism private: - std::vector f_inv; - std::vector f_assigned; - std::vector f_inv_assigned; - int mc; // #edges incident on k + std::vector f_inv_vec; + safe_iterator_property_map::iterator, + IndexMap2> f_inv; + + std::vector f_assigned_vec; + safe_iterator_property_map::iterator, + IndexMap1> f_assigned; + + std::vector f_inv_assigned_vec; + safe_iterator_property_map::iterator, + IndexMap2> f_inv_assigned; + + int num_edges_incident_on_k; @ - - void print_ordered_edges() { - std::cout << "ordered edges="; - for (edge_iter i = ordered_edges.begin(); i != ordered_edges.end(); ++i) - std::cout << "[" << name_map1[dfs_vertices[i->source]] - << "(" << i->source << ")" - << "," << name_map1[dfs_vertices[i->target]] << "(" << i->target << ")" - << " : " << i->order << ")"; - std::cout << std::endl; - } - - void print_dfs_numbers() { - std::cout << "dfs numbers="; - std::copy(dfs_number.begin(), dfs_number.end(), - std::ostream_iterator(std::cout, " ")); - std::cout << std::endl; - } }; @@ -698,21 +648,84 @@ void compute_in_degree(const Graph& g, InDegreeMap in_degree_map) template + typename IndexMap1, typename IndexMap2> bool isomorphism(const Graph1& G1, const Graph2& G2, IsoMapping f, Invariant1 invariant1, Invariant2 invariant2, std::size_t max_invariant, - IndexMap1 index_map1, IndexMap2 index_map2, - NameMap1 name_map1, NameMap2 name_map2) + IndexMap1 index_map1, IndexMap2 index_map2) { detail::isomorphism_algo + IndexMap1, IndexMap2> algo(G1, G2, f, invariant1, invariant2, max_invariant, - index_map1, index_map2, name_map1, name_map2); + index_map1, index_map2); return algo.test_isomorphism(); } +namespace detail { + +template +bool isomorphism_impl(const Graph1& G1, const Graph2& G2, + IsoMapping f, IndexMap1 index_map1, IndexMap2 index_map2, + const bgl_named_params& params) +{ + std::vector in_degree1_vec(num_vertices(G1)); + typedef safe_iterator_property_map::iterator, IndexMap1> InDeg1; + InDeg1 in_degree1(in_degree1_vec.begin(), in_degree1_vec.size(), index_map1); + compute_in_degree(G1, in_degree1); + + std::vector in_degree2_vec(num_vertices(G2)); + typedef safe_iterator_property_map::iterator, IndexMap2> InDeg2; + InDeg2 in_degree2(in_degree2_vec.begin(), in_degree2_vec.size(), index_map2); + compute_in_degree(G2, in_degree2); + + degree_vertex_invariant invariant1(in_degree1, G1); + degree_vertex_invariant invariant2(in_degree2, G2); + + return isomorphism(G1, G2, f, + choose_param(get_param(params, vertex_invariant1_t()), invariant1), + choose_param(get_param(params, vertex_invariant2_t()), invariant2), + choose_param(get_param(params, vertex_max_invariant_t()), invariant2.max()), + index_map1, index_map2 + ); +} + +} // namespace detail + + +// Named parameter interface +template +bool isomorphism(const Graph1& g1, + const Graph2& g2, + const bgl_named_params& params) +{ + typedef typename graph_traits::vertex_descriptor vertex2_t; + typename std::vector::size_type n = num_vertices(g1); + std::vector f(n); + vertex2_t x; + return detail::isomorphism_impl + (g1, g2, + choose_param(get_param(params, vertex_isomorphism_t()), + make_safe_iterator_property_map(f.begin(), f.size(), + choose_const_pmap(get_param(params, vertex_index1), + g1, vertex_index), x)), + choose_const_pmap(get_param(params, vertex_index1), g1, vertex_index), + choose_const_pmap(get_param(params, vertex_index2), g2, vertex_index), + params + ); +} + +// All defaults interface +template +bool isomorphism(const Graph1& g1, const Graph2& g2) +{ + return isomorphism(g1, g2, + bgl_named_params(0));// bogus named param +} + + // Verify that the given mapping iso_map from the vertices of g1 to the // vertices of g2 describes an isomorphism. // Note: this could be made much faster by specializing based on the graph