1 //=======================================================================
2 // Copyright (C) 2012 Flavio De Lorenzi (fdlorenzi@gmail.com)
3 // Copyright (C) 2013 Jakob Lykke Andersen, University of Southern Denmark
4 // (jlandersen@imada.sdu.dk)
6 // The algorithm implemented here is derived from original ideas by
7 // Pasquale Foggia and colaborators. For further information see
8 // e.g. Cordella et al. 2001, 2004.
10 // Distributed under the Boost Software License, Version 1.0. (See
11 // accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
13 //=======================================================================
16 // 8 April 2013: Fixed a typo in vf2_print_callback. (Flavio De Lorenzi)
18 #ifndef BOOST_VF2_SUB_GRAPH_ISO_HPP
19 #define BOOST_VF2_SUB_GRAPH_ISO_HPP
27 #include <boost/assert.hpp>
28 #include <boost/concept/assert.hpp>
29 #include <boost/concept_check.hpp>
30 #include <boost/graph/graph_utility.hpp>
31 #include <boost/graph/graph_traits.hpp>
32 #include <boost/graph/mcgregor_common_subgraphs.hpp> // for always_equivalent
33 #include <boost/graph/named_function_params.hpp>
34 #include <boost/type_traits/has_less.hpp>
35 #include <boost/mpl/int.hpp>
36 #include <boost/range/algorithm/sort.hpp>
37 #include <boost/tuple/tuple.hpp>
38 #include <boost/utility/enable_if.hpp>
40 #ifndef BOOST_GRAPH_ITERATION_MACROS_HPP
41 #define BOOST_ISO_INCLUDED_ITER_MACROS // local macro, see bottom of file
42 #include <boost/graph/iteration_macros.hpp>
48 // Default print_callback
49 template < typename Graph1, typename Graph2 > struct vf2_print_callback
52 vf2_print_callback(const Graph1& graph1, const Graph2& graph2)
53 : graph1_(graph1), graph2_(graph2)
57 template < typename CorrespondenceMap1To2, typename CorrespondenceMap2To1 >
58 bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1) const
61 // Print (sub)graph isomorphism map
62 BGL_FORALL_VERTICES_T(v, graph1_, Graph1)
63 std::cout << '(' << get(vertex_index_t(), graph1_, v) << ", "
64 << get(vertex_index_t(), graph2_, get(f, v)) << ") ";
66 std::cout << std::endl;
72 const Graph1& graph1_;
73 const Graph2& graph2_;
79 // State associated with a single graph (graph_this)
80 template < typename GraphThis, typename GraphOther, typename IndexMapThis,
81 typename IndexMapOther >
85 typedef typename graph_traits< GraphThis >::vertex_descriptor
87 typedef typename graph_traits< GraphOther >::vertex_descriptor
91 typename graph_traits< GraphThis >::vertices_size_type size_type;
93 const GraphThis& graph_this_;
94 const GraphOther& graph_other_;
96 IndexMapThis index_map_this_;
97 IndexMapOther index_map_other_;
99 std::vector< vertex_other_type > core_vec_;
100 typedef iterator_property_map<
101 typename std::vector< vertex_other_type >::iterator, IndexMapThis,
102 vertex_other_type, vertex_other_type& >
106 std::vector< size_type > in_vec_, out_vec_;
107 typedef iterator_property_map<
108 typename std::vector< size_type >::iterator, IndexMapThis,
109 size_type, size_type& >
111 in_out_map_type in_, out_;
113 size_type term_in_count_, term_out_count_, term_both_count_,
117 base_state(const base_state&);
118 base_state& operator=(const base_state&);
121 base_state(const GraphThis& graph_this, const GraphOther& graph_other,
122 IndexMapThis index_map_this, IndexMapOther index_map_other)
123 : graph_this_(graph_this)
124 , graph_other_(graph_other)
125 , index_map_this_(index_map_this)
126 , index_map_other_(index_map_other)
127 , core_vec_(num_vertices(graph_this_),
128 graph_traits< GraphOther >::null_vertex())
129 , core_(core_vec_.begin(), index_map_this_)
130 , in_vec_(num_vertices(graph_this_), 0)
131 , out_vec_(num_vertices(graph_this_), 0)
132 , in_(in_vec_.begin(), index_map_this_)
133 , out_(out_vec_.begin(), index_map_this_)
136 , term_both_count_(0)
141 // Adds a vertex pair to the state of graph graph_this
143 const vertex_this_type& v_this, const vertex_other_type& v_other)
148 put(core_, v_this, v_other);
150 if (!get(in_, v_this))
152 put(in_, v_this, core_count_);
154 if (get(out_, v_this))
158 if (!get(out_, v_this))
160 put(out_, v_this, core_count_);
162 if (get(in_, v_this))
166 BGL_FORALL_INEDGES_T(v_this, e, graph_this_, GraphThis)
168 vertex_this_type w = source(e, graph_this_);
171 put(in_, w, core_count_);
178 BGL_FORALL_OUTEDGES_T(v_this, e, graph_this_, GraphThis)
180 vertex_this_type w = target(e, graph_this_);
183 put(out_, w, core_count_);
191 // Removes vertex pair from state of graph_this
192 void pop(const vertex_this_type& v_this, const vertex_other_type&)
198 if (get(in_, v_this) == core_count_)
202 if (get(out_, v_this))
206 BGL_FORALL_INEDGES_T(v_this, e, graph_this_, GraphThis)
208 vertex_this_type w = source(e, graph_this_);
209 if (get(in_, w) == core_count_)
218 if (get(out_, v_this) == core_count_)
220 put(out_, v_this, 0);
222 if (get(in_, v_this))
226 BGL_FORALL_OUTEDGES_T(v_this, e, graph_this_, GraphThis)
228 vertex_this_type w = target(e, graph_this_);
229 if (get(out_, w) == core_count_)
237 put(core_, v_this, graph_traits< GraphOther >::null_vertex());
242 // Returns true if the in-terminal set is not empty
243 bool term_in() const { return core_count_ < term_in_count_; }
245 // Returns true if vertex belongs to the in-terminal set
246 bool term_in(const vertex_this_type& v) const
248 return (get(in_, v) > 0)
249 && (get(core_, v) == graph_traits< GraphOther >::null_vertex());
252 // Returns true if the out-terminal set is not empty
253 bool term_out() const { return core_count_ < term_out_count_; }
255 // Returns true if vertex belongs to the out-terminal set
256 bool term_out(const vertex_this_type& v) const
258 return (get(out_, v) > 0)
259 && (get(core_, v) == graph_traits< GraphOther >::null_vertex());
262 // Returns true of both (in- and out-terminal) sets are not empty
263 bool term_both() const { return core_count_ < term_both_count_; }
265 // Returns true if vertex belongs to both (in- and out-terminal) sets
266 bool term_both(const vertex_this_type& v) const
268 return (get(in_, v) > 0) && (get(out_, v) > 0)
269 && (get(core_, v) == graph_traits< GraphOther >::null_vertex());
272 // Returns true if vertex belongs to the core map, i.e. it is in the
274 bool in_core(const vertex_this_type& v) const
276 return get(core_, v) != graph_traits< GraphOther >::null_vertex();
279 // Returns the number of vertices in the mapping
280 size_type count() const { return core_count_; }
282 // Returns the image (in graph_other) of vertex v (in graph_this)
283 vertex_other_type core(const vertex_this_type& v) const
285 return get(core_, v);
288 // Returns the mapping
289 core_map_type get_map() const { return core_; }
291 // Returns the "time" (or depth) when vertex was added to the
293 size_type in_depth(const vertex_this_type& v) const
298 // Returns the "time" (or depth) when vertex was added to the
300 size_type out_depth(const vertex_this_type& v) const
305 // Returns the terminal set counts
306 boost::tuple< size_type, size_type, size_type > term_set() const
308 return boost::make_tuple(
309 term_in_count_, term_out_count_, term_both_count_);
313 // Function object that checks whether a valid edge
314 // exists. For multi-graphs matched edges are excluded
315 template < typename Graph, typename Enable = void >
316 struct equivalent_edge_exists
319 typename boost::graph_traits< Graph >::edge_descriptor edge_type;
321 BOOST_CONCEPT_ASSERT((LessThanComparable< edge_type >));
323 template < typename EdgePredicate >
324 bool operator()(typename graph_traits< Graph >::vertex_descriptor s,
325 typename graph_traits< Graph >::vertex_descriptor t,
326 EdgePredicate is_valid_edge, const Graph& g)
329 BGL_FORALL_OUTEDGES_T(s, e, g, Graph)
331 if ((target(e, g) == t) && is_valid_edge(e)
332 && (matched_edges_.find(e) == matched_edges_.end()))
334 matched_edges_.insert(e);
343 std::set< edge_type > matched_edges_;
346 template < typename Graph >
347 struct equivalent_edge_exists< Graph,
348 typename boost::disable_if< is_multigraph< Graph > >::type >
350 template < typename EdgePredicate >
351 bool operator()(typename graph_traits< Graph >::vertex_descriptor s,
352 typename graph_traits< Graph >::vertex_descriptor t,
353 EdgePredicate is_valid_edge, const Graph& g)
356 typename graph_traits< Graph >::edge_descriptor e;
358 boost::tie(e, found) = edge(s, t, g);
361 else if (is_valid_edge(e))
368 // Generates a predicate for edge e1 given a binary predicate and a
370 template < typename Graph1, typename Graph2,
371 typename EdgeEquivalencePredicate >
372 struct edge1_predicate
375 edge1_predicate(EdgeEquivalencePredicate edge_comp,
376 typename graph_traits< Graph2 >::edge_descriptor e2)
377 : edge_comp_(edge_comp), e2_(e2)
381 bool operator()(typename graph_traits< Graph1 >::edge_descriptor e1)
383 return edge_comp_(e1, e2_);
386 EdgeEquivalencePredicate edge_comp_;
387 typename graph_traits< Graph2 >::edge_descriptor e2_;
390 // Generates a predicate for edge e2 given given a binary predicate and a
392 template < typename Graph1, typename Graph2,
393 typename EdgeEquivalencePredicate >
394 struct edge2_predicate
397 edge2_predicate(EdgeEquivalencePredicate edge_comp,
398 typename graph_traits< Graph1 >::edge_descriptor e1)
399 : edge_comp_(edge_comp), e1_(e1)
403 bool operator()(typename graph_traits< Graph2 >::edge_descriptor e2)
405 return edge_comp_(e1_, e2);
408 EdgeEquivalencePredicate edge_comp_;
409 typename graph_traits< Graph1 >::edge_descriptor e1_;
412 enum problem_selector
419 // The actual state associated with both graphs
420 template < typename Graph1, typename Graph2, typename IndexMap1,
421 typename IndexMap2, typename EdgeEquivalencePredicate,
422 typename VertexEquivalencePredicate, typename SubGraphIsoMapCallback,
423 problem_selector problem_selection >
427 typedef typename graph_traits< Graph1 >::vertex_descriptor vertex1_type;
428 typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2_type;
430 typedef typename graph_traits< Graph1 >::edge_descriptor edge1_type;
431 typedef typename graph_traits< Graph2 >::edge_descriptor edge2_type;
433 typedef typename graph_traits< Graph1 >::vertices_size_type
435 typedef typename graph_traits< Graph2 >::vertices_size_type
438 const Graph1& graph1_;
439 const Graph2& graph2_;
441 IndexMap1 index_map1_;
443 EdgeEquivalencePredicate edge_comp_;
444 VertexEquivalencePredicate vertex_comp_;
446 base_state< Graph1, Graph2, IndexMap1, IndexMap2 > state1_;
447 base_state< Graph2, Graph1, IndexMap2, IndexMap1 > state2_;
449 // Three helper functions used in Feasibility and Valid functions to
450 // test terminal set counts when testing for:
451 // - graph sub-graph monomorphism, or
452 inline bool comp_term_sets(graph1_size_type a, graph2_size_type b,
453 boost::mpl::int_< subgraph_mono >) const
458 // - graph sub-graph isomorphism, or
459 inline bool comp_term_sets(graph1_size_type a, graph2_size_type b,
460 boost::mpl::int_< subgraph_iso >) const
465 // - graph isomorphism
466 inline bool comp_term_sets(graph1_size_type a, graph2_size_type b,
467 boost::mpl::int_< isomorphism >) const
474 state& operator=(const state&);
477 state(const Graph1& graph1, const Graph2& graph2, IndexMap1 index_map1,
478 IndexMap2 index_map2, EdgeEquivalencePredicate edge_comp,
479 VertexEquivalencePredicate vertex_comp)
482 , index_map1_(index_map1)
483 , edge_comp_(edge_comp)
484 , vertex_comp_(vertex_comp)
485 , state1_(graph1, graph2, index_map1, index_map2)
486 , state2_(graph2, graph1, index_map2, index_map1)
490 // Add vertex pair to the state
491 void push(const vertex1_type& v, const vertex2_type& w)
497 // Remove vertex pair from state
498 void pop(const vertex1_type& v, const vertex2_type&)
500 vertex2_type w = state1_.core(v);
505 // Checks the feasibility of a new vertex pair
506 bool feasible(const vertex1_type& v_new, const vertex2_type& w_new)
509 if (!vertex_comp_(v_new, w_new))
513 graph1_size_type term_in1_count = 0, term_out1_count = 0,
517 equivalent_edge_exists< Graph2 > edge2_exists;
519 BGL_FORALL_INEDGES_T(v_new, e1, graph1_, Graph1)
521 vertex1_type v = source(e1, graph1_);
523 if (state1_.in_core(v) || (v == v_new))
525 vertex2_type w = w_new;
528 if (!edge2_exists(w, w_new,
529 edge2_predicate< Graph1, Graph2,
530 EdgeEquivalencePredicate >(edge_comp_, e1),
536 if (0 < state1_.in_depth(v))
538 if (0 < state1_.out_depth(v))
540 if ((state1_.in_depth(v) == 0)
541 && (state1_.out_depth(v) == 0))
548 equivalent_edge_exists< Graph2 > edge2_exists;
550 BGL_FORALL_OUTEDGES_T(v_new, e1, graph1_, Graph1)
552 vertex1_type v = target(e1, graph1_);
553 if (state1_.in_core(v) || (v == v_new))
555 vertex2_type w = w_new;
559 if (!edge2_exists(w_new, w,
560 edge2_predicate< Graph1, Graph2,
561 EdgeEquivalencePredicate >(edge_comp_, e1),
567 if (0 < state1_.in_depth(v))
569 if (0 < state1_.out_depth(v))
571 if ((state1_.in_depth(v) == 0)
572 && (state1_.out_depth(v) == 0))
579 graph2_size_type term_out2_count = 0, term_in2_count = 0,
583 equivalent_edge_exists< Graph1 > edge1_exists;
585 BGL_FORALL_INEDGES_T(w_new, e2, graph2_, Graph2)
587 vertex2_type w = source(e2, graph2_);
588 if (state2_.in_core(w) || (w == w_new))
590 if (problem_selection != subgraph_mono)
592 vertex1_type v = v_new;
596 if (!edge1_exists(v, v_new,
597 edge1_predicate< Graph1, Graph2,
598 EdgeEquivalencePredicate >(
606 if (0 < state2_.in_depth(w))
608 if (0 < state2_.out_depth(w))
610 if ((state2_.in_depth(w) == 0)
611 && (state2_.out_depth(w) == 0))
618 equivalent_edge_exists< Graph1 > edge1_exists;
620 BGL_FORALL_OUTEDGES_T(w_new, e2, graph2_, Graph2)
622 vertex2_type w = target(e2, graph2_);
623 if (state2_.in_core(w) || (w == w_new))
625 if (problem_selection != subgraph_mono)
627 vertex1_type v = v_new;
631 if (!edge1_exists(v_new, v,
632 edge1_predicate< Graph1, Graph2,
633 EdgeEquivalencePredicate >(
641 if (0 < state2_.in_depth(w))
643 if (0 < state2_.out_depth(w))
645 if ((state2_.in_depth(w) == 0)
646 && (state2_.out_depth(w) == 0))
652 if (problem_selection != subgraph_mono)
653 { // subgraph_iso and isomorphism
654 return comp_term_sets(term_in1_count, term_in2_count,
655 boost::mpl::int_< problem_selection >())
656 && comp_term_sets(term_out1_count, term_out2_count,
657 boost::mpl::int_< problem_selection >())
658 && comp_term_sets(rest1_count, rest2_count,
659 boost::mpl::int_< problem_selection >());
663 return comp_term_sets(term_in1_count, term_in2_count,
664 boost::mpl::int_< problem_selection >())
665 && comp_term_sets(term_out1_count, term_out2_count,
666 boost::mpl::int_< problem_selection >())
668 term_in1_count + term_out1_count + rest1_count,
669 term_in2_count + term_out2_count + rest2_count,
670 boost::mpl::int_< problem_selection >());
674 // Returns true if vertex v in graph1 is a possible candidate to
675 // be added to the current state
676 bool possible_candidate1(const vertex1_type& v) const
678 if (state1_.term_both() && state2_.term_both())
679 return state1_.term_both(v);
680 else if (state1_.term_out() && state2_.term_out())
681 return state1_.term_out(v);
682 else if (state1_.term_in() && state2_.term_in())
683 return state1_.term_in(v);
685 return !state1_.in_core(v);
688 // Returns true if vertex w in graph2 is a possible candidate to
689 // be added to the current state
690 bool possible_candidate2(const vertex2_type& w) const
692 if (state1_.term_both() && state2_.term_both())
693 return state2_.term_both(w);
694 else if (state1_.term_out() && state2_.term_out())
695 return state2_.term_out(w);
696 else if (state1_.term_in() && state2_.term_in())
697 return state2_.term_in(w);
699 return !state2_.in_core(w);
702 // Returns true if a mapping was found
705 return state1_.count() == num_vertices(graph1_);
708 // Returns true if a state is valid
711 boost::tuple< graph1_size_type, graph1_size_type, graph1_size_type >
713 boost::tuple< graph2_size_type, graph2_size_type, graph2_size_type >
716 term1 = state1_.term_set();
717 term2 = state2_.term_set();
719 return comp_term_sets(boost::get< 0 >(term1),
720 boost::get< 0 >(term2),
721 boost::mpl::int_< problem_selection >())
722 && comp_term_sets(boost::get< 1 >(term1),
723 boost::get< 1 >(term2),
724 boost::mpl::int_< problem_selection >())
725 && comp_term_sets(boost::get< 2 >(term1),
726 boost::get< 2 >(term2),
727 boost::mpl::int_< problem_selection >());
730 // Calls the user_callback with a graph (sub)graph mapping
731 bool call_back(SubGraphIsoMapCallback user_callback) const
733 return user_callback(state1_.get_map(), state2_.get_map());
737 // Data structure to keep info used for back tracking during
739 template < typename Graph1, typename Graph2, typename VertexOrder1 >
740 struct vf2_match_continuation
742 typename VertexOrder1::const_iterator graph1_verts_iter;
743 typename graph_traits< Graph2 >::vertex_iterator graph2_verts_iter;
746 // Non-recursive method that explores state space using a depth-first
747 // search strategy. At each depth possible pairs candidate are compute
748 // and tested for feasibility to extend the mapping. If a complete
749 // mapping is found, the mapping is output to user_callback in the form
750 // of a correspondence map (graph1 to graph2). Returning false from the
751 // user_callback will terminate the search. Function match will return
752 // true if the entire search space was explored.
753 template < typename Graph1, typename Graph2, typename IndexMap1,
754 typename IndexMap2, typename VertexOrder1,
755 typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate,
756 typename SubGraphIsoMapCallback, problem_selector problem_selection >
757 bool match(const Graph1& graph1, const Graph2& graph2,
758 SubGraphIsoMapCallback user_callback, const VertexOrder1& vertex_order1,
759 state< Graph1, Graph2, IndexMap1, IndexMap2, EdgeEquivalencePredicate,
760 VertexEquivalencePredicate, SubGraphIsoMapCallback,
761 problem_selection >& s)
764 typename VertexOrder1::const_iterator graph1_verts_iter;
766 typedef typename graph_traits< Graph2 >::vertex_iterator
767 vertex2_iterator_type;
768 vertex2_iterator_type graph2_verts_iter, graph2_verts_iter_end;
770 typedef vf2_match_continuation< Graph1, Graph2, VertexOrder1 >
771 match_continuation_type;
772 std::vector< match_continuation_type > k;
773 bool found_match = false;
778 if (!s.call_back(user_callback))
788 graph1_verts_iter = vertex_order1.begin();
789 while (graph1_verts_iter != vertex_order1.end()
790 && !s.possible_candidate1(*graph1_verts_iter))
795 boost::tie(graph2_verts_iter, graph2_verts_iter_end) = vertices(graph2);
796 while (graph2_verts_iter != graph2_verts_iter_end)
798 if (s.possible_candidate2(*graph2_verts_iter))
800 if (s.feasible(*graph1_verts_iter, *graph2_verts_iter))
802 match_continuation_type kk;
803 kk.graph1_verts_iter = graph1_verts_iter;
804 kk.graph2_verts_iter = graph2_verts_iter;
807 s.push(*graph1_verts_iter, *graph2_verts_iter);
819 const match_continuation_type kk = k.back();
820 graph1_verts_iter = kk.graph1_verts_iter;
821 graph2_verts_iter = kk.graph2_verts_iter;
824 s.pop(*graph1_verts_iter, *graph2_verts_iter);
829 // Used to sort nodes by in/out degrees
830 template < typename Graph > struct vertex_in_out_degree_cmp
832 typedef typename graph_traits< Graph >::vertex_descriptor vertex_type;
834 vertex_in_out_degree_cmp(const Graph& graph) : graph_(graph) {}
836 bool operator()(const vertex_type& v, const vertex_type& w) const
838 // lexicographical comparison
839 return std::make_pair(in_degree(v, graph_), out_degree(v, graph_))
840 < std::make_pair(in_degree(w, graph_), out_degree(w, graph_));
846 // Used to sort nodes by multiplicity of in/out degrees
847 template < typename Graph, typename FrequencyMap >
848 struct vertex_frequency_degree_cmp
850 typedef typename graph_traits< Graph >::vertex_descriptor vertex_type;
852 vertex_frequency_degree_cmp(const Graph& graph, FrequencyMap freq)
853 : graph_(graph), freq_(freq)
857 bool operator()(const vertex_type& v, const vertex_type& w) const
859 // lexicographical comparison
860 return std::make_pair(
861 freq_[v], in_degree(v, graph_) + out_degree(v, graph_))
863 freq_[w], in_degree(w, graph_) + out_degree(w, graph_));
870 // Sorts vertices of a graph by multiplicity of in/out degrees
871 template < typename Graph, typename IndexMap, typename VertexOrder >
873 const Graph& graph, IndexMap index_map, VertexOrder& order)
875 typedef typename graph_traits< Graph >::vertices_size_type size_type;
877 boost::range::sort(order, vertex_in_out_degree_cmp< Graph >(graph));
879 std::vector< size_type > freq_vec(num_vertices(graph), 0);
880 typedef iterator_property_map<
881 typename std::vector< size_type >::iterator, IndexMap, size_type,
885 frequency_map_type freq
886 = make_iterator_property_map(freq_vec.begin(), index_map);
888 typedef typename VertexOrder::iterator order_iterator;
890 for (order_iterator order_iter = order.begin();
891 order_iter != order.end();)
894 for (order_iterator count_iter = order_iter;
895 (count_iter != order.end())
896 && (in_degree(*order_iter, graph)
897 == in_degree(*count_iter, graph))
898 && (out_degree(*order_iter, graph)
899 == out_degree(*count_iter, graph));
903 for (size_type i = 0; i < count; ++i)
905 freq[*order_iter] = count;
910 boost::range::sort(order,
911 vertex_frequency_degree_cmp< Graph, frequency_map_type >(
915 // Enumerates all graph sub-graph mono-/iso-morphism mappings between graphs
916 // graph_small and graph_large. Continues until user_callback returns true
917 // or the search space has been fully explored.
918 template < problem_selector problem_selection, typename GraphSmall,
919 typename GraphLarge, typename IndexMapSmall, typename IndexMapLarge,
920 typename VertexOrderSmall, typename EdgeEquivalencePredicate,
921 typename VertexEquivalencePredicate, typename SubGraphIsoMapCallback >
922 bool vf2_subgraph_morphism(const GraphSmall& graph_small,
923 const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback,
924 IndexMapSmall index_map_small, IndexMapLarge index_map_large,
925 const VertexOrderSmall& vertex_order_small,
926 EdgeEquivalencePredicate edge_comp,
927 VertexEquivalencePredicate vertex_comp)
930 // Graph requirements
931 BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< GraphSmall >));
932 BOOST_CONCEPT_ASSERT((VertexListGraphConcept< GraphSmall >));
933 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< GraphSmall >));
934 BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< GraphSmall >));
936 BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< GraphLarge >));
937 BOOST_CONCEPT_ASSERT((VertexListGraphConcept< GraphLarge >));
938 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< GraphLarge >));
939 BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< GraphLarge >));
941 typedef typename graph_traits< GraphSmall >::vertex_descriptor
943 typedef typename graph_traits< GraphLarge >::vertex_descriptor
946 typedef typename graph_traits< GraphSmall >::vertices_size_type
948 typedef typename graph_traits< GraphLarge >::vertices_size_type
951 // Property map requirements
952 BOOST_CONCEPT_ASSERT(
953 (ReadablePropertyMapConcept< IndexMapSmall, vertex_small_type >));
954 typedef typename property_traits< IndexMapSmall >::value_type
957 (is_convertible< IndexMapSmallValue, size_type_small >::value));
959 BOOST_CONCEPT_ASSERT(
960 (ReadablePropertyMapConcept< IndexMapLarge, vertex_large_type >));
961 typedef typename property_traits< IndexMapLarge >::value_type
964 (is_convertible< IndexMapLargeValue, size_type_large >::value));
966 // Edge & vertex requirements
967 typedef typename graph_traits< GraphSmall >::edge_descriptor
969 typedef typename graph_traits< GraphLarge >::edge_descriptor
972 BOOST_CONCEPT_ASSERT((BinaryPredicateConcept< EdgeEquivalencePredicate,
973 edge_small_type, edge_large_type >));
975 BOOST_CONCEPT_ASSERT(
976 (BinaryPredicateConcept< VertexEquivalencePredicate,
977 vertex_small_type, vertex_large_type >));
979 // Vertex order requirements
980 BOOST_CONCEPT_ASSERT((ContainerConcept< VertexOrderSmall >));
981 typedef typename VertexOrderSmall::value_type order_value_type;
983 (is_same< vertex_small_type, order_value_type >::value));
984 BOOST_ASSERT(num_vertices(graph_small) == vertex_order_small.size());
986 if (num_vertices(graph_small) > num_vertices(graph_large))
989 typename graph_traits< GraphSmall >::edges_size_type num_edges_small
990 = num_edges(graph_small);
991 typename graph_traits< GraphLarge >::edges_size_type num_edges_large
992 = num_edges(graph_large);
994 // Double the number of edges for undirected graphs: each edge counts as
995 // in-edge and out-edge
996 if (is_undirected(graph_small))
997 num_edges_small *= 2;
998 if (is_undirected(graph_large))
999 num_edges_large *= 2;
1000 if (num_edges_small > num_edges_large)
1003 detail::state< GraphSmall, GraphLarge, IndexMapSmall, IndexMapLarge,
1004 EdgeEquivalencePredicate, VertexEquivalencePredicate,
1005 SubGraphIsoMapCallback, problem_selection >
1006 s(graph_small, graph_large, index_map_small, index_map_large,
1007 edge_comp, vertex_comp);
1009 return detail::match(
1010 graph_small, graph_large, user_callback, vertex_order_small, s);
1013 } // namespace detail
1015 // Returns vertex order (vertices sorted by multiplicity of in/out degrees)
1016 template < typename Graph >
1017 std::vector< typename graph_traits< Graph >::vertex_descriptor >
1018 vertex_order_by_mult(const Graph& graph)
1021 std::vector< typename graph_traits< Graph >::vertex_descriptor >
1023 std::copy(vertices(graph).first, vertices(graph).second,
1024 std::back_inserter(vertex_order));
1026 detail::sort_vertices(graph, get(vertex_index, graph), vertex_order);
1027 return vertex_order;
1030 // Enumerates all graph sub-graph monomorphism mappings between graphs
1031 // graph_small and graph_large. Continues until user_callback returns true or
1032 // the search space has been fully explored.
1033 template < typename GraphSmall, typename GraphLarge, typename IndexMapSmall,
1034 typename IndexMapLarge, typename VertexOrderSmall,
1035 typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate,
1036 typename SubGraphIsoMapCallback >
1037 bool vf2_subgraph_mono(const GraphSmall& graph_small,
1038 const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback,
1039 IndexMapSmall index_map_small, IndexMapLarge index_map_large,
1040 const VertexOrderSmall& vertex_order_small,
1041 EdgeEquivalencePredicate edge_comp, VertexEquivalencePredicate vertex_comp)
1043 return detail::vf2_subgraph_morphism< detail::subgraph_mono >(graph_small,
1044 graph_large, user_callback, index_map_small, index_map_large,
1045 vertex_order_small, edge_comp, vertex_comp);
1048 // All default interface for vf2_subgraph_iso
1049 template < typename GraphSmall, typename GraphLarge,
1050 typename SubGraphIsoMapCallback >
1051 bool vf2_subgraph_mono(const GraphSmall& graph_small,
1052 const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback)
1054 return vf2_subgraph_mono(graph_small, graph_large, user_callback,
1055 get(vertex_index, graph_small), get(vertex_index, graph_large),
1056 vertex_order_by_mult(graph_small), always_equivalent(),
1057 always_equivalent());
1060 // Named parameter interface of vf2_subgraph_iso
1061 template < typename GraphSmall, typename GraphLarge, typename VertexOrderSmall,
1062 typename SubGraphIsoMapCallback, typename Param, typename Tag,
1064 bool vf2_subgraph_mono(const GraphSmall& graph_small,
1065 const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback,
1066 const VertexOrderSmall& vertex_order_small,
1067 const bgl_named_params< Param, Tag, Rest >& params)
1069 return vf2_subgraph_mono(graph_small, graph_large, user_callback,
1071 get_param(params, vertex_index1), graph_small, vertex_index),
1073 get_param(params, vertex_index2), graph_large, vertex_index),
1076 get_param(params, edges_equivalent_t()), always_equivalent()),
1078 get_param(params, vertices_equivalent_t()), always_equivalent()));
1081 // Enumerates all graph sub-graph isomorphism mappings between graphs
1082 // graph_small and graph_large. Continues until user_callback returns true or
1083 // the search space has been fully explored.
1084 template < typename GraphSmall, typename GraphLarge, typename IndexMapSmall,
1085 typename IndexMapLarge, typename VertexOrderSmall,
1086 typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate,
1087 typename SubGraphIsoMapCallback >
1088 bool vf2_subgraph_iso(const GraphSmall& graph_small,
1089 const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback,
1090 IndexMapSmall index_map_small, IndexMapLarge index_map_large,
1091 const VertexOrderSmall& vertex_order_small,
1092 EdgeEquivalencePredicate edge_comp, VertexEquivalencePredicate vertex_comp)
1094 return detail::vf2_subgraph_morphism< detail::subgraph_iso >(graph_small,
1095 graph_large, user_callback, index_map_small, index_map_large,
1096 vertex_order_small, edge_comp, vertex_comp);
1099 // All default interface for vf2_subgraph_iso
1100 template < typename GraphSmall, typename GraphLarge,
1101 typename SubGraphIsoMapCallback >
1102 bool vf2_subgraph_iso(const GraphSmall& graph_small,
1103 const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback)
1106 return vf2_subgraph_iso(graph_small, graph_large, user_callback,
1107 get(vertex_index, graph_small), get(vertex_index, graph_large),
1108 vertex_order_by_mult(graph_small), always_equivalent(),
1109 always_equivalent());
1112 // Named parameter interface of vf2_subgraph_iso
1113 template < typename GraphSmall, typename GraphLarge, typename VertexOrderSmall,
1114 typename SubGraphIsoMapCallback, typename Param, typename Tag,
1116 bool vf2_subgraph_iso(const GraphSmall& graph_small,
1117 const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback,
1118 const VertexOrderSmall& vertex_order_small,
1119 const bgl_named_params< Param, Tag, Rest >& params)
1122 return vf2_subgraph_iso(graph_small, graph_large, user_callback,
1124 get_param(params, vertex_index1), graph_small, vertex_index),
1126 get_param(params, vertex_index2), graph_large, vertex_index),
1129 get_param(params, edges_equivalent_t()), always_equivalent()),
1131 get_param(params, vertices_equivalent_t()), always_equivalent()));
1134 // Enumerates all isomorphism mappings between graphs graph1_ and graph2_.
1135 // Continues until user_callback returns true or the search space has been
1137 template < typename Graph1, typename Graph2, typename IndexMap1,
1138 typename IndexMap2, typename VertexOrder1,
1139 typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate,
1140 typename GraphIsoMapCallback >
1141 bool vf2_graph_iso(const Graph1& graph1, const Graph2& graph2,
1142 GraphIsoMapCallback user_callback, IndexMap1 index_map1,
1143 IndexMap2 index_map2, const VertexOrder1& vertex_order1,
1144 EdgeEquivalencePredicate edge_comp, VertexEquivalencePredicate vertex_comp)
1147 // Graph requirements
1148 BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph1 >));
1149 BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph1 >));
1150 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph1 >));
1151 BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph1 >));
1153 BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph2 >));
1154 BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph2 >));
1155 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph2 >));
1156 BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph2 >));
1158 typedef typename graph_traits< Graph1 >::vertex_descriptor vertex1_type;
1159 typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2_type;
1161 typedef typename graph_traits< Graph1 >::vertices_size_type size_type1;
1162 typedef typename graph_traits< Graph2 >::vertices_size_type size_type2;
1164 // Property map requirements
1165 BOOST_CONCEPT_ASSERT(
1166 (ReadablePropertyMapConcept< IndexMap1, vertex1_type >));
1167 typedef typename property_traits< IndexMap1 >::value_type IndexMap1Value;
1168 BOOST_STATIC_ASSERT((is_convertible< IndexMap1Value, size_type1 >::value));
1170 BOOST_CONCEPT_ASSERT(
1171 (ReadablePropertyMapConcept< IndexMap2, vertex2_type >));
1172 typedef typename property_traits< IndexMap2 >::value_type IndexMap2Value;
1173 BOOST_STATIC_ASSERT((is_convertible< IndexMap2Value, size_type2 >::value));
1175 // Edge & vertex requirements
1176 typedef typename graph_traits< Graph1 >::edge_descriptor edge1_type;
1177 typedef typename graph_traits< Graph2 >::edge_descriptor edge2_type;
1179 BOOST_CONCEPT_ASSERT((BinaryPredicateConcept< EdgeEquivalencePredicate,
1180 edge1_type, edge2_type >));
1182 BOOST_CONCEPT_ASSERT((BinaryPredicateConcept< VertexEquivalencePredicate,
1183 vertex1_type, vertex2_type >));
1185 // Vertex order requirements
1186 BOOST_CONCEPT_ASSERT((ContainerConcept< VertexOrder1 >));
1187 typedef typename VertexOrder1::value_type order_value_type;
1188 BOOST_STATIC_ASSERT((is_same< vertex1_type, order_value_type >::value));
1189 BOOST_ASSERT(num_vertices(graph1) == vertex_order1.size());
1191 if (num_vertices(graph1) != num_vertices(graph2))
1194 typename graph_traits< Graph1 >::edges_size_type num_edges1
1195 = num_edges(graph1);
1196 typename graph_traits< Graph2 >::edges_size_type num_edges2
1197 = num_edges(graph2);
1199 // Double the number of edges for undirected graphs: each edge counts as
1200 // in-edge and out-edge
1201 if (is_undirected(graph1))
1203 if (is_undirected(graph2))
1205 if (num_edges1 != num_edges2)
1208 detail::state< Graph1, Graph2, IndexMap1, IndexMap2,
1209 EdgeEquivalencePredicate, VertexEquivalencePredicate,
1210 GraphIsoMapCallback, detail::isomorphism >
1211 s(graph1, graph2, index_map1, index_map2, edge_comp, vertex_comp);
1213 return detail::match(graph1, graph2, user_callback, vertex_order1, s);
1216 // All default interface for vf2_graph_iso
1217 template < typename Graph1, typename Graph2, typename GraphIsoMapCallback >
1218 bool vf2_graph_iso(const Graph1& graph1, const Graph2& graph2,
1219 GraphIsoMapCallback user_callback)
1222 return vf2_graph_iso(graph1, graph2, user_callback,
1223 get(vertex_index, graph1), get(vertex_index, graph2),
1224 vertex_order_by_mult(graph1), always_equivalent(), always_equivalent());
1227 // Named parameter interface of vf2_graph_iso
1228 template < typename Graph1, typename Graph2, typename VertexOrder1,
1229 typename GraphIsoMapCallback, typename Param, typename Tag, typename Rest >
1230 bool vf2_graph_iso(const Graph1& graph1, const Graph2& graph2,
1231 GraphIsoMapCallback user_callback, const VertexOrder1& vertex_order1,
1232 const bgl_named_params< Param, Tag, Rest >& params)
1235 return vf2_graph_iso(graph1, graph2, user_callback,
1237 get_param(params, vertex_index1), graph1, vertex_index),
1239 get_param(params, vertex_index2), graph2, vertex_index),
1242 get_param(params, edges_equivalent_t()), always_equivalent()),
1244 get_param(params, vertices_equivalent_t()), always_equivalent()));
1247 // Verifies a graph (sub)graph isomorphism map
1248 template < typename Graph1, typename Graph2, typename CorresponenceMap1To2,
1249 typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate >
1250 inline bool verify_vf2_subgraph_iso(const Graph1& graph1, const Graph2& graph2,
1251 const CorresponenceMap1To2 f, EdgeEquivalencePredicate edge_comp,
1252 VertexEquivalencePredicate vertex_comp)
1255 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph1 >));
1256 BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph2 >));
1258 detail::equivalent_edge_exists< Graph2 > edge2_exists;
1260 BGL_FORALL_EDGES_T(e1, graph1, Graph1)
1262 typename graph_traits< Graph1 >::vertex_descriptor s1, t1;
1263 typename graph_traits< Graph2 >::vertex_descriptor s2, t2;
1265 s1 = source(e1, graph1);
1266 t1 = target(e1, graph1);
1270 if (!vertex_comp(s1, s2) || !vertex_comp(t1, t2))
1273 typename graph_traits< Graph2 >::edge_descriptor e2;
1275 if (!edge2_exists(s2, t2,
1276 detail::edge2_predicate< Graph1, Graph2,
1277 EdgeEquivalencePredicate >(edge_comp, e1),
1285 // Variant of verify_subgraph_iso with all default parameters
1286 template < typename Graph1, typename Graph2, typename CorresponenceMap1To2 >
1287 inline bool verify_vf2_subgraph_iso(
1288 const Graph1& graph1, const Graph2& graph2, const CorresponenceMap1To2 f)
1290 return verify_vf2_subgraph_iso(
1291 graph1, graph2, f, always_equivalent(), always_equivalent());
1294 } // namespace boost
1296 #ifdef BOOST_ISO_INCLUDED_ITER_MACROS
1297 #undef BOOST_ISO_INCLUDED_ITER_MACROS
1298 #include <boost/graph/iteration_macros_undef.hpp>
1301 #endif // BOOST_VF2_SUB_GRAPH_ISO_HPP