File indexing completed on 2025-01-18 09:37:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #ifndef BOOST_VF2_SUB_GRAPH_ISO_HPP
0019 #define BOOST_VF2_SUB_GRAPH_ISO_HPP
0020
0021 #include <iostream>
0022 #include <iomanip>
0023 #include <iterator>
0024 #include <vector>
0025 #include <utility>
0026
0027 #include <boost/assert.hpp>
0028 #include <boost/concept/assert.hpp>
0029 #include <boost/concept_check.hpp>
0030 #include <boost/graph/graph_utility.hpp>
0031 #include <boost/graph/graph_traits.hpp>
0032 #include <boost/graph/mcgregor_common_subgraphs.hpp> // for always_equivalent
0033 #include <boost/graph/named_function_params.hpp>
0034 #include <boost/type_traits/has_less.hpp>
0035 #include <boost/mpl/int.hpp>
0036 #include <boost/range/algorithm/sort.hpp>
0037 #include <boost/tuple/tuple.hpp>
0038 #include <boost/utility/enable_if.hpp>
0039
0040 #ifndef BOOST_GRAPH_ITERATION_MACROS_HPP
0041 #define BOOST_ISO_INCLUDED_ITER_MACROS
0042 #include <boost/graph/iteration_macros.hpp>
0043 #endif
0044
0045 namespace boost
0046 {
0047
0048
0049 template < typename Graph1, typename Graph2 > struct vf2_print_callback
0050 {
0051
0052 vf2_print_callback(const Graph1& graph1, const Graph2& graph2)
0053 : graph1_(graph1), graph2_(graph2)
0054 {
0055 }
0056
0057 template < typename CorrespondenceMap1To2, typename CorrespondenceMap2To1 >
0058 bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1) const
0059 {
0060
0061
0062 BGL_FORALL_VERTICES_T(v, graph1_, Graph1)
0063 std::cout << '(' << get(vertex_index_t(), graph1_, v) << ", "
0064 << get(vertex_index_t(), graph2_, get(f, v)) << ") ";
0065
0066 std::cout << std::endl;
0067
0068 return true;
0069 }
0070
0071 private:
0072 const Graph1& graph1_;
0073 const Graph2& graph2_;
0074 };
0075
0076 namespace detail
0077 {
0078
0079
0080 template < typename GraphThis, typename GraphOther, typename IndexMapThis,
0081 typename IndexMapOther >
0082 class base_state
0083 {
0084
0085 typedef typename graph_traits< GraphThis >::vertex_descriptor
0086 vertex_this_type;
0087 typedef typename graph_traits< GraphOther >::vertex_descriptor
0088 vertex_other_type;
0089
0090 typedef
0091 typename graph_traits< GraphThis >::vertices_size_type size_type;
0092
0093 const GraphThis& graph_this_;
0094 const GraphOther& graph_other_;
0095
0096 IndexMapThis index_map_this_;
0097 IndexMapOther index_map_other_;
0098
0099 std::vector< vertex_other_type > core_vec_;
0100 typedef iterator_property_map<
0101 typename std::vector< vertex_other_type >::iterator, IndexMapThis,
0102 vertex_other_type, vertex_other_type& >
0103 core_map_type;
0104 core_map_type core_;
0105
0106 std::vector< size_type > in_vec_, out_vec_;
0107 typedef iterator_property_map<
0108 typename std::vector< size_type >::iterator, IndexMapThis,
0109 size_type, size_type& >
0110 in_out_map_type;
0111 in_out_map_type in_, out_;
0112
0113 size_type term_in_count_, term_out_count_, term_both_count_,
0114 core_count_;
0115
0116
0117 base_state(const base_state&);
0118 base_state& operator=(const base_state&);
0119
0120 public:
0121 base_state(const GraphThis& graph_this, const GraphOther& graph_other,
0122 IndexMapThis index_map_this, IndexMapOther index_map_other)
0123 : graph_this_(graph_this)
0124 , graph_other_(graph_other)
0125 , index_map_this_(index_map_this)
0126 , index_map_other_(index_map_other)
0127 , core_vec_(num_vertices(graph_this_),
0128 graph_traits< GraphOther >::null_vertex())
0129 , core_(core_vec_.begin(), index_map_this_)
0130 , in_vec_(num_vertices(graph_this_), 0)
0131 , out_vec_(num_vertices(graph_this_), 0)
0132 , in_(in_vec_.begin(), index_map_this_)
0133 , out_(out_vec_.begin(), index_map_this_)
0134 , term_in_count_(0)
0135 , term_out_count_(0)
0136 , term_both_count_(0)
0137 , core_count_(0)
0138 {
0139 }
0140
0141
0142 void push(
0143 const vertex_this_type& v_this, const vertex_other_type& v_other)
0144 {
0145
0146 ++core_count_;
0147
0148 put(core_, v_this, v_other);
0149
0150 if (!get(in_, v_this))
0151 {
0152 put(in_, v_this, core_count_);
0153 ++term_in_count_;
0154 if (get(out_, v_this))
0155 ++term_both_count_;
0156 }
0157
0158 if (!get(out_, v_this))
0159 {
0160 put(out_, v_this, core_count_);
0161 ++term_out_count_;
0162 if (get(in_, v_this))
0163 ++term_both_count_;
0164 }
0165
0166 BGL_FORALL_INEDGES_T(v_this, e, graph_this_, GraphThis)
0167 {
0168 vertex_this_type w = source(e, graph_this_);
0169 if (!get(in_, w))
0170 {
0171 put(in_, w, core_count_);
0172 ++term_in_count_;
0173 if (get(out_, w))
0174 ++term_both_count_;
0175 }
0176 }
0177
0178 BGL_FORALL_OUTEDGES_T(v_this, e, graph_this_, GraphThis)
0179 {
0180 vertex_this_type w = target(e, graph_this_);
0181 if (!get(out_, w))
0182 {
0183 put(out_, w, core_count_);
0184 ++term_out_count_;
0185 if (get(in_, w))
0186 ++term_both_count_;
0187 }
0188 }
0189 }
0190
0191
0192 void pop(const vertex_this_type& v_this, const vertex_other_type&)
0193 {
0194
0195 if (!core_count_)
0196 return;
0197
0198 if (get(in_, v_this) == core_count_)
0199 {
0200 put(in_, v_this, 0);
0201 --term_in_count_;
0202 if (get(out_, v_this))
0203 --term_both_count_;
0204 }
0205
0206 BGL_FORALL_INEDGES_T(v_this, e, graph_this_, GraphThis)
0207 {
0208 vertex_this_type w = source(e, graph_this_);
0209 if (get(in_, w) == core_count_)
0210 {
0211 put(in_, w, 0);
0212 --term_in_count_;
0213 if (get(out_, w))
0214 --term_both_count_;
0215 }
0216 }
0217
0218 if (get(out_, v_this) == core_count_)
0219 {
0220 put(out_, v_this, 0);
0221 --term_out_count_;
0222 if (get(in_, v_this))
0223 --term_both_count_;
0224 }
0225
0226 BGL_FORALL_OUTEDGES_T(v_this, e, graph_this_, GraphThis)
0227 {
0228 vertex_this_type w = target(e, graph_this_);
0229 if (get(out_, w) == core_count_)
0230 {
0231 put(out_, w, 0);
0232 --term_out_count_;
0233 if (get(in_, w))
0234 --term_both_count_;
0235 }
0236 }
0237 put(core_, v_this, graph_traits< GraphOther >::null_vertex());
0238
0239 --core_count_;
0240 }
0241
0242
0243 bool term_in() const { return core_count_ < term_in_count_; }
0244
0245
0246 bool term_in(const vertex_this_type& v) const
0247 {
0248 return (get(in_, v) > 0)
0249 && (get(core_, v) == graph_traits< GraphOther >::null_vertex());
0250 }
0251
0252
0253 bool term_out() const { return core_count_ < term_out_count_; }
0254
0255
0256 bool term_out(const vertex_this_type& v) const
0257 {
0258 return (get(out_, v) > 0)
0259 && (get(core_, v) == graph_traits< GraphOther >::null_vertex());
0260 }
0261
0262
0263 bool term_both() const { return core_count_ < term_both_count_; }
0264
0265
0266 bool term_both(const vertex_this_type& v) const
0267 {
0268 return (get(in_, v) > 0) && (get(out_, v) > 0)
0269 && (get(core_, v) == graph_traits< GraphOther >::null_vertex());
0270 }
0271
0272
0273
0274 bool in_core(const vertex_this_type& v) const
0275 {
0276 return get(core_, v) != graph_traits< GraphOther >::null_vertex();
0277 }
0278
0279
0280 size_type count() const { return core_count_; }
0281
0282
0283 vertex_other_type core(const vertex_this_type& v) const
0284 {
0285 return get(core_, v);
0286 }
0287
0288
0289 core_map_type get_map() const { return core_; }
0290
0291
0292
0293 size_type in_depth(const vertex_this_type& v) const
0294 {
0295 return get(in_, v);
0296 }
0297
0298
0299
0300 size_type out_depth(const vertex_this_type& v) const
0301 {
0302 return get(out_, v);
0303 }
0304
0305
0306 boost::tuple< size_type, size_type, size_type > term_set() const
0307 {
0308 return boost::make_tuple(
0309 term_in_count_, term_out_count_, term_both_count_);
0310 }
0311 };
0312
0313
0314
0315 template < typename Graph, typename Enable = void >
0316 struct equivalent_edge_exists
0317 {
0318 typedef
0319 typename boost::graph_traits< Graph >::edge_descriptor edge_type;
0320
0321 BOOST_CONCEPT_ASSERT((LessThanComparable< edge_type >));
0322
0323 template < typename EdgePredicate >
0324 bool operator()(typename graph_traits< Graph >::vertex_descriptor s,
0325 typename graph_traits< Graph >::vertex_descriptor t,
0326 EdgePredicate is_valid_edge, const Graph& g)
0327 {
0328
0329 BGL_FORALL_OUTEDGES_T(s, e, g, Graph)
0330 {
0331 if ((target(e, g) == t) && is_valid_edge(e)
0332 && (matched_edges_.find(e) == matched_edges_.end()))
0333 {
0334 matched_edges_.insert(e);
0335 return true;
0336 }
0337 }
0338
0339 return false;
0340 }
0341
0342 private:
0343 std::set< edge_type > matched_edges_;
0344 };
0345
0346 template < typename Graph >
0347 struct equivalent_edge_exists< Graph,
0348 typename boost::disable_if< is_multigraph< Graph > >::type >
0349 {
0350 template < typename EdgePredicate >
0351 bool operator()(typename graph_traits< Graph >::vertex_descriptor s,
0352 typename graph_traits< Graph >::vertex_descriptor t,
0353 EdgePredicate is_valid_edge, const Graph& g)
0354 {
0355
0356 typename graph_traits< Graph >::edge_descriptor e;
0357 bool found;
0358 boost::tie(e, found) = edge(s, t, g);
0359 if (!found)
0360 return false;
0361 else if (is_valid_edge(e))
0362 return true;
0363
0364 return false;
0365 }
0366 };
0367
0368
0369
0370 template < typename Graph1, typename Graph2,
0371 typename EdgeEquivalencePredicate >
0372 struct edge1_predicate
0373 {
0374
0375 edge1_predicate(EdgeEquivalencePredicate edge_comp,
0376 typename graph_traits< Graph2 >::edge_descriptor e2)
0377 : edge_comp_(edge_comp), e2_(e2)
0378 {
0379 }
0380
0381 bool operator()(typename graph_traits< Graph1 >::edge_descriptor e1)
0382 {
0383 return edge_comp_(e1, e2_);
0384 }
0385
0386 EdgeEquivalencePredicate edge_comp_;
0387 typename graph_traits< Graph2 >::edge_descriptor e2_;
0388 };
0389
0390
0391
0392 template < typename Graph1, typename Graph2,
0393 typename EdgeEquivalencePredicate >
0394 struct edge2_predicate
0395 {
0396
0397 edge2_predicate(EdgeEquivalencePredicate edge_comp,
0398 typename graph_traits< Graph1 >::edge_descriptor e1)
0399 : edge_comp_(edge_comp), e1_(e1)
0400 {
0401 }
0402
0403 bool operator()(typename graph_traits< Graph2 >::edge_descriptor e2)
0404 {
0405 return edge_comp_(e1_, e2);
0406 }
0407
0408 EdgeEquivalencePredicate edge_comp_;
0409 typename graph_traits< Graph1 >::edge_descriptor e1_;
0410 };
0411
0412 enum problem_selector
0413 {
0414 subgraph_mono,
0415 subgraph_iso,
0416 isomorphism
0417 };
0418
0419
0420 template < typename Graph1, typename Graph2, typename IndexMap1,
0421 typename IndexMap2, typename EdgeEquivalencePredicate,
0422 typename VertexEquivalencePredicate, typename SubGraphIsoMapCallback,
0423 problem_selector problem_selection >
0424 class state
0425 {
0426
0427 typedef typename graph_traits< Graph1 >::vertex_descriptor vertex1_type;
0428 typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2_type;
0429
0430 typedef typename graph_traits< Graph1 >::edge_descriptor edge1_type;
0431 typedef typename graph_traits< Graph2 >::edge_descriptor edge2_type;
0432
0433 typedef typename graph_traits< Graph1 >::vertices_size_type
0434 graph1_size_type;
0435 typedef typename graph_traits< Graph2 >::vertices_size_type
0436 graph2_size_type;
0437
0438 const Graph1& graph1_;
0439 const Graph2& graph2_;
0440
0441 IndexMap1 index_map1_;
0442
0443 EdgeEquivalencePredicate edge_comp_;
0444 VertexEquivalencePredicate vertex_comp_;
0445
0446 base_state< Graph1, Graph2, IndexMap1, IndexMap2 > state1_;
0447 base_state< Graph2, Graph1, IndexMap2, IndexMap1 > state2_;
0448
0449
0450
0451
0452 inline bool comp_term_sets(graph1_size_type a, graph2_size_type b,
0453 boost::mpl::int_< subgraph_mono >) const
0454 {
0455 return a <= b;
0456 }
0457
0458
0459 inline bool comp_term_sets(graph1_size_type a, graph2_size_type b,
0460 boost::mpl::int_< subgraph_iso >) const
0461 {
0462 return a <= b;
0463 }
0464
0465
0466 inline bool comp_term_sets(graph1_size_type a, graph2_size_type b,
0467 boost::mpl::int_< isomorphism >) const
0468 {
0469 return a == b;
0470 }
0471
0472
0473 state(const state&);
0474 state& operator=(const state&);
0475
0476 public:
0477 state(const Graph1& graph1, const Graph2& graph2, IndexMap1 index_map1,
0478 IndexMap2 index_map2, EdgeEquivalencePredicate edge_comp,
0479 VertexEquivalencePredicate vertex_comp)
0480 : graph1_(graph1)
0481 , graph2_(graph2)
0482 , index_map1_(index_map1)
0483 , edge_comp_(edge_comp)
0484 , vertex_comp_(vertex_comp)
0485 , state1_(graph1, graph2, index_map1, index_map2)
0486 , state2_(graph2, graph1, index_map2, index_map1)
0487 {
0488 }
0489
0490
0491 void push(const vertex1_type& v, const vertex2_type& w)
0492 {
0493 state1_.push(v, w);
0494 state2_.push(w, v);
0495 }
0496
0497
0498 void pop(const vertex1_type& v, const vertex2_type&)
0499 {
0500 vertex2_type w = state1_.core(v);
0501 state1_.pop(v, w);
0502 state2_.pop(w, v);
0503 }
0504
0505
0506 bool feasible(const vertex1_type& v_new, const vertex2_type& w_new)
0507 {
0508
0509 if (!vertex_comp_(v_new, w_new))
0510 return false;
0511
0512
0513 graph1_size_type term_in1_count = 0, term_out1_count = 0,
0514 rest1_count = 0;
0515
0516 {
0517 equivalent_edge_exists< Graph2 > edge2_exists;
0518
0519 BGL_FORALL_INEDGES_T(v_new, e1, graph1_, Graph1)
0520 {
0521 vertex1_type v = source(e1, graph1_);
0522
0523 if (state1_.in_core(v) || (v == v_new))
0524 {
0525 vertex2_type w = w_new;
0526 if (v != v_new)
0527 w = state1_.core(v);
0528 if (!edge2_exists(w, w_new,
0529 edge2_predicate< Graph1, Graph2,
0530 EdgeEquivalencePredicate >(edge_comp_, e1),
0531 graph2_))
0532 return false;
0533 }
0534 else
0535 {
0536 if (0 < state1_.in_depth(v))
0537 ++term_in1_count;
0538 if (0 < state1_.out_depth(v))
0539 ++term_out1_count;
0540 if ((state1_.in_depth(v) == 0)
0541 && (state1_.out_depth(v) == 0))
0542 ++rest1_count;
0543 }
0544 }
0545 }
0546
0547 {
0548 equivalent_edge_exists< Graph2 > edge2_exists;
0549
0550 BGL_FORALL_OUTEDGES_T(v_new, e1, graph1_, Graph1)
0551 {
0552 vertex1_type v = target(e1, graph1_);
0553 if (state1_.in_core(v) || (v == v_new))
0554 {
0555 vertex2_type w = w_new;
0556 if (v != v_new)
0557 w = state1_.core(v);
0558
0559 if (!edge2_exists(w_new, w,
0560 edge2_predicate< Graph1, Graph2,
0561 EdgeEquivalencePredicate >(edge_comp_, e1),
0562 graph2_))
0563 return false;
0564 }
0565 else
0566 {
0567 if (0 < state1_.in_depth(v))
0568 ++term_in1_count;
0569 if (0 < state1_.out_depth(v))
0570 ++term_out1_count;
0571 if ((state1_.in_depth(v) == 0)
0572 && (state1_.out_depth(v) == 0))
0573 ++rest1_count;
0574 }
0575 }
0576 }
0577
0578
0579 graph2_size_type term_out2_count = 0, term_in2_count = 0,
0580 rest2_count = 0;
0581
0582 {
0583 equivalent_edge_exists< Graph1 > edge1_exists;
0584
0585 BGL_FORALL_INEDGES_T(w_new, e2, graph2_, Graph2)
0586 {
0587 vertex2_type w = source(e2, graph2_);
0588 if (state2_.in_core(w) || (w == w_new))
0589 {
0590 if (problem_selection != subgraph_mono)
0591 {
0592 vertex1_type v = v_new;
0593 if (w != w_new)
0594 v = state2_.core(w);
0595
0596 if (!edge1_exists(v, v_new,
0597 edge1_predicate< Graph1, Graph2,
0598 EdgeEquivalencePredicate >(
0599 edge_comp_, e2),
0600 graph1_))
0601 return false;
0602 }
0603 }
0604 else
0605 {
0606 if (0 < state2_.in_depth(w))
0607 ++term_in2_count;
0608 if (0 < state2_.out_depth(w))
0609 ++term_out2_count;
0610 if ((state2_.in_depth(w) == 0)
0611 && (state2_.out_depth(w) == 0))
0612 ++rest2_count;
0613 }
0614 }
0615 }
0616
0617 {
0618 equivalent_edge_exists< Graph1 > edge1_exists;
0619
0620 BGL_FORALL_OUTEDGES_T(w_new, e2, graph2_, Graph2)
0621 {
0622 vertex2_type w = target(e2, graph2_);
0623 if (state2_.in_core(w) || (w == w_new))
0624 {
0625 if (problem_selection != subgraph_mono)
0626 {
0627 vertex1_type v = v_new;
0628 if (w != w_new)
0629 v = state2_.core(w);
0630
0631 if (!edge1_exists(v_new, v,
0632 edge1_predicate< Graph1, Graph2,
0633 EdgeEquivalencePredicate >(
0634 edge_comp_, e2),
0635 graph1_))
0636 return false;
0637 }
0638 }
0639 else
0640 {
0641 if (0 < state2_.in_depth(w))
0642 ++term_in2_count;
0643 if (0 < state2_.out_depth(w))
0644 ++term_out2_count;
0645 if ((state2_.in_depth(w) == 0)
0646 && (state2_.out_depth(w) == 0))
0647 ++rest2_count;
0648 }
0649 }
0650 }
0651
0652 if (problem_selection != subgraph_mono)
0653 {
0654 return comp_term_sets(term_in1_count, term_in2_count,
0655 boost::mpl::int_< problem_selection >())
0656 && comp_term_sets(term_out1_count, term_out2_count,
0657 boost::mpl::int_< problem_selection >())
0658 && comp_term_sets(rest1_count, rest2_count,
0659 boost::mpl::int_< problem_selection >());
0660 }
0661 else
0662 {
0663 return comp_term_sets(term_in1_count, term_in2_count,
0664 boost::mpl::int_< problem_selection >())
0665 && comp_term_sets(term_out1_count, term_out2_count,
0666 boost::mpl::int_< problem_selection >())
0667 && comp_term_sets(
0668 term_in1_count + term_out1_count + rest1_count,
0669 term_in2_count + term_out2_count + rest2_count,
0670 boost::mpl::int_< problem_selection >());
0671 }
0672 }
0673
0674
0675
0676 bool possible_candidate1(const vertex1_type& v) const
0677 {
0678 if (state1_.term_both() && state2_.term_both())
0679 return state1_.term_both(v);
0680 else if (state1_.term_out() && state2_.term_out())
0681 return state1_.term_out(v);
0682 else if (state1_.term_in() && state2_.term_in())
0683 return state1_.term_in(v);
0684 else
0685 return !state1_.in_core(v);
0686 }
0687
0688
0689
0690 bool possible_candidate2(const vertex2_type& w) const
0691 {
0692 if (state1_.term_both() && state2_.term_both())
0693 return state2_.term_both(w);
0694 else if (state1_.term_out() && state2_.term_out())
0695 return state2_.term_out(w);
0696 else if (state1_.term_in() && state2_.term_in())
0697 return state2_.term_in(w);
0698 else
0699 return !state2_.in_core(w);
0700 }
0701
0702
0703 bool success() const
0704 {
0705 return state1_.count() == num_vertices(graph1_);
0706 }
0707
0708
0709 bool valid() const
0710 {
0711 boost::tuple< graph1_size_type, graph1_size_type, graph1_size_type >
0712 term1;
0713 boost::tuple< graph2_size_type, graph2_size_type, graph2_size_type >
0714 term2;
0715
0716 term1 = state1_.term_set();
0717 term2 = state2_.term_set();
0718
0719 return comp_term_sets(boost::get< 0 >(term1),
0720 boost::get< 0 >(term2),
0721 boost::mpl::int_< problem_selection >())
0722 && comp_term_sets(boost::get< 1 >(term1),
0723 boost::get< 1 >(term2),
0724 boost::mpl::int_< problem_selection >())
0725 && comp_term_sets(boost::get< 2 >(term1),
0726 boost::get< 2 >(term2),
0727 boost::mpl::int_< problem_selection >());
0728 }
0729
0730
0731 bool call_back(SubGraphIsoMapCallback user_callback) const
0732 {
0733 return user_callback(state1_.get_map(), state2_.get_map());
0734 }
0735 };
0736
0737
0738
0739 template < typename Graph1, typename Graph2, typename VertexOrder1 >
0740 struct vf2_match_continuation
0741 {
0742 typename VertexOrder1::const_iterator graph1_verts_iter;
0743 typename graph_traits< Graph2 >::vertex_iterator graph2_verts_iter;
0744 };
0745
0746
0747
0748
0749
0750
0751
0752
0753 template < typename Graph1, typename Graph2, typename IndexMap1,
0754 typename IndexMap2, typename VertexOrder1,
0755 typename EdgeEquivalencePredicate, typename VertexEquivalencePredicate,
0756 typename SubGraphIsoMapCallback, problem_selector problem_selection >
0757 bool match(const Graph1& graph1, const Graph2& graph2,
0758 SubGraphIsoMapCallback user_callback, const VertexOrder1& vertex_order1,
0759 state< Graph1, Graph2, IndexMap1, IndexMap2, EdgeEquivalencePredicate,
0760 VertexEquivalencePredicate, SubGraphIsoMapCallback,
0761 problem_selection >& s)
0762 {
0763
0764 typename VertexOrder1::const_iterator graph1_verts_iter;
0765
0766 typedef typename graph_traits< Graph2 >::vertex_iterator
0767 vertex2_iterator_type;
0768 vertex2_iterator_type graph2_verts_iter, graph2_verts_iter_end;
0769
0770 typedef vf2_match_continuation< Graph1, Graph2, VertexOrder1 >
0771 match_continuation_type;
0772 std::vector< match_continuation_type > k;
0773 bool found_match = false;
0774
0775 recur:
0776 if (s.success())
0777 {
0778 if (!s.call_back(user_callback))
0779 return true;
0780 found_match = true;
0781
0782 goto back_track;
0783 }
0784
0785 if (!s.valid())
0786 goto back_track;
0787
0788 graph1_verts_iter = vertex_order1.begin();
0789 while (graph1_verts_iter != vertex_order1.end()
0790 && !s.possible_candidate1(*graph1_verts_iter))
0791 {
0792 ++graph1_verts_iter;
0793 }
0794
0795 boost::tie(graph2_verts_iter, graph2_verts_iter_end) = vertices(graph2);
0796 while (graph2_verts_iter != graph2_verts_iter_end)
0797 {
0798 if (s.possible_candidate2(*graph2_verts_iter))
0799 {
0800 if (s.feasible(*graph1_verts_iter, *graph2_verts_iter))
0801 {
0802 match_continuation_type kk;
0803 kk.graph1_verts_iter = graph1_verts_iter;
0804 kk.graph2_verts_iter = graph2_verts_iter;
0805 k.push_back(kk);
0806
0807 s.push(*graph1_verts_iter, *graph2_verts_iter);
0808 goto recur;
0809 }
0810 }
0811 graph2_loop:
0812 ++graph2_verts_iter;
0813 }
0814
0815 back_track:
0816 if (k.empty())
0817 return found_match;
0818
0819 const match_continuation_type kk = k.back();
0820 graph1_verts_iter = kk.graph1_verts_iter;
0821 graph2_verts_iter = kk.graph2_verts_iter;
0822 k.pop_back();
0823
0824 s.pop(*graph1_verts_iter, *graph2_verts_iter);
0825
0826 goto graph2_loop;
0827 }
0828
0829
0830 template < typename Graph > struct vertex_in_out_degree_cmp
0831 {
0832 typedef typename graph_traits< Graph >::vertex_descriptor vertex_type;
0833
0834 vertex_in_out_degree_cmp(const Graph& graph) : graph_(graph) {}
0835
0836 bool operator()(const vertex_type& v, const vertex_type& w) const
0837 {
0838
0839 return std::make_pair(in_degree(v, graph_), out_degree(v, graph_))
0840 < std::make_pair(in_degree(w, graph_), out_degree(w, graph_));
0841 }
0842
0843 const Graph& graph_;
0844 };
0845
0846
0847 template < typename Graph, typename FrequencyMap >
0848 struct vertex_frequency_degree_cmp
0849 {
0850 typedef typename graph_traits< Graph >::vertex_descriptor vertex_type;
0851
0852 vertex_frequency_degree_cmp(const Graph& graph, FrequencyMap freq)
0853 : graph_(graph), freq_(freq)
0854 {
0855 }
0856
0857 bool operator()(const vertex_type& v, const vertex_type& w) const
0858 {
0859
0860 return std::make_pair(
0861 freq_[v], in_degree(v, graph_) + out_degree(v, graph_))
0862 < std::make_pair(
0863 freq_[w], in_degree(w, graph_) + out_degree(w, graph_));
0864 }
0865
0866 const Graph& graph_;
0867 FrequencyMap freq_;
0868 };
0869
0870
0871 template < typename Graph, typename IndexMap, typename VertexOrder >
0872 void sort_vertices(
0873 const Graph& graph, IndexMap index_map, VertexOrder& order)
0874 {
0875 typedef typename graph_traits< Graph >::vertices_size_type size_type;
0876
0877 boost::range::sort(order, vertex_in_out_degree_cmp< Graph >(graph));
0878
0879 std::vector< size_type > freq_vec(num_vertices(graph), 0);
0880 typedef iterator_property_map<
0881 typename std::vector< size_type >::iterator, IndexMap, size_type,
0882 size_type& >
0883 frequency_map_type;
0884
0885 frequency_map_type freq
0886 = make_iterator_property_map(freq_vec.begin(), index_map);
0887
0888 typedef typename VertexOrder::iterator order_iterator;
0889
0890 for (order_iterator order_iter = order.begin();
0891 order_iter != order.end();)
0892 {
0893 size_type count = 0;
0894 for (order_iterator count_iter = order_iter;
0895 (count_iter != order.end())
0896 && (in_degree(*order_iter, graph)
0897 == in_degree(*count_iter, graph))
0898 && (out_degree(*order_iter, graph)
0899 == out_degree(*count_iter, graph));
0900 ++count_iter)
0901 ++count;
0902
0903 for (size_type i = 0; i < count; ++i)
0904 {
0905 freq[*order_iter] = count;
0906 ++order_iter;
0907 }
0908 }
0909
0910 boost::range::sort(order,
0911 vertex_frequency_degree_cmp< Graph, frequency_map_type >(
0912 graph, freq));
0913 }
0914
0915
0916
0917
0918 template < problem_selector problem_selection, typename GraphSmall,
0919 typename GraphLarge, typename IndexMapSmall, typename IndexMapLarge,
0920 typename VertexOrderSmall, typename EdgeEquivalencePredicate,
0921 typename VertexEquivalencePredicate, typename SubGraphIsoMapCallback >
0922 bool vf2_subgraph_morphism(const GraphSmall& graph_small,
0923 const GraphLarge& graph_large, SubGraphIsoMapCallback user_callback,
0924 IndexMapSmall index_map_small, IndexMapLarge index_map_large,
0925 const VertexOrderSmall& vertex_order_small,
0926 EdgeEquivalencePredicate edge_comp,
0927 VertexEquivalencePredicate vertex_comp)
0928 {
0929
0930
0931 BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< GraphSmall >));
0932 BOOST_CONCEPT_ASSERT((VertexListGraphConcept< GraphSmall >));
0933 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< GraphSmall >));
0934 BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< GraphSmall >));
0935
0936 BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< GraphLarge >));
0937 BOOST_CONCEPT_ASSERT((VertexListGraphConcept< GraphLarge >));
0938 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< GraphLarge >));
0939 BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< GraphLarge >));
0940
0941 typedef typename graph_traits< GraphSmall >::vertex_descriptor
0942 vertex_small_type;
0943 typedef typename graph_traits< GraphLarge >::vertex_descriptor
0944 vertex_large_type;
0945
0946 typedef typename graph_traits< GraphSmall >::vertices_size_type
0947 size_type_small;
0948 typedef typename graph_traits< GraphLarge >::vertices_size_type
0949 size_type_large;
0950
0951
0952 BOOST_CONCEPT_ASSERT(
0953 (ReadablePropertyMapConcept< IndexMapSmall, vertex_small_type >));
0954 typedef typename property_traits< IndexMapSmall >::value_type
0955 IndexMapSmallValue;
0956 BOOST_STATIC_ASSERT(
0957 (is_convertible< IndexMapSmallValue, size_type_small >::value));
0958
0959 BOOST_CONCEPT_ASSERT(
0960 (ReadablePropertyMapConcept< IndexMapLarge, vertex_large_type >));
0961 typedef typename property_traits< IndexMapLarge >::value_type
0962 IndexMapLargeValue;
0963 BOOST_STATIC_ASSERT(
0964 (is_convertible< IndexMapLargeValue, size_type_large >::value));
0965
0966
0967 typedef typename graph_traits< GraphSmall >::edge_descriptor
0968 edge_small_type;
0969 typedef typename graph_traits< GraphLarge >::edge_descriptor
0970 edge_large_type;
0971
0972 BOOST_CONCEPT_ASSERT((BinaryPredicateConcept< EdgeEquivalencePredicate,
0973 edge_small_type, edge_large_type >));
0974
0975 BOOST_CONCEPT_ASSERT(
0976 (BinaryPredicateConcept< VertexEquivalencePredicate,
0977 vertex_small_type, vertex_large_type >));
0978
0979
0980 BOOST_CONCEPT_ASSERT((ContainerConcept< VertexOrderSmall >));
0981 typedef typename VertexOrderSmall::value_type order_value_type;
0982 BOOST_STATIC_ASSERT(
0983 (is_same< vertex_small_type, order_value_type >::value));
0984 BOOST_ASSERT(num_vertices(graph_small) == vertex_order_small.size());
0985
0986 if (num_vertices(graph_small) > num_vertices(graph_large))
0987 return false;
0988
0989 typename graph_traits< GraphSmall >::edges_size_type num_edges_small
0990 = num_edges(graph_small);
0991 typename graph_traits< GraphLarge >::edges_size_type num_edges_large
0992 = num_edges(graph_large);
0993
0994
0995
0996 if (is_undirected(graph_small))
0997 num_edges_small *= 2;
0998 if (is_undirected(graph_large))
0999 num_edges_large *= 2;
1000 if (num_edges_small > num_edges_large)
1001 return false;
1002
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);
1008
1009 return detail::match(
1010 graph_small, graph_large, user_callback, vertex_order_small, s);
1011 }
1012
1013 }
1014
1015
1016 template < typename Graph >
1017 std::vector< typename graph_traits< Graph >::vertex_descriptor >
1018 vertex_order_by_mult(const Graph& graph)
1019 {
1020
1021 std::vector< typename graph_traits< Graph >::vertex_descriptor >
1022 vertex_order;
1023 std::copy(vertices(graph).first, vertices(graph).second,
1024 std::back_inserter(vertex_order));
1025
1026 detail::sort_vertices(graph, get(vertex_index, graph), vertex_order);
1027 return vertex_order;
1028 }
1029
1030
1031
1032
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)
1042 {
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);
1046 }
1047
1048
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)
1053 {
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());
1058 }
1059
1060
1061 template < typename GraphSmall, typename GraphLarge, typename VertexOrderSmall,
1062 typename SubGraphIsoMapCallback, typename Param, typename Tag,
1063 typename Rest >
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)
1068 {
1069 return vf2_subgraph_mono(graph_small, graph_large, user_callback,
1070 choose_const_pmap(
1071 get_param(params, vertex_index1), graph_small, vertex_index),
1072 choose_const_pmap(
1073 get_param(params, vertex_index2), graph_large, vertex_index),
1074 vertex_order_small,
1075 choose_param(
1076 get_param(params, edges_equivalent_t()), always_equivalent()),
1077 choose_param(
1078 get_param(params, vertices_equivalent_t()), always_equivalent()));
1079 }
1080
1081
1082
1083
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)
1093 {
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);
1097 }
1098
1099
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)
1104 {
1105
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());
1110 }
1111
1112
1113 template < typename GraphSmall, typename GraphLarge, typename VertexOrderSmall,
1114 typename SubGraphIsoMapCallback, typename Param, typename Tag,
1115 typename Rest >
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)
1120 {
1121
1122 return vf2_subgraph_iso(graph_small, graph_large, user_callback,
1123 choose_const_pmap(
1124 get_param(params, vertex_index1), graph_small, vertex_index),
1125 choose_const_pmap(
1126 get_param(params, vertex_index2), graph_large, vertex_index),
1127 vertex_order_small,
1128 choose_param(
1129 get_param(params, edges_equivalent_t()), always_equivalent()),
1130 choose_param(
1131 get_param(params, vertices_equivalent_t()), always_equivalent()));
1132 }
1133
1134
1135
1136
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)
1145 {
1146
1147
1148 BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph1 >));
1149 BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph1 >));
1150 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph1 >));
1151 BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph1 >));
1152
1153 BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph2 >));
1154 BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph2 >));
1155 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph2 >));
1156 BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph2 >));
1157
1158 typedef typename graph_traits< Graph1 >::vertex_descriptor vertex1_type;
1159 typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2_type;
1160
1161 typedef typename graph_traits< Graph1 >::vertices_size_type size_type1;
1162 typedef typename graph_traits< Graph2 >::vertices_size_type size_type2;
1163
1164
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));
1169
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));
1174
1175
1176 typedef typename graph_traits< Graph1 >::edge_descriptor edge1_type;
1177 typedef typename graph_traits< Graph2 >::edge_descriptor edge2_type;
1178
1179 BOOST_CONCEPT_ASSERT((BinaryPredicateConcept< EdgeEquivalencePredicate,
1180 edge1_type, edge2_type >));
1181
1182 BOOST_CONCEPT_ASSERT((BinaryPredicateConcept< VertexEquivalencePredicate,
1183 vertex1_type, vertex2_type >));
1184
1185
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());
1190
1191 if (num_vertices(graph1) != num_vertices(graph2))
1192 return false;
1193
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);
1198
1199
1200
1201 if (is_undirected(graph1))
1202 num_edges1 *= 2;
1203 if (is_undirected(graph2))
1204 num_edges2 *= 2;
1205 if (num_edges1 != num_edges2)
1206 return false;
1207
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);
1212
1213 return detail::match(graph1, graph2, user_callback, vertex_order1, s);
1214 }
1215
1216
1217 template < typename Graph1, typename Graph2, typename GraphIsoMapCallback >
1218 bool vf2_graph_iso(const Graph1& graph1, const Graph2& graph2,
1219 GraphIsoMapCallback user_callback)
1220 {
1221
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());
1225 }
1226
1227
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)
1233 {
1234
1235 return vf2_graph_iso(graph1, graph2, user_callback,
1236 choose_const_pmap(
1237 get_param(params, vertex_index1), graph1, vertex_index),
1238 choose_const_pmap(
1239 get_param(params, vertex_index2), graph2, vertex_index),
1240 vertex_order1,
1241 choose_param(
1242 get_param(params, edges_equivalent_t()), always_equivalent()),
1243 choose_param(
1244 get_param(params, vertices_equivalent_t()), always_equivalent()));
1245 }
1246
1247
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)
1253 {
1254
1255 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph1 >));
1256 BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph2 >));
1257
1258 detail::equivalent_edge_exists< Graph2 > edge2_exists;
1259
1260 BGL_FORALL_EDGES_T(e1, graph1, Graph1)
1261 {
1262 typename graph_traits< Graph1 >::vertex_descriptor s1, t1;
1263 typename graph_traits< Graph2 >::vertex_descriptor s2, t2;
1264
1265 s1 = source(e1, graph1);
1266 t1 = target(e1, graph1);
1267 s2 = get(f, s1);
1268 t2 = get(f, t1);
1269
1270 if (!vertex_comp(s1, s2) || !vertex_comp(t1, t2))
1271 return false;
1272
1273 typename graph_traits< Graph2 >::edge_descriptor e2;
1274
1275 if (!edge2_exists(s2, t2,
1276 detail::edge2_predicate< Graph1, Graph2,
1277 EdgeEquivalencePredicate >(edge_comp, e1),
1278 graph2))
1279 return false;
1280 }
1281
1282 return true;
1283 }
1284
1285
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)
1289 {
1290 return verify_vf2_subgraph_iso(
1291 graph1, graph2, f, always_equivalent(), always_equivalent());
1292 }
1293
1294 }
1295
1296 #ifdef BOOST_ISO_INCLUDED_ITER_MACROS
1297 #undef BOOST_ISO_INCLUDED_ITER_MACROS
1298 #include <boost/graph/iteration_macros_undef.hpp>
1299 #endif
1300
1301 #endif