Index: boost/graph/vf2_sub_graph_iso.hpp
===================================================================
--- boost/graph/vf2_sub_graph_iso.hpp (revision 83224)
+++ boost/graph/vf2_sub_graph_iso.hpp (working copy)
@@ -1,5 +1,6 @@
//=======================================================================
// Copyright (C) 2012 Flavio De Lorenzi (fdlorenzi@gmail.com)
+// Copyright (C) 2013 Jakob Lykke Andersen, University of Southern Denmark (jlandersen@imada.sdu.dk)
//
// The algorithm implemented here is derived from original ideas by
// Pasquale Foggia and colaborators. For further information see
@@ -372,7 +373,7 @@
};
- enum problem_selector { subgraph_iso, isomorphism };
+ enum problem_selector {subgraph_mono, subgraph_iso, isomorphism };
// The actual state associated with both graphs
template state1_;
base_state state2_;
- // Two helper functions used in Feasibility and Valid functions to test
+ // Three helper functions used in Feasibility and Valid functions to test
// terminal set counts when testing for:
+ // - graph sub-graph monomorphism, or
+ inline bool comp_term_sets(graph1_size_type a,
+ graph2_size_type b,
+ boost::mpl::int_) const {
+ return a <= b;
+ }
+
// - graph sub-graph isomorphism, or
inline bool comp_term_sets(graph1_size_type a,
graph2_size_type b,
@@ -519,15 +527,16 @@
BGL_FORALL_INEDGES_T(w_new, e2, graph2_, Graph2) {
vertex2_type w = source(e2, graph2_);
if (state2_.in_core(w) || (w == w_new)) {
- vertex1_type v = v_new;
- if (w != w_new)
- v = state2_.core(w);
+ if (problem_selection != subgraph_mono) {
+ vertex1_type v = v_new;
+ if (w != w_new)
+ v = state2_.core(w);
- if (!edge1_exists(v, v_new,
- edge1_predicate(edge_comp_, e2),
- graph1_))
- return false;
-
+ if (!edge1_exists(v, v_new,
+ edge1_predicate(edge_comp_, e2),
+ graph1_))
+ return false;
+ }
} else {
if (0 < state2_.in_depth(w))
++term_in2_count;
@@ -545,15 +554,16 @@
BGL_FORALL_OUTEDGES_T(w_new, e2, graph2_, Graph2) {
vertex2_type w = target(e2, graph2_);
if (state2_.in_core(w) || (w == w_new)) {
- vertex1_type v = v_new;
- if (w != w_new)
- v = state2_.core(w);
+ if (problem_selection != subgraph_mono) {
+ vertex1_type v = v_new;
+ if (w != w_new)
+ v = state2_.core(w);
- if (!edge1_exists(v_new, v,
- edge1_predicate(edge_comp_, e2),
- graph1_))
- return false;
-
+ if (!edge1_exists(v_new, v,
+ edge1_predicate(edge_comp_, e2),
+ graph1_))
+ return false;
+ }
} else {
if (0 < state2_.in_depth(w))
++term_in2_count;
@@ -564,13 +574,23 @@
}
}
}
-
- return comp_term_sets(term_in1_count, term_in2_count,
- boost::mpl::int_()) &&
- comp_term_sets(term_out1_count, term_out2_count,
- boost::mpl::int_()) &&
- comp_term_sets(rest1_count, rest2_count,
- boost::mpl::int_());
+
+ if (problem_selection != subgraph_mono) { // subgraph_iso and isomorphism
+ return comp_term_sets(term_in1_count, term_in2_count,
+ boost::mpl::int_()) &&
+ comp_term_sets(term_out1_count, term_out2_count,
+ boost::mpl::int_()) &&
+ comp_term_sets(rest1_count, rest2_count,
+ boost::mpl::int_());
+ } else { // subgraph_mono
+ return comp_term_sets(term_in1_count, term_in2_count,
+ boost::mpl::int_()) &&
+ comp_term_sets(term_out1_count, term_out2_count,
+ boost::mpl::int_()) &&
+ comp_term_sets(term_in1_count + term_out1_count + rest1_count,
+ term_in2_count + term_out2_count + rest2_count,
+ boost::mpl::int_());
+ }
}
// Returns true if vertex v in graph1 is a possible candidate to
@@ -790,6 +810,91 @@
}
+ // Enumerates all graph sub-graph mono-/iso-morphism mappings between graphs
+ // graph_small and graph_large. Continues until user_callback returns true or the
+ // search space has been fully explored.
+ template
+ bool vf2_subgraph_morphism(const GraphSmall& graph_small, const GraphLarge& graph_large,
+ SubGraphIsoMapCallback user_callback,
+ IndexMapSmall index_map_small, IndexMapLarge index_map_large,
+ const VertexOrderSmall& vertex_order_small,
+ EdgeEquivalencePredicate edge_comp,
+ VertexEquivalencePredicate vertex_comp) {
+
+ // Graph requirements
+ BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept ));
+ BOOST_CONCEPT_ASSERT(( VertexListGraphConcept ));
+ BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept ));
+ BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept ));
+
+ BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept ));
+ BOOST_CONCEPT_ASSERT(( VertexListGraphConcept ));
+ BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept ));
+ BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept ));
+
+ typedef typename graph_traits::vertex_descriptor vertex_small_type;
+ typedef typename graph_traits::vertex_descriptor vertex_large_type;
+
+ typedef typename graph_traits::vertices_size_type size_type_small;
+ typedef typename graph_traits::vertices_size_type size_type_large;
+
+ // Property map requirements
+ BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept ));
+ typedef typename property_traits::value_type IndexMapSmallValue;
+ BOOST_STATIC_ASSERT(( is_convertible::value ));
+
+ BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept ));
+ typedef typename property_traits::value_type IndexMapLargeValue;
+ BOOST_STATIC_ASSERT(( is_convertible::value ));
+
+ // Edge & vertex requirements
+ typedef typename graph_traits::edge_descriptor edge_small_type;
+ typedef typename graph_traits::edge_descriptor edge_large_type;
+
+ BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept ));
+
+ BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept ));
+
+ // Vertex order requirements
+ BOOST_CONCEPT_ASSERT(( ContainerConcept ));
+ typedef typename VertexOrderSmall::value_type order_value_type;
+ BOOST_STATIC_ASSERT(( is_same::value ));
+ BOOST_ASSERT( num_vertices(graph_small) == vertex_order_small.size() );
+
+ if (num_vertices(graph_small) > num_vertices(graph_large))
+ return false;
+
+ typename graph_traits::edges_size_type num_edges_small = num_edges(graph_small);
+ typename graph_traits::edges_size_type num_edges_large = num_edges(graph_large);
+
+ // Double the number of edges for undirected graphs: each edge counts as
+ // in-edge and out-edge
+ if (is_undirected(graph_small)) num_edges_small *= 2;
+ if (is_undirected(graph_large)) num_edges_large *= 2;
+ if (num_edges_small > num_edges_large)
+ return false;
+
+ if ((num_vertices(graph_small) == 0) && (num_vertices(graph_large) == 0))
+ return true;
+
+ detail::state
+ s(graph_small, graph_large, index_map_small, index_map_large, edge_comp, vertex_comp);
+
+ return detail::match(graph_small, graph_large, user_callback, vertex_order_small, s);
+ }
+
} // namespace detail
@@ -805,7 +910,73 @@
return vertex_order;
}
+
+ // Enumerates all graph sub-graph monomorphism mappings between graphs
+ // graph_small and graph_large. Continues until user_callback returns true or the
+ // search space has been fully explored.
+ template
+ bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large,
+ SubGraphIsoMapCallback user_callback,
+ IndexMapSmall index_map_small, IndexMapLarge index_map_large,
+ const VertexOrderSmall& vertex_order_small,
+ EdgeEquivalencePredicate edge_comp,
+ VertexEquivalencePredicate vertex_comp) {
+ return detail::vf2_subgraph_morphism
+ (graph_small, graph_large,
+ user_callback,
+ index_map_small, index_map_large,
+ vertex_order_small,
+ edge_comp,
+ vertex_comp);
+ }
+
+
+ // All default interface for vf2_subgraph_iso
+ template
+ bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large,
+ SubGraphIsoMapCallback user_callback) {
+ return vf2_subgraph_mono(graph_small, graph_large, user_callback,
+ get(vertex_index, graph_small), get(vertex_index, graph_large),
+ vertex_order_by_mult(graph_small),
+ always_equivalent(), always_equivalent());
+ }
+
+
+ // Named parameter interface of vf2_subgraph_iso
+ template
+ bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large,
+ SubGraphIsoMapCallback user_callback,
+ const VertexOrderSmall& vertex_order_small,
+ const bgl_named_params& params) {
+ return vf2_subgraph_mono(graph_small, graph_large, user_callback,
+ choose_const_pmap(get_param(params, vertex_index1),
+ graph_small, vertex_index),
+ choose_const_pmap(get_param(params, vertex_index2),
+ graph_large, vertex_index),
+ vertex_order_small,
+ choose_param(get_param(params, edges_equivalent_t()),
+ always_equivalent()),
+ choose_param(get_param(params, vertices_equivalent_t()),
+ always_equivalent())
+ );
+ }
+
// Enumerates all graph sub-graph isomorphism mappings between graphs
// graph_small and graph_large. Continues until user_callback returns true or the
// search space has been fully explored.
@@ -823,71 +994,13 @@
const VertexOrderSmall& vertex_order_small,
EdgeEquivalencePredicate edge_comp,
VertexEquivalencePredicate vertex_comp) {
-
- // Graph requirements
- BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept ));
- BOOST_CONCEPT_ASSERT(( VertexListGraphConcept ));
- BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept ));
- BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept ));
-
- BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept ));
- BOOST_CONCEPT_ASSERT(( VertexListGraphConcept ));
- BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept ));
- BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept ));
-
- typedef typename graph_traits::vertex_descriptor vertex_small_type;
- typedef typename graph_traits::vertex_descriptor vertex_large_type;
-
- typedef typename graph_traits::vertices_size_type size_type_small;
- typedef typename graph_traits::vertices_size_type size_type_large;
-
- // Property map requirements
- BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept ));
- typedef typename property_traits::value_type IndexMapSmallValue;
- BOOST_STATIC_ASSERT(( is_convertible::value ));
-
- BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept ));
- typedef typename property_traits::value_type IndexMapLargeValue;
- BOOST_STATIC_ASSERT(( is_convertible::value ));
-
- // Edge & vertex requirements
- typedef typename graph_traits::edge_descriptor edge_small_type;
- typedef typename graph_traits::edge_descriptor edge_large_type;
-
- BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept ));
-
- BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept ));
-
- // Vertex order requirements
- BOOST_CONCEPT_ASSERT(( ContainerConcept ));
- typedef typename VertexOrderSmall::value_type order_value_type;
- BOOST_STATIC_ASSERT(( is_same::value ));
- BOOST_ASSERT( num_vertices(graph_small) == vertex_order_small.size() );
-
- if (num_vertices(graph_small) > num_vertices(graph_large))
- return false;
-
- typename graph_traits::edges_size_type num_edges_small = num_edges(graph_small);
- typename graph_traits::edges_size_type num_edges_large = num_edges(graph_large);
-
- // Double the number of edges for undirected graphs: each edge counts as
- // in-edge and out-edge
- if (is_undirected(graph_small)) num_edges_small *= 2;
- if (is_undirected(graph_large)) num_edges_large *= 2;
- if (num_edges_small > num_edges_large)
- return false;
-
- if ((num_vertices(graph_small) == 0) && (num_vertices(graph_large) == 0))
- return true;
-
- detail::state
- s(graph_small, graph_large, index_map_small, index_map_large, edge_comp, vertex_comp);
-
- return detail::match(graph_small, graph_large, user_callback, vertex_order_small, s);
+ return detail::vf2_subgraph_morphism
+ (graph_small, graph_large,
+ user_callback,
+ index_map_small, index_map_large,
+ vertex_order_small,
+ edge_comp,
+ vertex_comp);
}
Index: libs/graph/doc/vf2_sub_graph_iso.html
===================================================================
--- libs/graph/doc/vf2_sub_graph_iso.html (revision 83224)
+++ libs/graph/doc/vf2_sub_graph_iso.html (working copy)
@@ -87,13 +87,16 @@
graph that preserves the edge structure of the graphs. M is said to be a
graph-subgraph isomorphism if and only if M is an isomorphism between
G1 and a subgraph of G2.
+ An induced subgraph of a graph G = (V, E) is a normal subgraph
+ G' = (V', E') with the extra condition that all edges of G
+ which have both endpoints in V' are in E'.
- This function finds all graph-subgraph isomorphism mappings between
+ This function finds all induced subgraph isomorphisms between
graphs graph_small and graph_large and outputs them to
user_callback. It continues until user_callback
- returns true or the search space has been fully explored. vf2_subgraph_iso
+ returns false or the search space has been fully explored. vf2_subgraph_iso
returns true if a graph-subgraph isomorphism exists and false otherwise.
EdgeEquivalencePredicate and
VertexEquivalencePredicate predicates are used to test whether
@@ -182,8 +185,8 @@
and CorresondenceMap2To1 types are models
of Readable
Property Map and map equivalent vertices across the two
- graphs given to vf2_subgraph_iso (or vf2_graph_iso). For
- instance, if v is
+ graphs given to vf2_subgraph_iso (or vf2_graph_iso or
+ vf2_subgraph_mono). For instance, if v is
from graph_small, w is from graph_large,
and the vertices can be considered equivalent,
then get(f, v) will be w and get(g, w)
@@ -279,13 +282,22 @@
function
vf2_graph_iso(...)
+ vf2_subgraph_mono(...)
- for isomorphism testing take the same parameters as the corresponding
- functions vf2_subgraph_iso for subgraph isomorphism testing.
- The algorithm finds all isomorphism mappings between graphs
- graph1 and graph2 and outputs them to
- user_callback. It continues until user_callback
- returns true or the search space has been fully explored. As before,
+ for isomorphism and (not necessarily induced) subgraph isomorphism testing,
+ taking the same parameters as the corresponding functions vf2_subgraph_iso
+ for induced subgraph isomorphism testing.
+ For vf2_graph_iso the algorithm finds all isomorphism mappings between
+ graphs graph1 and graph2 and outputs them to
+ user_callback.
+ For vf2_graph_mono the algorithm finds all mappings of graph_small
+ to subgraphs of graph_large.
+ Note that, as opposed to vf2_subgraph_iso,
+ these subgraphs need not to be induced subgraphs.
+
+
+ Both algorithms continues until user_callback
+ returns false or the search space has been fully explored. As before,
EdgeEquivalencePredicate and
VertexEquivalencePredicate predicates are used to test
whether edges and vertices are equivalent. By default
@@ -511,7 +523,9 @@
Copyright © 2012, Flavio De Lorenzi
- (fdlorenzi@gmail.com)
+ (fdlorenzi@gmail.com)
+ Copyright © 2013, Jakob Lykke Andersen, University of Southern Denmark
+ (jlandersen@imada.sdu.dk)