diff --git a/doc/vf2_sub_graph_iso.html b/doc/vf2_sub_graph_iso.html index 66fc766ce..ed00510b3 100644 --- a/doc/vf2_sub_graph_iso.html +++ b/doc/vf2_sub_graph_iso.html @@ -44,7 +44,8 @@

typename SubGraphIsoMapCallback> bool vf2_subgraph_iso(const GraphSmall& graph_small, const GraphLarge& graph_large, - SubGraphIsoMapCallback user_callback) + SubGraphIsoMapCallback user_callback, + bool(*user_step_callback)() = &vf2_trivial_step_callback) // Named parameter version @@ -59,7 +60,8 @@

const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback, const VertexOrderSmall& vertex_order_small, - const bgl_named_params<Param, Tag, Rest>& params) + const bgl_named_params<Param, Tag, Rest>& params, + bool(*user_step_callback)() = &vf2_trivial_step_callback) // Non-named parameter version @@ -78,7 +80,8 @@

IndexMapLarge index_map_large, const VertexOrderSmall& vertex_order_small, EdgeEquivalencePredicate edge_comp, - VertexEquivalencePredicate vertex_comp) + VertexEquivalencePredicate vertex_comp, + bool(*user_step_callback)() = &vf2_trivial_step_callback)

An isomorphism between two graphs G1=(V1, E1) @@ -95,9 +98,9 @@

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 + user_callback. It continues until user_callback or user_step_callback returns false or the search space has been fully explored. vf2_subgraph_iso - returns true if a graph-subgraph isomorphism exists and false otherwise. + returns true if a graph-subgraph isomorphism was found and false otherwise. EdgeEquivalencePredicate and VertexEquivalencePredicate predicates are used to test whether edges and vertices are equivalent. To use property maps for equivalence, @@ -202,6 +205,18 @@

Parameters

+

OUT: bool(*user_step_callback)() = &vf2_trivial_step_callback

+
+

+ A function to be called at each step of the search. If it returns false, + the search is terminated. The default always returns true. Unlike + user_callback (which is only called when a match is found), + this callback is called with high frequency; it may be used, for + example, to stop the search when a time limit is exceeded or for other + external reasons. +

+
+

IN: const VertexOrderSmall& vertex_order_small

diff --git a/include/boost/graph/vf2_sub_graph_iso.hpp b/include/boost/graph/vf2_sub_graph_iso.hpp index 77f7496bd..a670d8e5e 100644 --- a/include/boost/graph/vf2_sub_graph_iso.hpp +++ b/include/boost/graph/vf2_sub_graph_iso.hpp @@ -73,6 +73,11 @@ template < typename Graph1, typename Graph2 > struct vf2_print_callback const Graph2& graph2_; }; +static bool vf2_trivial_step_callback() +{ + return true; +} + namespace detail { @@ -748,8 +753,8 @@ namespace detail // and tested for feasibility to extend the mapping. If a complete // mapping is found, the mapping is output to user_callback in the form // of a correspondence map (graph1 to graph2). Returning false from the - // user_callback will terminate the search. Function match will return - // true if the entire search space was explored. + // user_callback or user_step_callback will terminate the search. Function + // match will return true if a match was found. template < typename Graph1, typename Graph2, typename IndexMap1, typename IndexMap2, typename VertexOrder1, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, @@ -758,7 +763,8 @@ namespace detail SubGraphIsoMapCallback user_callback, const VertexOrder1& vertex_order1, state< Graph1, Graph2, IndexMap1, IndexMap2, EdgeEquivalencePredicate, VertexEquivalencePredicate, SubGraphIsoMapCallback, - problem_selection >& s) + problem_selection >& s, + bool(*user_step_callback)() = &vf2_trivial_step_callback) { typename VertexOrder1::const_iterator graph1_verts_iter; @@ -773,6 +779,10 @@ namespace detail bool found_match = false; recur: + if (!user_step_callback()) { + return found_match; + } + if (s.success()) { if (!s.call_back(user_callback)) @@ -913,8 +923,9 @@ namespace detail } // 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. + // graph_small and graph_large. Continues until user_callback or + // user_step_callback returns false or the search space has been fully + // explored. template < problem_selector problem_selection, typename GraphSmall, typename GraphLarge, typename IndexMapSmall, typename IndexMapLarge, typename VertexOrderSmall, typename EdgeEquivalencePredicate, @@ -924,7 +935,8 @@ namespace detail IndexMapSmall index_map_small, IndexMapLarge index_map_large, const VertexOrderSmall& vertex_order_small, EdgeEquivalencePredicate edge_comp, - VertexEquivalencePredicate vertex_comp) + VertexEquivalencePredicate vertex_comp, + bool(*user_step_callback)() = &vf2_trivial_step_callback) { // Graph requirements @@ -1007,7 +1019,8 @@ namespace detail edge_comp, vertex_comp); return detail::match( - graph_small, graph_large, user_callback, vertex_order_small, s); + graph_small, graph_large, user_callback, vertex_order_small, s, + user_step_callback); } } // namespace detail @@ -1028,8 +1041,8 @@ vertex_order_by_mult(const Graph& graph) } // 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. +// graph_small and graph_large. Continues until user_callback or +// user_step_callback returns false or the search space has been fully explored. template < typename GraphSmall, typename GraphLarge, typename IndexMapSmall, typename IndexMapLarge, typename VertexOrderSmall, typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate, @@ -1038,23 +1051,25 @@ 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) + EdgeEquivalencePredicate edge_comp, VertexEquivalencePredicate vertex_comp, + bool(*user_step_callback)() = &vf2_trivial_step_callback) { return detail::vf2_subgraph_morphism< detail::subgraph_mono >(graph_small, graph_large, user_callback, index_map_small, index_map_large, - vertex_order_small, edge_comp, vertex_comp); + vertex_order_small, edge_comp, vertex_comp, user_step_callback); } // All default interface for vf2_subgraph_iso template < typename GraphSmall, typename GraphLarge, typename SubGraphIsoMapCallback > bool vf2_subgraph_mono(const GraphSmall& graph_small, - const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback) + const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback, + bool(*user_step_callback)() = &vf2_trivial_step_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()); + always_equivalent(), user_step_callback); } // Named parameter interface of vf2_subgraph_iso @@ -1064,7 +1079,8 @@ template < typename GraphSmall, typename GraphLarge, typename VertexOrderSmall, bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback, const VertexOrderSmall& vertex_order_small, - const bgl_named_params< Param, Tag, Rest >& params) + const bgl_named_params< Param, Tag, Rest >& params, + bool(*user_step_callback)() = &vf2_trivial_step_callback) { return vf2_subgraph_mono(graph_small, graph_large, user_callback, choose_const_pmap( @@ -1075,7 +1091,8 @@ bool vf2_subgraph_mono(const GraphSmall& graph_small, choose_param( get_param(params, edges_equivalent_t()), always_equivalent()), choose_param( - get_param(params, vertices_equivalent_t()), always_equivalent())); + get_param(params, vertices_equivalent_t()), always_equivalent()), + user_step_callback); } // Enumerates all graph sub-graph isomorphism mappings between graphs diff --git a/test/vf2_sub_graph_iso_test_2.cpp b/test/vf2_sub_graph_iso_test_2.cpp index 437150a85..73cbfff85 100644 --- a/test/vf2_sub_graph_iso_test_2.cpp +++ b/test/vf2_sub_graph_iso_test_2.cpp @@ -39,6 +39,18 @@ struct false_predicate } }; +bool step_callback_always_false() +{ + return false; +} + +bool step_callback_max_10_steps() +{ + static int n = 0; + n++; + return (n <= 10); +} + void test_empty_graph_cases() { typedef boost::adjacency_list< boost::vecS, boost::vecS, @@ -201,9 +213,37 @@ BOOST_TEST(!got_hit); } } +void test_step_callback() +{ + typedef boost::adjacency_list< boost::vecS, boost::vecS, + boost::bidirectionalS > + Graph; + Graph gEmpty, gLarge; + add_vertex(gLarge); + + { // isomorphism exists but search aborted + bool got_hit = false; + test_callback callback(got_hit, true); + bool found = vf2_subgraph_mono(gEmpty, gEmpty, callback, + &step_callback_always_false); + BOOST_TEST(!found); + BOOST_TEST(!got_hit); + } + + { // isomorphism exists and found within 10 steps + bool got_hit = false; + test_callback callback(got_hit, true); + bool found = vf2_subgraph_mono(gEmpty, gEmpty, callback, + &step_callback_max_10_steps); + BOOST_TEST(found); + BOOST_TEST(got_hit); + } +} + int main(int argc, char* argv[]) { test_empty_graph_cases(); test_return_value(); + test_step_callback(); return boost::report_errors(); }