summaryrefslogtreecommitdiff
path: root/boost/graph/isomorphism.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/graph/isomorphism.hpp')
-rw-r--r--boost/graph/isomorphism.hpp233
1 files changed, 164 insertions, 69 deletions
diff --git a/boost/graph/isomorphism.hpp b/boost/graph/isomorphism.hpp
index bbdd1f7b41..99055f35c8 100644
--- a/boost/graph/isomorphism.hpp
+++ b/boost/graph/isomorphism.hpp
@@ -11,8 +11,9 @@
#include <iterator>
#include <algorithm>
#include <boost/config.hpp>
+#include <boost/assert.hpp>
+#include <boost/smart_ptr.hpp>
#include <boost/graph/depth_first_search.hpp>
-#include <boost/utility.hpp>
#include <boost/detail/algorithm.hpp>
#include <boost/pending/indirect_cmp.hpp> // for make_indirect_pmap
#include <boost/concept/assert.hpp>
@@ -134,6 +135,10 @@ namespace boost {
bool test_isomorphism()
{
+ // reset isomapping
+ BGL_FORALL_VERTICES_T(v, G1, Graph1)
+ f[v] = graph_traits<Graph2>::null_vertex();
+
{
std::vector<invar1_value> invar1_array;
BGL_FORALL_VERTICES_T(v, G1, Graph1)
@@ -195,69 +200,130 @@ namespace boost {
}
private:
+ struct match_continuation {
+ enum {pos_G2_vertex_loop, pos_fi_adj_loop, pos_dfs_num} position;
+ typedef typename graph_traits<Graph2>::vertex_iterator vertex_iterator;
+ std::pair<vertex_iterator, vertex_iterator> G2_verts;
+ typedef typename graph_traits<Graph2>::adjacency_iterator adjacency_iterator;
+ std::pair<adjacency_iterator, adjacency_iterator> fi_adj;
+ edge_iter iter;
+ int dfs_num_k;
+ };
+
bool match(edge_iter iter, int dfs_num_k)
{
+ std::vector<match_continuation> k;
+ typedef typename graph_traits<Graph2>::vertex_iterator vertex_iterator;
+ std::pair<vertex_iterator, vertex_iterator> G2_verts(vertices(G2));
+ typedef typename graph_traits<Graph2>::adjacency_iterator adjacency_iterator;
+ std::pair<adjacency_iterator, adjacency_iterator> fi_adj;
+ vertex1_t i, j;
+
+ recur:
if (iter != ordered_edges.end()) {
- vertex1_t i = source(*iter, G1), j = target(*iter, G2);
+ i = source(*iter, G1);
+ j = target(*iter, G2);
if (dfs_num[i] > dfs_num_k) {
- vertex1_t kp1 = dfs_vertices[dfs_num_k + 1];
- BGL_FORALL_VERTICES_T(u, G2, Graph2) {
- if (invariant1(kp1) == invariant2(u) && in_S[u] == false) {
- f[kp1] = u;
- in_S[u] = true;
- num_edges_on_k = 0;
-
- if (match(iter, dfs_num_k + 1))
-#if 0
- // dwa 2003/7/11 -- this *HAS* to be a bug!
- ;
-#endif
- return true;
+ G2_verts = vertices(G2);
+ while (G2_verts.first != G2_verts.second) {
+ {
+ vertex2_t u = *G2_verts.first;
+ vertex1_t kp1 = dfs_vertices[dfs_num_k + 1];
+ if (invariant1(kp1) == invariant2(u) && in_S[u] == false) {
+ {
+ f[kp1] = u;
+ in_S[u] = true;
+ num_edges_on_k = 0;
- in_S[u] = false;
+ match_continuation new_k;
+ new_k.position = match_continuation::pos_G2_vertex_loop;
+ new_k.G2_verts = G2_verts;
+ new_k.iter = iter;
+ new_k.dfs_num_k = dfs_num_k;
+ k.push_back(new_k);
+ ++dfs_num_k;
+ goto recur;
+ }
+ }
}
+G2_loop_k: ++G2_verts.first;
}
}
else if (dfs_num[j] > dfs_num_k) {
- vertex1_t k = dfs_vertices[dfs_num_k];
- num_edges_on_k -=
- count_if(adjacent_vertices(f[k], G2), make_indirect_pmap(in_S));
-
- for (int jj = 0; jj < dfs_num_k; ++jj) {
- vertex1_t j = dfs_vertices[jj];
- num_edges_on_k -= count(adjacent_vertices(f[j], G2), f[k]);
+ {
+ vertex1_t vk = dfs_vertices[dfs_num_k];
+ num_edges_on_k -=
+ count_if(adjacent_vertices(f[vk], G2), make_indirect_pmap(in_S));
+
+ for (int jj = 0; jj < dfs_num_k; ++jj) {
+ vertex1_t j = dfs_vertices[jj];
+ num_edges_on_k -= count(adjacent_vertices(f[j], G2), f[vk]);
+ }
}
if (num_edges_on_k != 0)
- return false;
- BGL_FORALL_ADJ_T(f[i], v, G2, Graph2)
- if (invariant2(v) == invariant1(j) && in_S[v] == false) {
- f[j] = v;
- in_S[v] = true;
- num_edges_on_k = 1;
- BOOST_USING_STD_MAX();
- int next_k = max BOOST_PREVENT_MACRO_SUBSTITUTION(dfs_num_k, max BOOST_PREVENT_MACRO_SUBSTITUTION(dfs_num[i], dfs_num[j]));
- if (match(boost::next(iter), next_k))
- return true;
- in_S[v] = false;
+ goto return_point_false;
+ fi_adj = adjacent_vertices(f[i], G2);
+ while (fi_adj.first != fi_adj.second) {
+ {
+ vertex2_t v = *fi_adj.first;
+ if (invariant2(v) == invariant1(j) && in_S[v] == false) {
+ f[j] = v;
+ in_S[v] = true;
+ num_edges_on_k = 1;
+ BOOST_USING_STD_MAX();
+ int next_k = max BOOST_PREVENT_MACRO_SUBSTITUTION(dfs_num_k, max BOOST_PREVENT_MACRO_SUBSTITUTION(dfs_num[i], dfs_num[j]));
+ match_continuation new_k;
+ new_k.position = match_continuation::pos_fi_adj_loop;
+ new_k.fi_adj = fi_adj;
+ new_k.iter = iter;
+ new_k.dfs_num_k = dfs_num_k;
+ ++iter;
+ dfs_num_k = next_k;
+ k.push_back(new_k);
+ goto recur;
+ }
}
-
-
+fi_adj_loop_k:++fi_adj.first;
+ }
}
else {
if (container_contains(adjacent_vertices(f[i], G2), f[j])) {
++num_edges_on_k;
- if (match(boost::next(iter), dfs_num_k))
- return true;
+ match_continuation new_k;
+ new_k.position = match_continuation::pos_dfs_num;
+ k.push_back(new_k);
+ ++iter;
+ goto recur;
}
}
} else
- return true;
- return false;
- }
+ goto return_point_true;
+ goto return_point_false;
+ {
+ return_point_true: return true;
+
+ return_point_false:
+ if (k.empty()) return false;
+ const match_continuation& this_k = k.back();
+ switch (this_k.position) {
+ case match_continuation::pos_G2_vertex_loop: {G2_verts = this_k.G2_verts; iter = this_k.iter; dfs_num_k = this_k.dfs_num_k; k.pop_back(); in_S[*G2_verts.first] = false; i = source(*iter, G1); j = target(*iter, G2); goto G2_loop_k;}
+ case match_continuation::pos_fi_adj_loop: {fi_adj = this_k.fi_adj; iter = this_k.iter; dfs_num_k = this_k.dfs_num_k; k.pop_back(); in_S[*fi_adj.first] = false; i = source(*iter, G1); j = target(*iter, G2); goto fi_adj_loop_k;}
+ case match_continuation::pos_dfs_num: {k.pop_back(); goto return_point_false;}
+ default: {
+ BOOST_ASSERT(!"Bad position");
+#ifdef UNDER_CE
+ exit(-1);
+#else
+ abort();
+#endif
+ }
+ }
+ }
+ }
};
@@ -404,39 +470,68 @@ namespace boost {
index_map1, index_map2
);
}
+
+ template <typename G, typename Index>
+ struct make_degree_invariant {
+ const G& g;
+ const Index& index;
+ make_degree_invariant(const G& g, const Index& index): g(g), index(index) {}
+ typedef typename boost::graph_traits<G>::degree_size_type degree_size_type;
+ typedef shared_array_property_map<degree_size_type, Index> prop_map_type;
+ typedef degree_vertex_invariant<prop_map_type, G> result_type;
+ result_type operator()() const {
+ prop_map_type pm = make_shared_array_property_map(num_vertices(g), degree_size_type(), index);
+ compute_in_degree(g, pm);
+ return result_type(pm, g);
+ }
+ };
} // namespace detail
-
- // Named parameter interface
- template <typename Graph1, typename Graph2, class P, class T, class R>
- bool isomorphism(const Graph1& g1,
- const Graph2& g2,
- const bgl_named_params<P,T,R>& params)
- {
- typedef typename graph_traits<Graph2>::vertex_descriptor vertex2_t;
- typename std::vector<vertex2_t>::size_type n = num_vertices(g1);
- std::vector<vertex2_t> f(n);
- 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), vertex2_t())),
- 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 <typename Graph1, typename Graph2>
- bool isomorphism(const Graph1& g1, const Graph2& g2)
- {
- return isomorphism(g1, g2,
- bgl_named_params<int, buffer_param_t>(0));// bogus named param
+ namespace graph {
+ namespace detail {
+ template <typename Graph1, typename Graph2>
+ struct isomorphism_impl {
+ typedef bool result_type;
+ template <typename ArgPack>
+ bool operator()(const Graph1& g1, const Graph2& g2, const ArgPack& arg_pack) const {
+ using namespace boost::graph::keywords;
+ typedef typename boost::detail::override_const_property_result<ArgPack, tag::vertex_index1_map, boost::vertex_index_t, Graph1>::type index1_map_type;
+ typedef typename boost::detail::override_const_property_result<ArgPack, tag::vertex_index2_map, boost::vertex_index_t, Graph2>::type index2_map_type;
+ index1_map_type index1_map = boost::detail::override_const_property(arg_pack, _vertex_index1_map, g1, boost::vertex_index);
+ index2_map_type index2_map = boost::detail::override_const_property(arg_pack, _vertex_index2_map, g2, boost::vertex_index);
+ typedef typename graph_traits<Graph2>::vertex_descriptor vertex2_t;
+ typename std::vector<vertex2_t>::size_type n = (typename std::vector<vertex2_t>::size_type)num_vertices(g1);
+ std::vector<vertex2_t> f(n);
+ typename boost::parameter::lazy_binding<
+ ArgPack,
+ tag::vertex_invariant1,
+ boost::detail::make_degree_invariant<Graph1, index1_map_type> >::type
+ invariant1 =
+ arg_pack[_vertex_invariant1 || boost::detail::make_degree_invariant<Graph1, index1_map_type>(g1, index1_map)];
+ typename boost::parameter::lazy_binding<
+ ArgPack,
+ tag::vertex_invariant2,
+ boost::detail::make_degree_invariant<Graph2, index2_map_type> >::type
+ invariant2 =
+ arg_pack[_vertex_invariant2 || boost::detail::make_degree_invariant<Graph2, index2_map_type>(g2, index2_map)];
+ return boost::isomorphism
+ (g1, g2,
+ choose_param(arg_pack[_isomorphism_map | boost::param_not_found()],
+ make_shared_array_property_map(num_vertices(g1), vertex2_t(), index1_map)),
+ invariant1,
+ invariant2,
+ arg_pack[_vertex_max_invariant | (invariant2.max)()],
+ index1_map,
+ index2_map);
+ }
+ };
+ }
+ BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(isomorphism, 2, 6)
}
+ // Named parameter interface
+ BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(isomorphism, 2)
// Verify that the given mapping iso_map from the vertices of g1 to the
// vertices of g2 describes an isomorphism.