Index: boost/graph/vf2_sub_graph_iso.hpp =================================================================== --- boost/graph/vf2_sub_graph_iso.hpp (revision 83143) +++ boost/graph/vf2_sub_graph_iso.hpp (working copy) @@ -372,7 +372,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 +526,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 +553,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 +573,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) { + 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_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(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 +809,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 +909,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 +993,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 83143) +++ 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