From 2f33232ea8ebcc667d8e3d92d51268524fe6eeb8 Mon Sep 17 00:00:00 2001 From: Jeremy Siek Date: Sat, 1 Dec 2001 23:13:57 +0000 Subject: [PATCH] more progress, simplified the main function [SVN r11850] --- doc/isomorphism-impl.w | 281 ++++++++++++++++------------------------- 1 file changed, 111 insertions(+), 170 deletions(-) diff --git a/doc/isomorphism-impl.w b/doc/isomorphism-impl.w index eac5e6bf..9787b08e 100644 --- a/doc/isomorphism-impl.w +++ b/doc/isomorphism-impl.w @@ -94,7 +94,7 @@ v \}]$. \begin{tabbing} IS\=O\=M\=O\=RPH($k$, $S$, $f_{k-1}$) $\equiv$ \\ -\>\textbf{if} ($S = V_2$) \\ +\>\textbf{if} ($k = |V_1|+1$) \\ \>\>\textbf{return} true \\ \>\textbf{for} each vertex $v \in V_2 - S$ \\ \>\>\textbf{if} (MATCH($k$, $v$)) \\ @@ -210,6 +210,7 @@ start the DFS at the vertex with the lowest invariant multiplicity, and each time we restart the DFS, we choose the undiscovered vertex with lowest invariant multiplicity. + \section{Implementation} @@ -220,7 +221,7 @@ template bool simple_isomorphism(const Graph1& g1, const Graph2& g2, IndexMapping f, VertexInvariant invariant, - VertexIndexMap1 v1_index_map, VertexIndexMap2 v2_index_map) + VertexIndexMap1 index_map1, VertexIndexMap2 index_map2) @} @@ -235,8 +236,7 @@ bool simple_isomorphism(const Graph1& g1, const Graph2& g2, @ @ @ - @ - @ + @ } @} @@ -259,6 +259,14 @@ typename graph_traits::vertex_iterator i2, i2_end; @} +@d Quick return with false if $|V_1| \neq |V_2|$ +@{ +if (num_vertices(g1) != num_vertices(g2)) + return false; +@} + + +\subsection{Ordering by Vertex Invariant Multiplicity} @d Degree vertex invariant @@ -270,22 +278,11 @@ struct degree_vertex_invariant { template typename graph_traits::degree_size_type operator()(typename graph_traits::vertex_descriptor v, const Graph& g) - { - return out_degree(v, g); - } + { return out_degree(v, g); } }; @} - -@d Quick return with false if $|V_1| \neq |V_2|$ -@{ -if (num_vertices(g1) != num_vertices(g2)) - return false; -@} - - - @d Compute vertex invariants @{ @ @@ -307,9 +304,9 @@ invar_vec2_t invar2_vec(num_vertices(g2)); // Provide Property Map interface for invariants iterator_property_map - invar1(invar1_vec.begin(), v1_index_map); + invar1(invar1_vec.begin(), index_map1); iterator_property_map - invar2(invar2_vec.begin(), v2_index_map); + invar2(invar2_vec.begin(), index_map2); @} @@ -349,6 +346,8 @@ for (tie(i1, i1_end) = vertices(g1); i1 != i1_end; ++i1) permute(g1_vertices.begin(), g1_vertices.end(), perm.begin()); @} +\subsection{Ordering by DFS Discover Time} + @d Order the vertices by DFS discover time @{ @@ -368,78 +367,44 @@ permute(g1_vertices.begin(), g1_vertices.end(), perm.begin()); std::vector color_vec(num_vertices(g1)); for (typename std::vector::iterator ui = g1_vertices.begin(); ui != g1_vertices.end(); ++ui) { - if (color_vec[get(v1_index_map, *ui)] + if (color_vec[get(index_map1, *ui)] == color_traits::white()) { depth_first_visit - (g1, *ui, detail::record_dfs_order(perm, - v1_index_map), - make_iterator_property_map(&color_vec[0], v1_index_map, - color_vec[0])); + (g1, *ui, detail::record_dfs_order(perm, index_map1), + make_iterator_property_map(&color_vec[0], index_map1, color_vec[0])); } } @} +The set $V_2 - S$ is represented with a bitset named +\code{not\_in\_S}. -@d Order the edge set by DFS discover time + + +@d Invoke recursive \code{isomorph} function @{ -typedef typename graph_traits::edge_descriptor edge1_t; -std::vector edge_set; -std::copy(edges(g1).first, edges(g1).second, - std::back_inserter(edge_set)); - -std::sort(edge_set.begin(), edge_set.end(), - detail::isomorph_edge_ordering - (make_iterator_property_map(perm.begin(), v1_index_map, - perm[0]), g1)); +std::vector not_in_S(num_vertices(g2), true); +return detail::isomorph(g1_vertices.begin(), g1_vertices.end(), g1, g2, + make_iterator_property_map(perm.begin(), index_map1, perm[0]), + index_map2, f, invar1, invar2, not_in_S)); @} - -@d Perform backtracking searches, trying each vertex in $G_2$ as the start -@{ -typename graph_traits::vertex_iterator vi, vi_end; -for (tie(vi, vi_end) = vertices(g2); vi != vi_end; ++vi) { - f[*first] = *vi; // S = { *vi } - @ - @ -} -@} - - -@d Construct $V_2 - S$, calling it \code{not\_in\_S} -@{ -typedef indirect_cmp > Cmp; -Cmp cmp(v2_index_map); -std::set not_in_S(cmp); -for (tie(i2, i2_end) = vertices(g2); i2 != i2_end; ++i2) - set_insert(not_in_S, *i2); -set_remove(not_in_S, *vi); -@} - - - -@d Attempt to extend $S$ to the whole of $V_2$ -@{ -if(detail::isomorph(boost::next(first), g1_vertices.end(), - edge_set.begin(), edge_set.end(), g1, g2, - make_iterator_property_map(perm.begin(), v1_index_map, perm[0]), - v2_index_map, f, invar1, invar2, not_in_S)) - return true; -@} +\subsection{Implementation of ISOMORPH} @d Signature for the recursive isomorph function @{ -template +template bool isomorph(VertexIter k, VertexIter last, - EdgeIter edge_iter, EdgeIter edge_iter_end, const Graph1& g1, const Graph2& g2, - V1IndexMap v1_index_map, - V2IndexMap v2_index_map, - IndexMapping f, Invar1 invar1, Invar2 invar2, - const Set& not_in_S) + IndexMap2 index_map2, + IndexMap2 index_map2, + IndexMapping f, + Invar1 invar1, Invar2 invar2, + const NotInSMap& not_in_S) @} @@ -447,8 +412,9 @@ bool isomorph(VertexIter k, VertexIter last, @d Outline for the isomorph function @{ @ +@ @ -@ +@ @} @d Return true if matching is complete @@ -457,24 +423,13 @@ if (k == last) return true; @} -@d Create a local copy of the mapping $f_k$ -@{ -typedef typename graph_traits::vertex_descriptor v2_desc_t; -std::vector my_f_vec(num_vertices(g1)); -typedef typename std::vector::iterator vec_iter; -iterator_property_map - my_f(my_f_vec.begin(), v1_index_map); - -typename graph_traits::vertex_iterator i1, i1_end; -for (tie(i1, i1_end) = vertices(g1); i1 != i1_end; ++i1) - my_f[*i1] = f[*i1]; -@} In the psuedo-code for ISOMORPH, we iterate through each vertex in $v \in V_2 - S$ and check if $k$ and $v$ can match. A more efficient approach is to directly iterate through all the potential matches for -$k$. Let $M$ be the set of vertices that can be potentially matched to -$k$. We define $M$ as follows: +$k$, for this often is many fewer vertices than $V_2 - S$. Let $M$ +denote the set of vertices that can be potentially matched to $k$. We +define $M$ as follows: % \begin{align*} M &= out \intersect in \\ @@ -495,7 +450,22 @@ in &= \Big\{ v \st \forall (j,k) \in In[k] \Big( (f(j),v) \in Out[f(j)] \Land i( To compute the $out$ set, we iterate through the out-edges $(k,j)$ of $k$, and for each $j$ we iterate through the in-edges $(v,f(j))$ of $f(j)$, putting all of the $v$'s in $out$ that have the same vertex -invariant as $k$, and which are in $V_2 - S$. +invariant as $k$, and which are in $V_2 - S$. Figure~\ref{fig:out} +depicts the computation of the $out$ set. The implementation is as +follows. + +@d Compute the $out$ set +@{ + for (tie(k_j, k_j_end) = out_edges(k, g1); k_j != k_j_end; ++k_j) { + vertex1_t j = target(*k_j, g1); + for (tie(v_fj, v_fj_end) = in_edges(get(f, j), g2); v_fj != v_fj_end; ++v_fj) { + vertex2_t v = source(*v_fj, g2); + if ((get(invar1, j) == get(invar2, get(f, j))) && not_in_S[get(index_map2, v)]) + out.push_back(v); + } + } +@} + \vizfig{out}{Computing the $out$ set.} @@ -503,7 +473,7 @@ invariant as $k$, and which are in $V_2 - S$. @{ digraph G { node[shape=circle] - size="5,3" + size="4,2" ratio="fill" subgraph cluster0 { label="G_1" @@ -536,6 +506,24 @@ digraph G { } @} +The $in$ set is is constructed by iterating through the in-edges +$(j,k)$ of $k$, and for each $j$ we iterate through the out-edges +$(f(j),v)$ of $f(j)$. We put all of the $v$'s in $in$ that have the +same vertex invariant as $k$, and which are in $V_2 - +S$. Figure~\ref{fig:in} depicts the computation of the $in$ set. The +following code computes the $in$ set. + +@d Compute the $in$ set +@{ + for (tie(j_k, j_k_end) = in_edges(k, g1); j_k != j_k_end; ++j_k) { + j = source(*j_k, g1); + for (tie(fj_v, fj_v_end) = out_edges(get(f, j), g2); fj_v != fj_v_end; ++fj_v) { + v = target(*fj_v, g2); + if ((get(invar1, j) == get(invar2, get(f, j))) && not_in_S[get(index_map2, v)]) + in.push_back(v); + } + } +@} \vizfig{in}{Computing the $in$ set.} @@ -569,95 +557,48 @@ digraph G { } @} +For each vertex $v$ in the potential matches $M$, we will create an +extended isomorphism $f_k = f_{k-1} \union \pair{k}{v}$. First +we create a local copy of $f_{k-1}$. -The set $V_2 - S$ is represented with a bitset named -\code{not\_in\_S}. The bitset is accessed here through the property -map interface. The implementation for computing the $out$ set is as -follows. - - -@d Compute the $out$ set +@d Create a copy of $f_{k-1}$ which will become $f_k$ @{ - for (tie(k_j, k_j_end) = out_edges(k, g1); k_j != k_j_end; ++k_j) { - vertex1_t j = target(*k_j, g1); - for (tie(v_fj, v_fj_end) = in_edges(get(f, j), g2); v_fj != v_fj_end; ++v_fj) { - vertex2_t v = source(*v_fj, g2); - if ((get(invar1, j) == get(invar2, get(f, j))) && get(not_in_S, v)) - out.push_back(v); - } - } +typedef typename graph_traits::vertex_descriptor v2_desc_t; +std::vector my_f_vec(num_vertices(g1)); + +// Construct property map interface to my_f_vec +typedef typename std::vector::iterator vec_iter; +iterator_property_map + my_f(my_f_vec.begin(), index_map2); + +typename graph_traits::vertex_iterator i1, i1_end; +for (tie(i1, i1_end) = vertices(g1); i1 != i1_end; ++i1) + my_f[*i1] = f[*i1]; @} +Next we enter the loop through every vertex $v$ in $M$, and extend the +isomorphism with $\pair{k}{v}$. We then update the set $S$ (by +removing $v$ from $V_2 - S$) and make the recursive call to +\code{isomorph}. If \code{isomorph} returns successfully, we have +found an isomorphism for the complete graph, so we copy our local +mapping into the mapping from the previous calling function. -@d Compute the $in$ set +@d Invoke isomorph for each vertex in $M$ @{ - for (tie(j_k, j_k_end) = in_edges(k, g1); j_k != j_k_end; ++j_k) { - j = source(*j_k, g1); - for (tie(fj_v, fj_v_end) = out_edges(get(f, j), g2); fj_v != fj_v_end; ++fj_v) { - v = target(*fj_v, g2); - if ((get(invar1, j) == get(invar2, get(f, j))) && get(not_in_S, v)) - in.push_back(v); - } - } +for (iterator v_iter = M.begin(); v_iter != M.end(); ++v_iter) { + vertex2_t v = *v_iter; + my_f[k] = v; + std::vector my_not_in_S(not_in_S); + my_not_in_S[get(index_map2, v)] = false; + if (isomorph(next(k), last, g1, g2, index_map2, index_map2, my_f, invar1, invar2, my_not_in_S)) { + for (tie(i1, i1_end) = vertices(g1); i1 != i1_end; ++i1) + f[*i1] = my_f[*i1]; + return true; + } +} @} -%(k,j) -%(j,k) -%(v,f(j)) -%(f(j), v) - -Let $M$ be the set of vertices that have the same connectivity -structure as $k$ with respect to the vertices that have already been -mapped, and which have the same vertex invariant. It is the -intersection of the vertices in $C$ with the vertices in $V_2 - S_2$ -that are potential matches for $k$, which we denote $P$. - -introduce notion of partial isomorphism? - - - - - -@d Let $P = V_2 - S$ -@{ -std::vector vertex_set; -std::copy(not_in_S.begin(), not_in_S.end(), std::back_inserter(vertex_set)); -@} - -@d Construct $C$, the vertices that are partially isomorphic to $k$ -@{ - -@} - -@d Perform $P = P \intersect C$ -@{ - -@} - -Let $P_2$ be the vertices from $V_2 - S$ that have the same -connectivity with respect to vertex $k$ and the same vertex invariant -as $k$. - - -@d MATCH-INVAR implementation -@{ -@} - -% P_2 = V_2 - S_2 - -% (k, v_1) -% v_2 = f(v_1) -% A = {} -% for all (u,v_2) \in E_2 -% if (i(k) = i(u)) -% A = A U { u } - -% P_2 <- P_2 \intersect A - -% same connectivity and same vertex invariant - - \end{document} % LocalWords: Isomorphism Siek isomorphism adjacency subgraph subgraphs OM DFS % LocalWords: ISOMORPH Invariants invariants typename IndexMapping bool const