annotate DEPENDENCIES/generic/include/boost/graph/vf2_sub_graph_iso.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 //=======================================================================
Chris@16 2 // Copyright (C) 2012 Flavio De Lorenzi (fdlorenzi@gmail.com)
Chris@16 3 // Copyright (C) 2013 Jakob Lykke Andersen, University of Southern Denmark (jlandersen@imada.sdu.dk)
Chris@16 4 //
Chris@16 5 // The algorithm implemented here is derived from original ideas by
Chris@16 6 // Pasquale Foggia and colaborators. For further information see
Chris@16 7 // e.g. Cordella et al. 2001, 2004.
Chris@16 8 //
Chris@16 9 // Distributed under the Boost Software License, Version 1.0. (See
Chris@16 10 // accompanying file LICENSE_1_0.txt or copy at
Chris@16 11 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 12 //=======================================================================
Chris@16 13
Chris@16 14 // Revision History:
Chris@16 15 // 8 April 2013: Fixed a typo in vf2_print_callback. (Flavio De Lorenzi)
Chris@16 16
Chris@16 17 #ifndef BOOST_VF2_SUB_GRAPH_ISO_HPP
Chris@16 18 #define BOOST_VF2_SUB_GRAPH_ISO_HPP
Chris@16 19
Chris@16 20 #include <iostream>
Chris@16 21 #include <iomanip>
Chris@16 22 #include <iterator>
Chris@16 23 #include <vector>
Chris@16 24 #include <utility>
Chris@16 25
Chris@16 26 #include <boost/assert.hpp>
Chris@16 27 #include <boost/concept/assert.hpp>
Chris@16 28 #include <boost/concept_check.hpp>
Chris@16 29 #include <boost/graph/graph_utility.hpp>
Chris@16 30 #include <boost/graph/graph_traits.hpp>
Chris@16 31 #include <boost/graph/mcgregor_common_subgraphs.hpp> // for always_equivalent
Chris@16 32 #include <boost/graph/named_function_params.hpp>
Chris@16 33 #include <boost/type_traits/has_less.hpp>
Chris@16 34 #include <boost/mpl/int.hpp>
Chris@16 35 #include <boost/range/algorithm/sort.hpp>
Chris@16 36 #include <boost/tuple/tuple.hpp>
Chris@16 37 #include <boost/utility/enable_if.hpp>
Chris@16 38
Chris@16 39 #ifndef BOOST_GRAPH_ITERATION_MACROS_HPP
Chris@16 40 #define BOOST_ISO_INCLUDED_ITER_MACROS // local macro, see bottom of file
Chris@16 41 #include <boost/graph/iteration_macros.hpp>
Chris@16 42 #endif
Chris@16 43
Chris@16 44 namespace boost {
Chris@16 45
Chris@16 46 // Default print_callback
Chris@16 47 template <typename Graph1,
Chris@16 48 typename Graph2>
Chris@16 49 struct vf2_print_callback {
Chris@16 50
Chris@16 51 vf2_print_callback(const Graph1& graph1, const Graph2& graph2)
Chris@16 52 : graph1_(graph1), graph2_(graph2) {}
Chris@16 53
Chris@16 54 template <typename CorrespondenceMap1To2,
Chris@16 55 typename CorrespondenceMap2To1>
Chris@16 56 bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1) const {
Chris@16 57
Chris@16 58 // Print (sub)graph isomorphism map
Chris@16 59 BGL_FORALL_VERTICES_T(v, graph1_, Graph1)
Chris@16 60 std::cout << '(' << get(vertex_index_t(), graph1_, v) << ", "
Chris@16 61 << get(vertex_index_t(), graph2_, get(f, v)) << ") ";
Chris@16 62
Chris@16 63 std::cout << std::endl;
Chris@16 64
Chris@16 65 return true;
Chris@16 66 }
Chris@16 67
Chris@16 68 private:
Chris@16 69 const Graph1& graph1_;
Chris@16 70 const Graph2& graph2_;
Chris@16 71 };
Chris@16 72
Chris@16 73 namespace detail {
Chris@16 74
Chris@16 75 // State associated with a single graph (graph_this)
Chris@16 76 template<typename GraphThis,
Chris@16 77 typename GraphOther,
Chris@16 78 typename IndexMapThis,
Chris@16 79 typename IndexMapOther>
Chris@16 80 class base_state {
Chris@16 81
Chris@16 82 typedef typename graph_traits<GraphThis>::vertex_descriptor vertex_this_type;
Chris@16 83 typedef typename graph_traits<GraphOther>::vertex_descriptor vertex_other_type;
Chris@16 84
Chris@16 85 typedef typename graph_traits<GraphThis>::vertices_size_type size_type;
Chris@16 86
Chris@16 87 const GraphThis& graph_this_;
Chris@16 88 const GraphOther& graph_other_;
Chris@16 89
Chris@16 90 IndexMapThis index_map_this_;
Chris@16 91 IndexMapOther index_map_other_;
Chris@16 92
Chris@16 93 std::vector<vertex_other_type> core_vec_;
Chris@16 94 typedef iterator_property_map<typename std::vector<vertex_other_type>::iterator,
Chris@16 95 IndexMapThis, vertex_other_type,
Chris@16 96 vertex_other_type&> core_map_type;
Chris@16 97 core_map_type core_;
Chris@16 98
Chris@16 99 std::vector<size_type> in_vec_, out_vec_;
Chris@16 100 typedef iterator_property_map<typename std::vector<size_type>::iterator,
Chris@16 101 IndexMapThis, size_type, size_type&> in_out_map_type;
Chris@16 102 in_out_map_type in_, out_;
Chris@16 103
Chris@16 104 size_type term_in_count_, term_out_count_, term_both_count_, core_count_;
Chris@16 105
Chris@16 106 // Forbidden
Chris@16 107 base_state(const base_state&);
Chris@16 108 base_state& operator=(const base_state&);
Chris@16 109
Chris@16 110 public:
Chris@16 111
Chris@16 112 base_state(const GraphThis& graph_this, const GraphOther& graph_other,
Chris@16 113 IndexMapThis index_map_this, IndexMapOther index_map_other)
Chris@16 114 : graph_this_(graph_this), graph_other_(graph_other),
Chris@16 115 index_map_this_(index_map_this), index_map_other_(index_map_other),
Chris@16 116 term_in_count_(0), term_out_count_(0), term_both_count_(0), core_count_(0) {
Chris@16 117
Chris@16 118 core_vec_.resize(num_vertices(graph_this_), graph_traits<GraphOther>::null_vertex());
Chris@16 119 core_ = make_iterator_property_map(core_vec_.begin(), index_map_this_);
Chris@16 120
Chris@16 121 in_vec_.resize(num_vertices(graph_this_), 0);
Chris@16 122 in_ = make_iterator_property_map(in_vec_.begin(), index_map_this_);
Chris@16 123
Chris@16 124 out_vec_.resize(num_vertices(graph_this_), 0);
Chris@16 125 out_ = make_iterator_property_map(out_vec_.begin(), index_map_this_);
Chris@16 126 }
Chris@16 127
Chris@16 128 // Adds a vertex pair to the state of graph graph_this
Chris@16 129 void push(const vertex_this_type& v_this, const vertex_other_type& v_other) {
Chris@16 130
Chris@16 131 ++core_count_;
Chris@16 132
Chris@16 133 put(core_, v_this, v_other);
Chris@16 134
Chris@16 135 if (!get(in_, v_this)) {
Chris@16 136 put(in_, v_this, core_count_);
Chris@16 137 ++term_in_count_;
Chris@16 138 if (get(out_, v_this))
Chris@16 139 ++term_both_count_;
Chris@16 140 }
Chris@16 141
Chris@16 142 if (!get(out_, v_this)) {
Chris@16 143 put(out_, v_this, core_count_);
Chris@16 144 ++term_out_count_;
Chris@16 145 if (get(in_, v_this))
Chris@16 146 ++term_both_count_;
Chris@16 147 }
Chris@16 148
Chris@16 149 BGL_FORALL_INEDGES_T(v_this, e, graph_this_, GraphThis) {
Chris@16 150 vertex_this_type w = source(e, graph_this_);
Chris@16 151 if (!get(in_, w)) {
Chris@16 152 put(in_, w, core_count_);
Chris@16 153 ++term_in_count_;
Chris@16 154 if (get(out_, w))
Chris@16 155 ++term_both_count_;
Chris@16 156 }
Chris@16 157 }
Chris@16 158
Chris@16 159 BGL_FORALL_OUTEDGES_T(v_this, e, graph_this_, GraphThis) {
Chris@16 160 vertex_this_type w = target(e, graph_this_);
Chris@16 161 if (!get(out_, w)) {
Chris@16 162 put(out_, w, core_count_);
Chris@16 163 ++term_out_count_;
Chris@16 164 if (get(in_, w))
Chris@16 165 ++term_both_count_;
Chris@16 166 }
Chris@16 167 }
Chris@16 168
Chris@16 169 }
Chris@16 170
Chris@16 171 // Removes vertex pair from state of graph_this
Chris@16 172 void pop(const vertex_this_type& v_this, const vertex_other_type&) {
Chris@16 173
Chris@16 174 if (!core_count_) return;
Chris@16 175
Chris@16 176 if (get(in_, v_this) == core_count_) {
Chris@16 177 put(in_, v_this, 0);
Chris@16 178 --term_in_count_;
Chris@16 179 if (get(out_, v_this))
Chris@16 180 --term_both_count_;
Chris@16 181 }
Chris@16 182
Chris@16 183 BGL_FORALL_INEDGES_T(v_this, e, graph_this_, GraphThis) {
Chris@16 184 vertex_this_type w = source(e, graph_this_);
Chris@16 185 if (get(in_, w) == core_count_) {
Chris@16 186 put(in_, w, 0);
Chris@16 187 --term_in_count_;
Chris@16 188 if (get(out_, w))
Chris@16 189 --term_both_count_;
Chris@16 190 }
Chris@16 191 }
Chris@16 192
Chris@16 193 if (get(out_, v_this) == core_count_) {
Chris@16 194 put(out_, v_this, 0);
Chris@16 195 --term_out_count_;
Chris@16 196 if (get(in_, v_this))
Chris@16 197 --term_both_count_;
Chris@16 198 }
Chris@16 199
Chris@16 200 BGL_FORALL_OUTEDGES_T(v_this, e, graph_this_, GraphThis) {
Chris@16 201 vertex_this_type w = target(e, graph_this_);
Chris@16 202 if (get(out_, w) == core_count_) {
Chris@16 203 put(out_, w, 0);
Chris@16 204 --term_out_count_;
Chris@16 205 if (get(in_, w))
Chris@16 206 --term_both_count_;
Chris@16 207 }
Chris@16 208 }
Chris@16 209 put(core_, v_this, graph_traits<GraphOther>::null_vertex());
Chris@16 210
Chris@16 211 --core_count_;
Chris@16 212
Chris@16 213 }
Chris@16 214
Chris@16 215 // Returns true if the in-terminal set is not empty
Chris@16 216 bool term_in() const {
Chris@16 217 return core_count_ < term_in_count_ ;
Chris@16 218 }
Chris@16 219
Chris@16 220 // Returns true if vertex belongs to the in-terminal set
Chris@16 221 bool term_in(const vertex_this_type& v) const {
Chris@16 222 return (get(in_, v) > 0) &&
Chris@16 223 (get(core_, v) == graph_traits<GraphOther>::null_vertex());
Chris@16 224 }
Chris@16 225
Chris@16 226 // Returns true if the out-terminal set is not empty
Chris@16 227 bool term_out() const {
Chris@16 228 return core_count_ < term_out_count_;
Chris@16 229 }
Chris@16 230
Chris@16 231 // Returns true if vertex belongs to the out-terminal set
Chris@16 232 bool term_out(const vertex_this_type& v) const {
Chris@16 233 return (get(out_, v) > 0) &&
Chris@16 234 (get(core_, v) == graph_traits<GraphOther>::null_vertex());
Chris@16 235 }
Chris@16 236
Chris@16 237 // Returns true of both (in- and out-terminal) sets are not empty
Chris@16 238 bool term_both() const {
Chris@16 239 return core_count_ < term_both_count_;
Chris@16 240 }
Chris@16 241
Chris@16 242 // Returns true if vertex belongs to both (in- and out-terminal) sets
Chris@16 243 bool term_both(const vertex_this_type& v) const {
Chris@16 244 return (get(in_, v) > 0) && (get(out_, v) > 0) &&
Chris@16 245 (get(core_, v) == graph_traits<GraphOther>::null_vertex());
Chris@16 246 }
Chris@16 247
Chris@16 248 // Returns true if vertex belongs to the core map, i.e. it is in the
Chris@16 249 // present mapping
Chris@16 250 bool in_core(const vertex_this_type& v) const {
Chris@16 251 return get(core_, v) != graph_traits<GraphOther>::null_vertex();
Chris@16 252 }
Chris@16 253
Chris@16 254 // Returns the number of vertices in the mapping
Chris@16 255 size_type count() const {
Chris@16 256 return core_count_;
Chris@16 257 }
Chris@16 258
Chris@16 259 // Returns the image (in graph_other) of vertex v (in graph_this)
Chris@16 260 vertex_other_type core(const vertex_this_type& v) const {
Chris@16 261 return get(core_, v);
Chris@16 262 }
Chris@16 263
Chris@16 264 // Returns the mapping
Chris@16 265 core_map_type get_map() const {
Chris@16 266 return core_;
Chris@16 267 }
Chris@16 268
Chris@16 269 // Returns the "time" (or depth) when vertex was added to the in-terminal set
Chris@16 270 size_type in_depth(const vertex_this_type& v) const {
Chris@16 271 return get(in_, v);
Chris@16 272 }
Chris@16 273
Chris@16 274 // Returns the "time" (or depth) when vertex was added to the out-terminal set
Chris@16 275 size_type out_depth(const vertex_this_type& v) const {
Chris@16 276 return get(out_, v);
Chris@16 277 }
Chris@16 278
Chris@16 279 // Returns the terminal set counts
Chris@16 280 boost::tuple<size_type, size_type, size_type>
Chris@16 281 term_set() const {
Chris@16 282 return boost::make_tuple(term_in_count_, term_out_count_,
Chris@16 283 term_both_count_);
Chris@16 284 }
Chris@16 285
Chris@16 286 };
Chris@16 287
Chris@16 288
Chris@16 289 // Function object that checks whether a valid edge
Chris@16 290 // exists. For multi-graphs matched edges are excluded
Chris@16 291 template <typename Graph, typename Enable = void>
Chris@16 292 struct equivalent_edge_exists {
Chris@16 293 typedef typename boost::graph_traits<Graph>::edge_descriptor edge_type;
Chris@16 294
Chris@16 295 BOOST_CONCEPT_ASSERT(( LessThanComparable<edge_type> ));
Chris@16 296
Chris@16 297 template<typename EdgePredicate>
Chris@16 298 bool operator()(typename graph_traits<Graph>::vertex_descriptor s,
Chris@16 299 typename graph_traits<Graph>::vertex_descriptor t,
Chris@16 300 EdgePredicate is_valid_edge, const Graph& g) {
Chris@16 301
Chris@16 302 BGL_FORALL_OUTEDGES_T(s, e, g, Graph) {
Chris@16 303 if ((target(e, g) == t) && is_valid_edge(e) &&
Chris@16 304 (matched_edges_.find(e) == matched_edges_.end())) {
Chris@16 305 matched_edges_.insert(e);
Chris@16 306 return true;
Chris@16 307 }
Chris@16 308 }
Chris@16 309
Chris@16 310 return false;
Chris@16 311 }
Chris@16 312
Chris@16 313 private:
Chris@16 314
Chris@16 315 std::set<edge_type> matched_edges_;
Chris@16 316 };
Chris@16 317
Chris@16 318 template <typename Graph>
Chris@16 319 struct equivalent_edge_exists<Graph, typename boost::disable_if<is_multigraph<Graph> >::type> {
Chris@16 320 template<typename EdgePredicate>
Chris@16 321 bool operator()(typename graph_traits<Graph>::vertex_descriptor s,
Chris@16 322 typename graph_traits<Graph>::vertex_descriptor t,
Chris@16 323 EdgePredicate is_valid_edge, const Graph& g) {
Chris@16 324
Chris@16 325 typename graph_traits<Graph>::edge_descriptor e;
Chris@16 326 bool found;
Chris@16 327 boost::tie(e, found) = edge(s, t, g);
Chris@16 328 if (!found)
Chris@16 329 return false;
Chris@16 330 else if (is_valid_edge(e))
Chris@16 331 return true;
Chris@16 332
Chris@16 333 return false;
Chris@16 334 }
Chris@16 335
Chris@16 336 };
Chris@16 337
Chris@16 338
Chris@16 339 // Generates a predicate for edge e1 given a binary predicate and a
Chris@16 340 // fixed edge e2
Chris@16 341 template <typename Graph1,
Chris@16 342 typename Graph2,
Chris@16 343 typename EdgeEquivalencePredicate>
Chris@16 344 struct edge1_predicate {
Chris@16 345
Chris@16 346 edge1_predicate(EdgeEquivalencePredicate edge_comp,
Chris@16 347 typename graph_traits<Graph2>::edge_descriptor e2)
Chris@16 348 : edge_comp_(edge_comp), e2_(e2) {}
Chris@16 349
Chris@16 350 bool operator()(typename graph_traits<Graph1>::edge_descriptor e1) {
Chris@16 351 return edge_comp_(e1, e2_);
Chris@16 352 }
Chris@16 353
Chris@16 354 EdgeEquivalencePredicate edge_comp_;
Chris@16 355 typename graph_traits<Graph2>::edge_descriptor e2_;
Chris@16 356 };
Chris@16 357
Chris@16 358
Chris@16 359 // Generates a predicate for edge e2 given given a binary predicate and a
Chris@16 360 // fixed edge e1
Chris@16 361 template <typename Graph1,
Chris@16 362 typename Graph2,
Chris@16 363 typename EdgeEquivalencePredicate>
Chris@16 364 struct edge2_predicate {
Chris@16 365
Chris@16 366 edge2_predicate(EdgeEquivalencePredicate edge_comp,
Chris@16 367 typename graph_traits<Graph1>::edge_descriptor e1)
Chris@16 368 : edge_comp_(edge_comp), e1_(e1) {}
Chris@16 369
Chris@16 370 bool operator()(typename graph_traits<Graph2>::edge_descriptor e2) {
Chris@16 371 return edge_comp_(e1_, e2);
Chris@16 372 }
Chris@16 373
Chris@16 374 EdgeEquivalencePredicate edge_comp_;
Chris@16 375 typename graph_traits<Graph1>::edge_descriptor e1_;
Chris@16 376 };
Chris@16 377
Chris@16 378
Chris@16 379 enum problem_selector {subgraph_mono, subgraph_iso, isomorphism };
Chris@16 380
Chris@16 381 // The actual state associated with both graphs
Chris@16 382 template<typename Graph1,
Chris@16 383 typename Graph2,
Chris@16 384 typename IndexMap1,
Chris@16 385 typename IndexMap2,
Chris@16 386 typename EdgeEquivalencePredicate,
Chris@16 387 typename VertexEquivalencePredicate,
Chris@16 388 typename SubGraphIsoMapCallback,
Chris@16 389 problem_selector problem_selection>
Chris@16 390 class state {
Chris@16 391
Chris@16 392 typedef typename graph_traits<Graph1>::vertex_descriptor vertex1_type;
Chris@16 393 typedef typename graph_traits<Graph2>::vertex_descriptor vertex2_type;
Chris@16 394
Chris@16 395 typedef typename graph_traits<Graph1>::edge_descriptor edge1_type;
Chris@16 396 typedef typename graph_traits<Graph2>::edge_descriptor edge2_type;
Chris@16 397
Chris@16 398 typedef typename graph_traits<Graph1>::vertices_size_type graph1_size_type;
Chris@16 399 typedef typename graph_traits<Graph2>::vertices_size_type graph2_size_type;
Chris@16 400
Chris@16 401 const Graph1& graph1_;
Chris@16 402 const Graph2& graph2_;
Chris@16 403
Chris@16 404 IndexMap1 index_map1_;
Chris@16 405
Chris@16 406 EdgeEquivalencePredicate edge_comp_;
Chris@16 407 VertexEquivalencePredicate vertex_comp_;
Chris@16 408
Chris@16 409 base_state<Graph1, Graph2, IndexMap1, IndexMap2> state1_;
Chris@16 410 base_state<Graph2, Graph1, IndexMap2, IndexMap1> state2_;
Chris@16 411
Chris@16 412 // Three helper functions used in Feasibility and Valid functions to test
Chris@16 413 // terminal set counts when testing for:
Chris@16 414 // - graph sub-graph monomorphism, or
Chris@16 415 inline bool comp_term_sets(graph1_size_type a,
Chris@16 416 graph2_size_type b,
Chris@16 417 boost::mpl::int_<subgraph_mono>) const {
Chris@16 418 return a <= b;
Chris@16 419 }
Chris@16 420
Chris@16 421 // - graph sub-graph isomorphism, or
Chris@16 422 inline bool comp_term_sets(graph1_size_type a,
Chris@16 423 graph2_size_type b,
Chris@16 424 boost::mpl::int_<subgraph_iso>) const {
Chris@16 425 return a <= b;
Chris@16 426 }
Chris@16 427
Chris@16 428 // - graph isomorphism
Chris@16 429 inline bool comp_term_sets(graph1_size_type a,
Chris@16 430 graph2_size_type b,
Chris@16 431 boost::mpl::int_<isomorphism>) const {
Chris@16 432 return a == b;
Chris@16 433 }
Chris@16 434
Chris@16 435 // Forbidden
Chris@16 436 state(const state&);
Chris@16 437 state& operator=(const state&);
Chris@16 438
Chris@16 439 public:
Chris@16 440
Chris@16 441 state(const Graph1& graph1, const Graph2& graph2,
Chris@16 442 IndexMap1 index_map1, IndexMap2 index_map2,
Chris@16 443 EdgeEquivalencePredicate edge_comp,
Chris@16 444 VertexEquivalencePredicate vertex_comp)
Chris@16 445 : graph1_(graph1), graph2_(graph2),
Chris@16 446 index_map1_(index_map1),
Chris@16 447 edge_comp_(edge_comp), vertex_comp_(vertex_comp),
Chris@16 448 state1_(graph1, graph2, index_map1, index_map2),
Chris@16 449 state2_(graph2, graph1, index_map2, index_map1) {}
Chris@16 450
Chris@16 451 // Add vertex pair to the state
Chris@16 452 void push(const vertex1_type& v, const vertex2_type& w) {
Chris@16 453 state1_.push(v, w);
Chris@16 454 state2_.push(w, v);
Chris@16 455 }
Chris@16 456
Chris@16 457 // Remove vertex pair from state
Chris@16 458 void pop(const vertex1_type& v, const vertex2_type&) {
Chris@16 459 vertex2_type w = state1_.core(v);
Chris@16 460 state1_.pop(v, w);
Chris@16 461 state2_.pop(w, v);
Chris@16 462 }
Chris@16 463
Chris@16 464 // Checks the feasibility of a new vertex pair
Chris@16 465 bool feasible(const vertex1_type& v_new, const vertex2_type& w_new) {
Chris@16 466
Chris@16 467 if (!vertex_comp_(v_new, w_new)) return false;
Chris@16 468
Chris@16 469 // graph1
Chris@16 470 graph1_size_type term_in1_count = 0, term_out1_count = 0, rest1_count = 0;
Chris@16 471
Chris@16 472 {
Chris@16 473 equivalent_edge_exists<Graph2> edge2_exists;
Chris@16 474
Chris@16 475 BGL_FORALL_INEDGES_T(v_new, e1, graph1_, Graph1) {
Chris@16 476 vertex1_type v = source(e1, graph1_);
Chris@16 477
Chris@16 478 if (state1_.in_core(v) || (v == v_new)) {
Chris@16 479 vertex2_type w = w_new;
Chris@16 480 if (v != v_new)
Chris@16 481 w = state1_.core(v);
Chris@16 482 if (!edge2_exists(w, w_new,
Chris@16 483 edge2_predicate<Graph1, Graph2, EdgeEquivalencePredicate>(edge_comp_, e1),
Chris@16 484 graph2_))
Chris@16 485 return false;
Chris@16 486
Chris@16 487 } else {
Chris@16 488 if (0 < state1_.in_depth(v))
Chris@16 489 ++term_in1_count;
Chris@16 490 if (0 < state1_.out_depth(v))
Chris@16 491 ++term_out1_count;
Chris@16 492 if ((state1_.in_depth(v) == 0) && (state1_.out_depth(v) == 0))
Chris@16 493 ++rest1_count;
Chris@16 494 }
Chris@16 495 }
Chris@16 496 }
Chris@16 497
Chris@16 498 {
Chris@16 499 equivalent_edge_exists<Graph2> edge2_exists;
Chris@16 500
Chris@16 501 BGL_FORALL_OUTEDGES_T(v_new, e1, graph1_, Graph1) {
Chris@16 502 vertex1_type v = target(e1, graph1_);
Chris@16 503 if (state1_.in_core(v) || (v == v_new)) {
Chris@16 504 vertex2_type w = w_new;
Chris@16 505 if (v != v_new)
Chris@16 506 w = state1_.core(v);
Chris@16 507
Chris@16 508 if (!edge2_exists(w_new, w,
Chris@16 509 edge2_predicate<Graph1, Graph2, EdgeEquivalencePredicate>(edge_comp_, e1),
Chris@16 510 graph2_))
Chris@16 511 return false;
Chris@16 512
Chris@16 513 } else {
Chris@16 514 if (0 < state1_.in_depth(v))
Chris@16 515 ++term_in1_count;
Chris@16 516 if (0 < state1_.out_depth(v))
Chris@16 517 ++term_out1_count;
Chris@16 518 if ((state1_.in_depth(v) == 0) && (state1_.out_depth(v) == 0))
Chris@16 519 ++rest1_count;
Chris@16 520 }
Chris@16 521 }
Chris@16 522 }
Chris@16 523
Chris@16 524 // graph2
Chris@16 525 graph2_size_type term_out2_count = 0, term_in2_count = 0, rest2_count = 0;
Chris@16 526
Chris@16 527 {
Chris@16 528 equivalent_edge_exists<Graph1> edge1_exists;
Chris@16 529
Chris@16 530 BGL_FORALL_INEDGES_T(w_new, e2, graph2_, Graph2) {
Chris@16 531 vertex2_type w = source(e2, graph2_);
Chris@16 532 if (state2_.in_core(w) || (w == w_new)) {
Chris@16 533 if (problem_selection != subgraph_mono) {
Chris@16 534 vertex1_type v = v_new;
Chris@16 535 if (w != w_new)
Chris@16 536 v = state2_.core(w);
Chris@16 537
Chris@16 538 if (!edge1_exists(v, v_new,
Chris@16 539 edge1_predicate<Graph1, Graph2, EdgeEquivalencePredicate>(edge_comp_, e2),
Chris@16 540 graph1_))
Chris@16 541 return false;
Chris@16 542 }
Chris@16 543 } else {
Chris@16 544 if (0 < state2_.in_depth(w))
Chris@16 545 ++term_in2_count;
Chris@16 546 if (0 < state2_.out_depth(w))
Chris@16 547 ++term_out2_count;
Chris@16 548 if ((state2_.in_depth(w) == 0) && (state2_.out_depth(w) == 0))
Chris@16 549 ++rest2_count;
Chris@16 550 }
Chris@16 551 }
Chris@16 552 }
Chris@16 553
Chris@16 554 {
Chris@16 555 equivalent_edge_exists<Graph1> edge1_exists;
Chris@16 556
Chris@16 557 BGL_FORALL_OUTEDGES_T(w_new, e2, graph2_, Graph2) {
Chris@16 558 vertex2_type w = target(e2, graph2_);
Chris@16 559 if (state2_.in_core(w) || (w == w_new)) {
Chris@16 560 if (problem_selection != subgraph_mono) {
Chris@16 561 vertex1_type v = v_new;
Chris@16 562 if (w != w_new)
Chris@16 563 v = state2_.core(w);
Chris@16 564
Chris@16 565 if (!edge1_exists(v_new, v,
Chris@16 566 edge1_predicate<Graph1, Graph2, EdgeEquivalencePredicate>(edge_comp_, e2),
Chris@16 567 graph1_))
Chris@16 568 return false;
Chris@16 569 }
Chris@16 570 } else {
Chris@16 571 if (0 < state2_.in_depth(w))
Chris@16 572 ++term_in2_count;
Chris@16 573 if (0 < state2_.out_depth(w))
Chris@16 574 ++term_out2_count;
Chris@16 575 if ((state2_.in_depth(w) == 0) && (state2_.out_depth(w) == 0))
Chris@16 576 ++rest2_count;
Chris@16 577 }
Chris@16 578 }
Chris@16 579 }
Chris@16 580
Chris@16 581 if (problem_selection != subgraph_mono) { // subgraph_iso and isomorphism
Chris@16 582 return comp_term_sets(term_in1_count, term_in2_count,
Chris@16 583 boost::mpl::int_<problem_selection>()) &&
Chris@16 584 comp_term_sets(term_out1_count, term_out2_count,
Chris@16 585 boost::mpl::int_<problem_selection>()) &&
Chris@16 586 comp_term_sets(rest1_count, rest2_count,
Chris@16 587 boost::mpl::int_<problem_selection>());
Chris@16 588 } else { // subgraph_mono
Chris@16 589 return comp_term_sets(term_in1_count, term_in2_count,
Chris@16 590 boost::mpl::int_<problem_selection>()) &&
Chris@16 591 comp_term_sets(term_out1_count, term_out2_count,
Chris@16 592 boost::mpl::int_<problem_selection>()) &&
Chris@16 593 comp_term_sets(term_in1_count + term_out1_count + rest1_count,
Chris@16 594 term_in2_count + term_out2_count + rest2_count,
Chris@16 595 boost::mpl::int_<problem_selection>());
Chris@16 596 }
Chris@16 597 }
Chris@16 598
Chris@16 599 // Returns true if vertex v in graph1 is a possible candidate to
Chris@16 600 // be added to the current state
Chris@16 601 bool possible_candidate1(const vertex1_type& v) const {
Chris@16 602 if (state1_.term_both() && state2_.term_both())
Chris@16 603 return state1_.term_both(v);
Chris@16 604 else if (state1_.term_out() && state2_.term_out())
Chris@16 605 return state1_.term_out(v);
Chris@16 606 else if (state1_.term_in() && state2_.term_in())
Chris@16 607 return state1_.term_in(v);
Chris@16 608 else
Chris@16 609 return !state1_.in_core(v);
Chris@16 610 }
Chris@16 611
Chris@16 612 // Returns true if vertex w in graph2 is a possible candidate to
Chris@16 613 // be added to the current state
Chris@16 614 bool possible_candidate2(const vertex2_type& w) const {
Chris@16 615 if (state1_.term_both() && state2_.term_both())
Chris@16 616 return state2_.term_both(w);
Chris@16 617 else if (state1_.term_out() && state2_.term_out())
Chris@16 618 return state2_.term_out(w);
Chris@16 619 else if (state1_.term_in() && state2_.term_in())
Chris@16 620 return state2_.term_in(w);
Chris@16 621 else
Chris@16 622 return !state2_.in_core(w);
Chris@16 623 }
Chris@16 624
Chris@16 625 // Returns true if a mapping was found
Chris@16 626 bool success() const {
Chris@16 627 return state1_.count() == num_vertices(graph1_);
Chris@16 628 }
Chris@16 629
Chris@16 630 // Returns true if a state is valid
Chris@16 631 bool valid() const {
Chris@16 632 boost::tuple<graph1_size_type, graph1_size_type, graph1_size_type> term1;
Chris@16 633 boost::tuple<graph2_size_type, graph2_size_type, graph2_size_type> term2;
Chris@16 634
Chris@16 635 term1 = state1_.term_set();
Chris@16 636 term2 = state2_.term_set();
Chris@16 637
Chris@16 638 return comp_term_sets(boost::get<0>(term1), boost::get<0>(term2),
Chris@16 639 boost::mpl::int_<problem_selection>()) &&
Chris@16 640 comp_term_sets(boost::get<1>(term1), boost::get<1>(term2),
Chris@16 641 boost::mpl::int_<problem_selection>()) &&
Chris@16 642 comp_term_sets(boost::get<2>(term1), boost::get<2>(term2),
Chris@16 643 boost::mpl::int_<problem_selection>());
Chris@16 644 }
Chris@16 645
Chris@16 646 // Calls the user_callback with a graph (sub)graph mapping
Chris@16 647 bool call_back(SubGraphIsoMapCallback user_callback) const {
Chris@16 648 return user_callback(state1_.get_map(), state2_.get_map());
Chris@16 649 }
Chris@16 650
Chris@16 651 };
Chris@16 652
Chris@16 653
Chris@16 654 // Data structure to keep info used for back tracking during
Chris@16 655 // matching process
Chris@16 656 template<typename Graph1,
Chris@16 657 typename Graph2,
Chris@16 658 typename VertexOrder1>
Chris@16 659 struct vf2_match_continuation {
Chris@16 660 typename VertexOrder1::const_iterator graph1_verts_iter;
Chris@16 661 typename graph_traits<Graph2>::vertex_iterator graph2_verts_iter;
Chris@16 662 };
Chris@16 663
Chris@16 664 // Non-recursive method that explores state space using a depth-first
Chris@16 665 // search strategy. At each depth possible pairs candidate are compute
Chris@16 666 // and tested for feasibility to extend the mapping. If a complete
Chris@16 667 // mapping is found, the mapping is output to user_callback in the form
Chris@16 668 // of a correspondence map (graph1 to graph2). Returning false from the
Chris@16 669 // user_callback will terminate the search. Function match will return
Chris@16 670 // true if the entire search space was explored.
Chris@16 671 template<typename Graph1,
Chris@16 672 typename Graph2,
Chris@16 673 typename IndexMap1,
Chris@16 674 typename IndexMap2,
Chris@16 675 typename VertexOrder1,
Chris@16 676 typename EdgeEquivalencePredicate,
Chris@16 677 typename VertexEquivalencePredicate,
Chris@16 678 typename SubGraphIsoMapCallback,
Chris@16 679 problem_selector problem_selection>
Chris@16 680 bool match(const Graph1& graph1, const Graph2& graph2,
Chris@16 681 SubGraphIsoMapCallback user_callback, const VertexOrder1& vertex_order1,
Chris@16 682 state<Graph1, Graph2, IndexMap1, IndexMap2,
Chris@16 683 EdgeEquivalencePredicate, VertexEquivalencePredicate,
Chris@16 684 SubGraphIsoMapCallback, problem_selection>& s) {
Chris@16 685
Chris@16 686 typename VertexOrder1::const_iterator graph1_verts_iter;
Chris@16 687
Chris@16 688 typedef typename graph_traits<Graph2>::vertex_iterator vertex2_iterator_type;
Chris@16 689 vertex2_iterator_type graph2_verts_iter, graph2_verts_iter_end;
Chris@16 690
Chris@16 691 typedef vf2_match_continuation<Graph1, Graph2, VertexOrder1> match_continuation_type;
Chris@16 692 std::vector<match_continuation_type> k;
Chris@101 693 bool found_match = false;
Chris@16 694
Chris@16 695 recur:
Chris@16 696 if (s.success()) {
Chris@16 697 if (!s.call_back(user_callback))
Chris@101 698 return true;
Chris@101 699 found_match = true;
Chris@16 700
Chris@16 701 goto back_track;
Chris@16 702 }
Chris@16 703
Chris@16 704 if (!s.valid())
Chris@16 705 goto back_track;
Chris@16 706
Chris@16 707 graph1_verts_iter = vertex_order1.begin();
Chris@16 708 while (graph1_verts_iter != vertex_order1.end() &&
Chris@16 709 !s.possible_candidate1(*graph1_verts_iter)) {
Chris@16 710 ++graph1_verts_iter;
Chris@16 711 }
Chris@16 712
Chris@16 713 boost::tie(graph2_verts_iter, graph2_verts_iter_end) = vertices(graph2);
Chris@16 714 while (graph2_verts_iter != graph2_verts_iter_end) {
Chris@16 715 if (s.possible_candidate2(*graph2_verts_iter)) {
Chris@16 716 if (s.feasible(*graph1_verts_iter, *graph2_verts_iter)) {
Chris@16 717 match_continuation_type kk;
Chris@16 718 kk.graph1_verts_iter = graph1_verts_iter;
Chris@16 719 kk.graph2_verts_iter = graph2_verts_iter;
Chris@16 720 k.push_back(kk);
Chris@16 721
Chris@16 722 s.push(*graph1_verts_iter, *graph2_verts_iter);
Chris@16 723 goto recur;
Chris@16 724 }
Chris@16 725 }
Chris@16 726 graph2_loop: ++graph2_verts_iter;
Chris@16 727 }
Chris@16 728
Chris@16 729 back_track:
Chris@16 730 if (k.empty())
Chris@101 731 return found_match;
Chris@16 732
Chris@16 733 const match_continuation_type kk = k.back();
Chris@16 734 graph1_verts_iter = kk.graph1_verts_iter;
Chris@16 735 graph2_verts_iter = kk.graph2_verts_iter;
Chris@16 736 k.pop_back();
Chris@16 737
Chris@16 738 s.pop(*graph1_verts_iter, *graph2_verts_iter);
Chris@16 739
Chris@16 740 goto graph2_loop;
Chris@16 741 }
Chris@16 742
Chris@16 743
Chris@16 744 // Used to sort nodes by in/out degrees
Chris@16 745 template<typename Graph>
Chris@16 746 struct vertex_in_out_degree_cmp {
Chris@16 747 typedef typename graph_traits<Graph>::vertex_descriptor vertex_type;
Chris@16 748
Chris@16 749 vertex_in_out_degree_cmp(const Graph& graph)
Chris@16 750 : graph_(graph) {}
Chris@16 751
Chris@16 752 bool operator()(const vertex_type& v, const vertex_type& w) const {
Chris@16 753 // lexicographical comparison
Chris@16 754 return std::make_pair(in_degree(v, graph_), out_degree(v, graph_)) <
Chris@16 755 std::make_pair(in_degree(w, graph_), out_degree(w, graph_));
Chris@16 756 }
Chris@16 757
Chris@16 758 const Graph& graph_;
Chris@16 759 };
Chris@16 760
Chris@16 761
Chris@16 762 // Used to sort nodes by multiplicity of in/out degrees
Chris@16 763 template<typename Graph,
Chris@16 764 typename FrequencyMap>
Chris@16 765 struct vertex_frequency_degree_cmp {
Chris@16 766 typedef typename graph_traits<Graph>::vertex_descriptor vertex_type;
Chris@16 767
Chris@16 768 vertex_frequency_degree_cmp(const Graph& graph, FrequencyMap freq)
Chris@16 769 : graph_(graph), freq_(freq) {}
Chris@16 770
Chris@16 771 bool operator()(const vertex_type& v, const vertex_type& w) const {
Chris@16 772 // lexicographical comparison
Chris@16 773 return std::make_pair(freq_[v], in_degree(v, graph_)+out_degree(v, graph_)) <
Chris@16 774 std::make_pair(freq_[w], in_degree(w, graph_)+out_degree(w, graph_));
Chris@16 775 }
Chris@16 776
Chris@16 777 const Graph& graph_;
Chris@16 778 FrequencyMap freq_;
Chris@16 779 };
Chris@16 780
Chris@16 781
Chris@16 782 // Sorts vertices of a graph by multiplicity of in/out degrees
Chris@16 783 template<typename Graph,
Chris@16 784 typename IndexMap,
Chris@16 785 typename VertexOrder>
Chris@16 786 void sort_vertices(const Graph& graph, IndexMap index_map, VertexOrder& order) {
Chris@16 787 typedef typename graph_traits<Graph>::vertices_size_type size_type;
Chris@16 788
Chris@16 789 boost::range::sort(order, vertex_in_out_degree_cmp<Graph>(graph));
Chris@16 790
Chris@16 791 std::vector<size_type> freq_vec(num_vertices(graph), 0);
Chris@16 792 typedef iterator_property_map<typename std::vector<size_type>::iterator,
Chris@16 793 IndexMap, size_type, size_type&> frequency_map_type;
Chris@16 794
Chris@16 795 frequency_map_type freq = make_iterator_property_map(freq_vec.begin(), index_map);
Chris@16 796
Chris@16 797 typedef typename VertexOrder::iterator order_iterator;
Chris@16 798
Chris@16 799 for (order_iterator order_iter = order.begin(); order_iter != order.end(); ) {
Chris@16 800 size_type count = 0;
Chris@16 801 for (order_iterator count_iter = order_iter;
Chris@16 802 (count_iter != order.end()) &&
Chris@16 803 (in_degree(*order_iter, graph) == in_degree(*count_iter, graph)) &&
Chris@16 804 (out_degree(*order_iter, graph) == out_degree(*count_iter, graph));
Chris@16 805 ++count_iter)
Chris@16 806 ++count;
Chris@16 807
Chris@16 808 for (size_type i = 0; i < count; ++i) {
Chris@16 809 freq[*order_iter] = count;
Chris@16 810 ++order_iter;
Chris@16 811 }
Chris@16 812 }
Chris@16 813
Chris@16 814 boost::range::sort(order, vertex_frequency_degree_cmp<Graph, frequency_map_type>(graph, freq));
Chris@16 815
Chris@16 816 }
Chris@16 817
Chris@16 818 // Enumerates all graph sub-graph mono-/iso-morphism mappings between graphs
Chris@16 819 // graph_small and graph_large. Continues until user_callback returns true or the
Chris@16 820 // search space has been fully explored.
Chris@16 821 template <problem_selector problem_selection,
Chris@16 822 typename GraphSmall,
Chris@16 823 typename GraphLarge,
Chris@16 824 typename IndexMapSmall,
Chris@16 825 typename IndexMapLarge,
Chris@16 826 typename VertexOrderSmall,
Chris@16 827 typename EdgeEquivalencePredicate,
Chris@16 828 typename VertexEquivalencePredicate,
Chris@16 829 typename SubGraphIsoMapCallback>
Chris@16 830 bool vf2_subgraph_morphism(const GraphSmall& graph_small, const GraphLarge& graph_large,
Chris@16 831 SubGraphIsoMapCallback user_callback,
Chris@16 832 IndexMapSmall index_map_small, IndexMapLarge index_map_large,
Chris@16 833 const VertexOrderSmall& vertex_order_small,
Chris@16 834 EdgeEquivalencePredicate edge_comp,
Chris@16 835 VertexEquivalencePredicate vertex_comp) {
Chris@16 836
Chris@16 837 // Graph requirements
Chris@16 838 BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept<GraphSmall> ));
Chris@16 839 BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<GraphSmall> ));
Chris@16 840 BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept<GraphSmall> ));
Chris@16 841 BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept<GraphSmall> ));
Chris@16 842
Chris@16 843 BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept<GraphLarge> ));
Chris@16 844 BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<GraphLarge> ));
Chris@16 845 BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept<GraphLarge> ));
Chris@16 846 BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept<GraphLarge> ));
Chris@16 847
Chris@16 848 typedef typename graph_traits<GraphSmall>::vertex_descriptor vertex_small_type;
Chris@16 849 typedef typename graph_traits<GraphLarge>::vertex_descriptor vertex_large_type;
Chris@16 850
Chris@16 851 typedef typename graph_traits<GraphSmall>::vertices_size_type size_type_small;
Chris@16 852 typedef typename graph_traits<GraphLarge>::vertices_size_type size_type_large;
Chris@16 853
Chris@16 854 // Property map requirements
Chris@16 855 BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<IndexMapSmall, vertex_small_type> ));
Chris@16 856 typedef typename property_traits<IndexMapSmall>::value_type IndexMapSmallValue;
Chris@16 857 BOOST_STATIC_ASSERT(( is_convertible<IndexMapSmallValue, size_type_small>::value ));
Chris@16 858
Chris@16 859 BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<IndexMapLarge, vertex_large_type> ));
Chris@16 860 typedef typename property_traits<IndexMapLarge>::value_type IndexMapLargeValue;
Chris@16 861 BOOST_STATIC_ASSERT(( is_convertible<IndexMapLargeValue, size_type_large>::value ));
Chris@16 862
Chris@16 863 // Edge & vertex requirements
Chris@16 864 typedef typename graph_traits<GraphSmall>::edge_descriptor edge_small_type;
Chris@16 865 typedef typename graph_traits<GraphLarge>::edge_descriptor edge_large_type;
Chris@16 866
Chris@16 867 BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept<EdgeEquivalencePredicate,
Chris@16 868 edge_small_type, edge_large_type> ));
Chris@16 869
Chris@16 870 BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept<VertexEquivalencePredicate,
Chris@16 871 vertex_small_type, vertex_large_type> ));
Chris@16 872
Chris@16 873 // Vertex order requirements
Chris@16 874 BOOST_CONCEPT_ASSERT(( ContainerConcept<VertexOrderSmall> ));
Chris@16 875 typedef typename VertexOrderSmall::value_type order_value_type;
Chris@16 876 BOOST_STATIC_ASSERT(( is_same<vertex_small_type, order_value_type>::value ));
Chris@16 877 BOOST_ASSERT( num_vertices(graph_small) == vertex_order_small.size() );
Chris@16 878
Chris@16 879 if (num_vertices(graph_small) > num_vertices(graph_large))
Chris@16 880 return false;
Chris@16 881
Chris@16 882 typename graph_traits<GraphSmall>::edges_size_type num_edges_small = num_edges(graph_small);
Chris@16 883 typename graph_traits<GraphLarge>::edges_size_type num_edges_large = num_edges(graph_large);
Chris@16 884
Chris@16 885 // Double the number of edges for undirected graphs: each edge counts as
Chris@16 886 // in-edge and out-edge
Chris@16 887 if (is_undirected(graph_small)) num_edges_small *= 2;
Chris@16 888 if (is_undirected(graph_large)) num_edges_large *= 2;
Chris@16 889 if (num_edges_small > num_edges_large)
Chris@16 890 return false;
Chris@16 891
Chris@16 892 detail::state<GraphSmall, GraphLarge, IndexMapSmall, IndexMapLarge,
Chris@16 893 EdgeEquivalencePredicate, VertexEquivalencePredicate,
Chris@16 894 SubGraphIsoMapCallback, problem_selection>
Chris@16 895 s(graph_small, graph_large, index_map_small, index_map_large, edge_comp, vertex_comp);
Chris@16 896
Chris@16 897 return detail::match(graph_small, graph_large, user_callback, vertex_order_small, s);
Chris@16 898 }
Chris@16 899
Chris@16 900 } // namespace detail
Chris@16 901
Chris@16 902
Chris@16 903 // Returns vertex order (vertices sorted by multiplicity of in/out degrees)
Chris@16 904 template<typename Graph>
Chris@16 905 std::vector<typename graph_traits<Graph>::vertex_descriptor>
Chris@16 906 vertex_order_by_mult(const Graph& graph) {
Chris@16 907
Chris@16 908 std::vector<typename graph_traits<Graph>::vertex_descriptor> vertex_order;
Chris@16 909 std::copy(vertices(graph).first, vertices(graph).second, std::back_inserter(vertex_order));
Chris@16 910
Chris@16 911 detail::sort_vertices(graph, get(vertex_index, graph), vertex_order);
Chris@16 912 return vertex_order;
Chris@16 913 }
Chris@16 914
Chris@16 915
Chris@16 916 // Enumerates all graph sub-graph monomorphism mappings between graphs
Chris@16 917 // graph_small and graph_large. Continues until user_callback returns true or the
Chris@16 918 // search space has been fully explored.
Chris@16 919 template <typename GraphSmall,
Chris@16 920 typename GraphLarge,
Chris@16 921 typename IndexMapSmall,
Chris@16 922 typename IndexMapLarge,
Chris@16 923 typename VertexOrderSmall,
Chris@16 924 typename EdgeEquivalencePredicate,
Chris@16 925 typename VertexEquivalencePredicate,
Chris@16 926 typename SubGraphIsoMapCallback>
Chris@16 927 bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large,
Chris@16 928 SubGraphIsoMapCallback user_callback,
Chris@16 929 IndexMapSmall index_map_small, IndexMapLarge index_map_large,
Chris@16 930 const VertexOrderSmall& vertex_order_small,
Chris@16 931 EdgeEquivalencePredicate edge_comp,
Chris@16 932 VertexEquivalencePredicate vertex_comp) {
Chris@16 933 return detail::vf2_subgraph_morphism<detail::subgraph_mono>
Chris@16 934 (graph_small, graph_large,
Chris@16 935 user_callback,
Chris@16 936 index_map_small, index_map_large,
Chris@16 937 vertex_order_small,
Chris@16 938 edge_comp,
Chris@16 939 vertex_comp);
Chris@16 940 }
Chris@16 941
Chris@16 942
Chris@16 943 // All default interface for vf2_subgraph_iso
Chris@16 944 template <typename GraphSmall,
Chris@16 945 typename GraphLarge,
Chris@16 946 typename SubGraphIsoMapCallback>
Chris@16 947 bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large,
Chris@16 948 SubGraphIsoMapCallback user_callback) {
Chris@16 949 return vf2_subgraph_mono(graph_small, graph_large, user_callback,
Chris@16 950 get(vertex_index, graph_small), get(vertex_index, graph_large),
Chris@16 951 vertex_order_by_mult(graph_small),
Chris@16 952 always_equivalent(), always_equivalent());
Chris@16 953 }
Chris@16 954
Chris@16 955
Chris@16 956 // Named parameter interface of vf2_subgraph_iso
Chris@16 957 template <typename GraphSmall,
Chris@16 958 typename GraphLarge,
Chris@16 959 typename VertexOrderSmall,
Chris@16 960 typename SubGraphIsoMapCallback,
Chris@16 961 typename Param,
Chris@16 962 typename Tag,
Chris@16 963 typename Rest>
Chris@16 964 bool vf2_subgraph_mono(const GraphSmall& graph_small, const GraphLarge& graph_large,
Chris@16 965 SubGraphIsoMapCallback user_callback,
Chris@16 966 const VertexOrderSmall& vertex_order_small,
Chris@16 967 const bgl_named_params<Param, Tag, Rest>& params) {
Chris@16 968 return vf2_subgraph_mono(graph_small, graph_large, user_callback,
Chris@16 969 choose_const_pmap(get_param(params, vertex_index1),
Chris@16 970 graph_small, vertex_index),
Chris@16 971 choose_const_pmap(get_param(params, vertex_index2),
Chris@16 972 graph_large, vertex_index),
Chris@16 973 vertex_order_small,
Chris@16 974 choose_param(get_param(params, edges_equivalent_t()),
Chris@16 975 always_equivalent()),
Chris@16 976 choose_param(get_param(params, vertices_equivalent_t()),
Chris@16 977 always_equivalent())
Chris@16 978 );
Chris@16 979 }
Chris@16 980
Chris@16 981
Chris@16 982 // Enumerates all graph sub-graph isomorphism mappings between graphs
Chris@16 983 // graph_small and graph_large. Continues until user_callback returns true or the
Chris@16 984 // search space has been fully explored.
Chris@16 985 template <typename GraphSmall,
Chris@16 986 typename GraphLarge,
Chris@16 987 typename IndexMapSmall,
Chris@16 988 typename IndexMapLarge,
Chris@16 989 typename VertexOrderSmall,
Chris@16 990 typename EdgeEquivalencePredicate,
Chris@16 991 typename VertexEquivalencePredicate,
Chris@16 992 typename SubGraphIsoMapCallback>
Chris@16 993 bool vf2_subgraph_iso(const GraphSmall& graph_small, const GraphLarge& graph_large,
Chris@16 994 SubGraphIsoMapCallback user_callback,
Chris@16 995 IndexMapSmall index_map_small, IndexMapLarge index_map_large,
Chris@16 996 const VertexOrderSmall& vertex_order_small,
Chris@16 997 EdgeEquivalencePredicate edge_comp,
Chris@16 998 VertexEquivalencePredicate vertex_comp) {
Chris@16 999 return detail::vf2_subgraph_morphism<detail::subgraph_iso>
Chris@16 1000 (graph_small, graph_large,
Chris@16 1001 user_callback,
Chris@16 1002 index_map_small, index_map_large,
Chris@16 1003 vertex_order_small,
Chris@16 1004 edge_comp,
Chris@16 1005 vertex_comp);
Chris@16 1006 }
Chris@16 1007
Chris@16 1008
Chris@16 1009 // All default interface for vf2_subgraph_iso
Chris@16 1010 template <typename GraphSmall,
Chris@16 1011 typename GraphLarge,
Chris@16 1012 typename SubGraphIsoMapCallback>
Chris@16 1013 bool vf2_subgraph_iso(const GraphSmall& graph_small, const GraphLarge& graph_large,
Chris@16 1014 SubGraphIsoMapCallback user_callback) {
Chris@16 1015
Chris@16 1016 return vf2_subgraph_iso(graph_small, graph_large, user_callback,
Chris@16 1017 get(vertex_index, graph_small), get(vertex_index, graph_large),
Chris@16 1018 vertex_order_by_mult(graph_small),
Chris@16 1019 always_equivalent(), always_equivalent());
Chris@16 1020 }
Chris@16 1021
Chris@16 1022
Chris@16 1023 // Named parameter interface of vf2_subgraph_iso
Chris@16 1024 template <typename GraphSmall,
Chris@16 1025 typename GraphLarge,
Chris@16 1026 typename VertexOrderSmall,
Chris@16 1027 typename SubGraphIsoMapCallback,
Chris@16 1028 typename Param,
Chris@16 1029 typename Tag,
Chris@16 1030 typename Rest>
Chris@16 1031 bool vf2_subgraph_iso(const GraphSmall& graph_small, const GraphLarge& graph_large,
Chris@16 1032 SubGraphIsoMapCallback user_callback,
Chris@16 1033 const VertexOrderSmall& vertex_order_small,
Chris@16 1034 const bgl_named_params<Param, Tag, Rest>& params) {
Chris@16 1035
Chris@16 1036 return vf2_subgraph_iso(graph_small, graph_large, user_callback,
Chris@16 1037 choose_const_pmap(get_param(params, vertex_index1),
Chris@16 1038 graph_small, vertex_index),
Chris@16 1039 choose_const_pmap(get_param(params, vertex_index2),
Chris@16 1040 graph_large, vertex_index),
Chris@16 1041 vertex_order_small,
Chris@16 1042 choose_param(get_param(params, edges_equivalent_t()),
Chris@16 1043 always_equivalent()),
Chris@16 1044 choose_param(get_param(params, vertices_equivalent_t()),
Chris@16 1045 always_equivalent())
Chris@16 1046 );
Chris@16 1047
Chris@16 1048 }
Chris@16 1049
Chris@16 1050
Chris@16 1051 // Enumerates all isomorphism mappings between graphs graph1_ and graph2_.
Chris@16 1052 // Continues until user_callback returns true or the search space has been
Chris@16 1053 // fully explored.
Chris@16 1054 template <typename Graph1,
Chris@16 1055 typename Graph2,
Chris@16 1056 typename IndexMap1,
Chris@16 1057 typename IndexMap2,
Chris@16 1058 typename VertexOrder1,
Chris@16 1059 typename EdgeEquivalencePredicate,
Chris@16 1060 typename VertexEquivalencePredicate,
Chris@16 1061 typename GraphIsoMapCallback>
Chris@16 1062 bool vf2_graph_iso(const Graph1& graph1, const Graph2& graph2,
Chris@16 1063 GraphIsoMapCallback user_callback,
Chris@16 1064 IndexMap1 index_map1, IndexMap2 index_map2,
Chris@16 1065 const VertexOrder1& vertex_order1,
Chris@16 1066 EdgeEquivalencePredicate edge_comp,
Chris@16 1067 VertexEquivalencePredicate vertex_comp) {
Chris@16 1068
Chris@16 1069 // Graph requirements
Chris@16 1070 BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept<Graph1> ));
Chris@16 1071 BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph1> ));
Chris@16 1072 BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept<Graph1> ));
Chris@16 1073 BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept<Graph1> ));
Chris@16 1074
Chris@16 1075 BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept<Graph2> ));
Chris@16 1076 BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph2> ));
Chris@16 1077 BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept<Graph2> ));
Chris@16 1078 BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept<Graph2> ));
Chris@16 1079
Chris@16 1080
Chris@16 1081 typedef typename graph_traits<Graph1>::vertex_descriptor vertex1_type;
Chris@16 1082 typedef typename graph_traits<Graph2>::vertex_descriptor vertex2_type;
Chris@16 1083
Chris@16 1084 typedef typename graph_traits<Graph1>::vertices_size_type size_type1;
Chris@16 1085 typedef typename graph_traits<Graph2>::vertices_size_type size_type2;
Chris@16 1086
Chris@16 1087 // Property map requirements
Chris@16 1088 BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<IndexMap1, vertex1_type> ));
Chris@16 1089 typedef typename property_traits<IndexMap1>::value_type IndexMap1Value;
Chris@16 1090 BOOST_STATIC_ASSERT(( is_convertible<IndexMap1Value, size_type1>::value ));
Chris@16 1091
Chris@16 1092 BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<IndexMap2, vertex2_type> ));
Chris@16 1093 typedef typename property_traits<IndexMap2>::value_type IndexMap2Value;
Chris@16 1094 BOOST_STATIC_ASSERT(( is_convertible<IndexMap2Value, size_type2>::value ));
Chris@16 1095
Chris@16 1096 // Edge & vertex requirements
Chris@16 1097 typedef typename graph_traits<Graph1>::edge_descriptor edge1_type;
Chris@16 1098 typedef typename graph_traits<Graph2>::edge_descriptor edge2_type;
Chris@16 1099
Chris@16 1100 BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept<EdgeEquivalencePredicate,
Chris@16 1101 edge1_type, edge2_type> ));
Chris@16 1102
Chris@16 1103 BOOST_CONCEPT_ASSERT(( BinaryPredicateConcept<VertexEquivalencePredicate,
Chris@16 1104 vertex1_type, vertex2_type> ));
Chris@16 1105
Chris@16 1106 // Vertex order requirements
Chris@16 1107 BOOST_CONCEPT_ASSERT(( ContainerConcept<VertexOrder1> ));
Chris@16 1108 typedef typename VertexOrder1::value_type order_value_type;
Chris@16 1109 BOOST_STATIC_ASSERT(( is_same<vertex1_type, order_value_type>::value ));
Chris@16 1110 BOOST_ASSERT( num_vertices(graph1) == vertex_order1.size() );
Chris@16 1111
Chris@16 1112 if (num_vertices(graph1) != num_vertices(graph2))
Chris@16 1113 return false;
Chris@16 1114
Chris@16 1115 typename graph_traits<Graph1>::edges_size_type num_edges1 = num_edges(graph1);
Chris@16 1116 typename graph_traits<Graph2>::edges_size_type num_edges2 = num_edges(graph2);
Chris@16 1117
Chris@16 1118 // Double the number of edges for undirected graphs: each edge counts as
Chris@16 1119 // in-edge and out-edge
Chris@16 1120 if (is_undirected(graph1)) num_edges1 *= 2;
Chris@16 1121 if (is_undirected(graph2)) num_edges2 *= 2;
Chris@16 1122 if (num_edges1 != num_edges2)
Chris@16 1123 return false;
Chris@16 1124
Chris@16 1125 detail::state<Graph1, Graph2, IndexMap1, IndexMap2,
Chris@16 1126 EdgeEquivalencePredicate, VertexEquivalencePredicate,
Chris@16 1127 GraphIsoMapCallback, detail::isomorphism>
Chris@16 1128 s(graph1, graph2, index_map1, index_map2, edge_comp, vertex_comp);
Chris@16 1129
Chris@16 1130 return detail::match(graph1, graph2, user_callback, vertex_order1, s);
Chris@16 1131 }
Chris@16 1132
Chris@16 1133
Chris@16 1134 // All default interface for vf2_graph_iso
Chris@16 1135 template <typename Graph1,
Chris@16 1136 typename Graph2,
Chris@16 1137 typename GraphIsoMapCallback>
Chris@16 1138 bool vf2_graph_iso(const Graph1& graph1, const Graph2& graph2,
Chris@16 1139 GraphIsoMapCallback user_callback) {
Chris@16 1140
Chris@16 1141 return vf2_graph_iso(graph1, graph2, user_callback,
Chris@16 1142 get(vertex_index, graph1), get(vertex_index, graph2),
Chris@16 1143 vertex_order_by_mult(graph1),
Chris@16 1144 always_equivalent(), always_equivalent());
Chris@16 1145 }
Chris@16 1146
Chris@16 1147
Chris@16 1148 // Named parameter interface of vf2_graph_iso
Chris@16 1149 template <typename Graph1,
Chris@16 1150 typename Graph2,
Chris@16 1151 typename VertexOrder1,
Chris@16 1152 typename GraphIsoMapCallback,
Chris@16 1153 typename Param,
Chris@16 1154 typename Tag,
Chris@16 1155 typename Rest>
Chris@16 1156 bool vf2_graph_iso(const Graph1& graph1, const Graph2& graph2,
Chris@16 1157 GraphIsoMapCallback user_callback,
Chris@16 1158 const VertexOrder1& vertex_order1,
Chris@16 1159 const bgl_named_params<Param, Tag, Rest>& params) {
Chris@16 1160
Chris@16 1161 return vf2_graph_iso(graph1, graph2, user_callback,
Chris@16 1162 choose_const_pmap(get_param(params, vertex_index1),
Chris@16 1163 graph1, vertex_index),
Chris@16 1164 choose_const_pmap(get_param(params, vertex_index2),
Chris@16 1165 graph2, vertex_index),
Chris@16 1166 vertex_order1,
Chris@16 1167 choose_param(get_param(params, edges_equivalent_t()),
Chris@16 1168 always_equivalent()),
Chris@16 1169 choose_param(get_param(params, vertices_equivalent_t()),
Chris@16 1170 always_equivalent())
Chris@16 1171 );
Chris@16 1172
Chris@16 1173 }
Chris@16 1174
Chris@16 1175
Chris@16 1176 // Verifies a graph (sub)graph isomorphism map
Chris@16 1177 template<typename Graph1,
Chris@16 1178 typename Graph2,
Chris@16 1179 typename CorresponenceMap1To2,
Chris@16 1180 typename EdgeEquivalencePredicate,
Chris@16 1181 typename VertexEquivalencePredicate>
Chris@16 1182 inline bool verify_vf2_subgraph_iso(const Graph1& graph1, const Graph2& graph2,
Chris@16 1183 const CorresponenceMap1To2 f,
Chris@16 1184 EdgeEquivalencePredicate edge_comp,
Chris@16 1185 VertexEquivalencePredicate vertex_comp) {
Chris@16 1186
Chris@16 1187 BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept<Graph1> ));
Chris@16 1188 BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept<Graph2> ));
Chris@16 1189
Chris@16 1190 detail::equivalent_edge_exists<Graph2> edge2_exists;
Chris@16 1191
Chris@16 1192 BGL_FORALL_EDGES_T(e1, graph1, Graph1) {
Chris@16 1193 typename graph_traits<Graph1>::vertex_descriptor s1, t1;
Chris@16 1194 typename graph_traits<Graph2>::vertex_descriptor s2, t2;
Chris@16 1195
Chris@16 1196 s1 = source(e1, graph1); t1 = target(e1, graph1);
Chris@16 1197 s2 = get(f, s1); t2 = get(f, t1);
Chris@16 1198
Chris@16 1199 if (!vertex_comp(s1, s2) || !vertex_comp(t1, t2))
Chris@16 1200 return false;
Chris@16 1201
Chris@16 1202 typename graph_traits<Graph2>::edge_descriptor e2;
Chris@16 1203
Chris@16 1204 if (!edge2_exists(s2, t2,
Chris@16 1205 detail::edge2_predicate<Graph1, Graph2, EdgeEquivalencePredicate>(edge_comp, e1),
Chris@16 1206 graph2))
Chris@16 1207 return false;
Chris@16 1208
Chris@16 1209 }
Chris@16 1210
Chris@16 1211 return true;
Chris@16 1212 }
Chris@16 1213
Chris@16 1214 // Variant of verify_subgraph_iso with all default parameters
Chris@16 1215 template<typename Graph1,
Chris@16 1216 typename Graph2,
Chris@16 1217 typename CorresponenceMap1To2>
Chris@16 1218 inline bool verify_vf2_subgraph_iso(const Graph1& graph1, const Graph2& graph2,
Chris@16 1219 const CorresponenceMap1To2 f) {
Chris@16 1220 return verify_vf2_subgraph_iso(graph1, graph2, f,
Chris@16 1221 always_equivalent(), always_equivalent());
Chris@16 1222 }
Chris@16 1223
Chris@16 1224
Chris@16 1225
Chris@16 1226 } // namespace boost
Chris@16 1227
Chris@16 1228 #ifdef BOOST_ISO_INCLUDED_ITER_MACROS
Chris@16 1229 #undef BOOST_ISO_INCLUDED_ITER_MACROS
Chris@16 1230 #include <boost/graph/iteration_macros_undef.hpp>
Chris@16 1231 #endif
Chris@16 1232
Chris@16 1233 #endif // BOOST_VF2_SUB_GRAPH_ISO_HPP