isomorphism.hpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. // Copyright (C) 2001 Jeremy Siek, Douglas Gregor, Brian Osman
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_GRAPH_ISOMORPHISM_HPP
  7. #define BOOST_GRAPH_ISOMORPHISM_HPP
  8. #include <utility>
  9. #include <vector>
  10. #include <iterator>
  11. #include <algorithm>
  12. #include <boost/config.hpp>
  13. #include <boost/assert.hpp>
  14. #include <boost/smart_ptr.hpp>
  15. #include <boost/graph/depth_first_search.hpp>
  16. #include <boost/detail/algorithm.hpp>
  17. #include <boost/unordered_map.hpp>
  18. #include <boost/unordered/unordered_flat_map.hpp>
  19. #include <boost/pending/indirect_cmp.hpp> // for make_indirect_pmap
  20. #include <boost/concept/assert.hpp>
  21. #ifndef BOOST_GRAPH_ITERATION_MACROS_HPP
  22. #define BOOST_ISO_INCLUDED_ITER_MACROS // local macro, see bottom of file
  23. #include <boost/graph/iteration_macros.hpp>
  24. #endif
  25. namespace boost
  26. {
  27. namespace detail
  28. {
  29. template < typename Graph1, typename Graph2, typename IsoMapping,
  30. typename Invariant1, typename Invariant2, typename IndexMap1,
  31. typename IndexMap2, typename InvariantCountMap = boost::unordered_flat_map<typename Invariant1::result_type, typename graph_traits< Graph1 >::vertices_size_type > >
  32. class isomorphism_algo
  33. {
  34. typedef typename graph_traits< Graph1 >::vertex_descriptor vertex1_t;
  35. typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2_t;
  36. typedef typename graph_traits< Graph1 >::edge_descriptor edge1_t;
  37. typedef typename graph_traits< Graph1 >::vertices_size_type size_type;
  38. typedef typename Invariant1::result_type invariant_t;
  39. const Graph1& G1;
  40. const Graph2& G2;
  41. IsoMapping f;
  42. Invariant1 invariant1;
  43. Invariant2 invariant2;
  44. IndexMap1 index_map1;
  45. IndexMap2 index_map2;
  46. std::vector< vertex1_t > dfs_vertices;
  47. typedef typename std::vector< vertex1_t >::iterator vertex_iter;
  48. std::vector< int > dfs_num_vec;
  49. typedef safe_iterator_property_map<
  50. typename std::vector< int >::iterator, IndexMap1
  51. #ifdef BOOST_NO_STD_ITERATOR_TRAITS
  52. ,
  53. int, int&
  54. #endif /* BOOST_NO_STD_ITERATOR_TRAITS */
  55. >
  56. DFSNumMap;
  57. DFSNumMap dfs_num;
  58. std::vector< edge1_t > ordered_edges;
  59. typedef typename std::vector< edge1_t >::iterator edge_iter;
  60. std::vector< char > in_S_vec;
  61. typedef safe_iterator_property_map<
  62. typename std::vector< char >::iterator, IndexMap2
  63. #ifdef BOOST_NO_STD_ITERATOR_TRAITS
  64. ,
  65. char, char&
  66. #endif /* BOOST_NO_STD_ITERATOR_TRAITS */
  67. >
  68. InSMap;
  69. InSMap in_S;
  70. int num_edges_on_k;
  71. friend struct compare_multiplicity;
  72. struct compare_multiplicity
  73. {
  74. compare_multiplicity(Invariant1 invariant1, const InvariantCountMap& multiplicity)
  75. : invariant1(invariant1), multiplicity(&multiplicity)
  76. {
  77. }
  78. bool operator()(const vertex1_t& x, const vertex1_t& y) const
  79. {
  80. auto x_multiplicity_iter = multiplicity->find(invariant1(x));
  81. assert(x_multiplicity_iter != multiplicity->end());
  82. auto y_multiplicity_iter = multiplicity->find(invariant1(y));
  83. assert(y_multiplicity_iter != multiplicity->end());
  84. return *x_multiplicity_iter < *y_multiplicity_iter;
  85. }
  86. Invariant1 invariant1;
  87. const InvariantCountMap* multiplicity;
  88. };
  89. struct record_dfs_order : default_dfs_visitor
  90. {
  91. record_dfs_order(
  92. std::vector< vertex1_t >& v, std::vector< edge1_t >& e)
  93. : vertices(v), edges(e)
  94. {
  95. }
  96. void discover_vertex(vertex1_t v, const Graph1&) const
  97. {
  98. vertices.push_back(v);
  99. }
  100. void examine_edge(edge1_t e, const Graph1&) const
  101. {
  102. edges.push_back(e);
  103. }
  104. std::vector< vertex1_t >& vertices;
  105. std::vector< edge1_t >& edges;
  106. };
  107. struct edge_cmp
  108. {
  109. edge_cmp(const Graph1& G1, DFSNumMap dfs_num)
  110. : G1(G1), dfs_num(dfs_num)
  111. {
  112. }
  113. bool operator()(const edge1_t& e1, const edge1_t& e2) const
  114. {
  115. using namespace std;
  116. int u1 = dfs_num[source(e1, G1)], v1 = dfs_num[target(e1, G1)];
  117. int u2 = dfs_num[source(e2, G1)], v2 = dfs_num[target(e2, G1)];
  118. int m1 = (max)(u1, v1);
  119. int m2 = (max)(u2, v2);
  120. // lexicographical comparison
  121. return std::make_pair(m1, std::make_pair(u1, v1))
  122. < std::make_pair(m2, std::make_pair(u2, v2));
  123. }
  124. const Graph1& G1;
  125. DFSNumMap dfs_num;
  126. };
  127. public:
  128. isomorphism_algo(const Graph1& G1, const Graph2& G2, IsoMapping f,
  129. Invariant1 invariant1, Invariant2 invariant2,
  130. std::size_t /* max_invariant */, IndexMap1 index_map1,
  131. IndexMap2 index_map2)
  132. : G1(G1)
  133. , G2(G2)
  134. , f(f)
  135. , invariant1(invariant1)
  136. , invariant2(invariant2)
  137. , index_map1(index_map1)
  138. , index_map2(index_map2)
  139. {
  140. in_S_vec.resize(num_vertices(G1));
  141. in_S = make_safe_iterator_property_map(
  142. in_S_vec.begin(), in_S_vec.size(), index_map2
  143. #ifdef BOOST_NO_STD_ITERATOR_TRAITS
  144. ,
  145. in_S_vec.front()
  146. #endif /* BOOST_NO_STD_ITERATOR_TRAITS */
  147. );
  148. }
  149. // Generates map of invariant multiplicity from sorted invariants
  150. template<typename ForwardIterator>
  151. InvariantCountMap multiplicities(ForwardIterator first, const ForwardIterator last)
  152. {
  153. typedef typename InvariantCountMap::iterator invar_map_iter;
  154. assert(std::is_sorted(first, last));
  155. InvariantCountMap invar_multiplicity;
  156. if(first == last)
  157. return invar_multiplicity;
  158. invariant_t invar = *first;
  159. invar_map_iter inserted = invar_multiplicity.emplace(invar, 1).first;
  160. ++first;
  161. for(; first != last; ++first)
  162. {
  163. if(*first == invar)
  164. {
  165. inserted->second += 1;
  166. }
  167. else
  168. {
  169. invar = *first;
  170. inserted = invar_multiplicity.emplace(invar, 1).first;
  171. }
  172. }
  173. return invar_multiplicity;
  174. }
  175. bool test_isomorphism()
  176. {
  177. // reset isomapping
  178. BGL_FORALL_VERTICES_T(v, G1, Graph1)
  179. f[v] = graph_traits< Graph2 >::null_vertex();
  180. // Calculate all invariants of G1 and G2, sort and compare
  181. std::vector< invariant_t > invar1_array;
  182. invar1_array.reserve(num_vertices(G1));
  183. BGL_FORALL_VERTICES_T(v, G1, Graph1)
  184. invar1_array.push_back(invariant1(v));
  185. sort(invar1_array);
  186. std::vector< invariant_t > invar2_array;
  187. invar2_array.reserve(num_vertices(G2));
  188. BGL_FORALL_VERTICES_T(v, G2, Graph2)
  189. invar2_array.push_back(invariant2(v));
  190. sort(invar2_array);
  191. if (!equal(invar1_array, invar2_array))
  192. return false;
  193. // Sort vertices by the multiplicity of their invariants
  194. std::vector< vertex1_t > V_mult;
  195. BGL_FORALL_VERTICES_T(v, G1, Graph1)
  196. V_mult.push_back(v);
  197. sort(V_mult, compare_multiplicity(invariant1, multiplicities(invar1_array.begin(), invar1_array.end())));
  198. std::vector< default_color_type > color_vec(num_vertices(G1));
  199. safe_iterator_property_map<
  200. std::vector< default_color_type >::iterator, IndexMap1
  201. #ifdef BOOST_NO_STD_ITERATOR_TRAITS
  202. ,
  203. default_color_type, default_color_type&
  204. #endif /* BOOST_NO_STD_ITERATOR_TRAITS */
  205. >
  206. color_map(color_vec.begin(), color_vec.size(), index_map1);
  207. record_dfs_order dfs_visitor(dfs_vertices, ordered_edges);
  208. typedef color_traits< default_color_type > Color;
  209. for (vertex_iter u = V_mult.begin(); u != V_mult.end(); ++u)
  210. {
  211. if (color_map[*u] == Color::white())
  212. {
  213. dfs_visitor.start_vertex(*u, G1);
  214. depth_first_visit(G1, *u, dfs_visitor, color_map);
  215. }
  216. }
  217. // Create the dfs_num array and dfs_num_map
  218. dfs_num_vec.resize(num_vertices(G1));
  219. dfs_num = make_safe_iterator_property_map(
  220. dfs_num_vec.begin(), dfs_num_vec.size(), index_map1
  221. #ifdef BOOST_NO_STD_ITERATOR_TRAITS
  222. ,
  223. dfs_num_vec.front()
  224. #endif /* BOOST_NO_STD_ITERATOR_TRAITS */
  225. );
  226. size_type n = 0;
  227. for (vertex_iter v = dfs_vertices.begin(); v != dfs_vertices.end();
  228. ++v)
  229. dfs_num[*v] = n++;
  230. sort(ordered_edges, edge_cmp(G1, dfs_num));
  231. int dfs_num_k = -1;
  232. return this->match(ordered_edges.begin(), dfs_num_k);
  233. }
  234. private:
  235. struct match_continuation
  236. {
  237. enum
  238. {
  239. pos_G2_vertex_loop,
  240. pos_fi_adj_loop,
  241. pos_dfs_num
  242. } position;
  243. typedef typename graph_traits< Graph2 >::vertex_iterator
  244. vertex_iterator;
  245. std::pair< vertex_iterator, vertex_iterator > G2_verts;
  246. typedef typename graph_traits< Graph2 >::adjacency_iterator
  247. adjacency_iterator;
  248. std::pair< adjacency_iterator, adjacency_iterator > fi_adj;
  249. edge_iter iter;
  250. int dfs_num_k;
  251. };
  252. bool match(edge_iter iter, int dfs_num_k)
  253. {
  254. std::vector< match_continuation > k;
  255. typedef typename graph_traits< Graph2 >::vertex_iterator
  256. vertex_iterator;
  257. std::pair< vertex_iterator, vertex_iterator > G2_verts(
  258. vertices(G2));
  259. typedef typename graph_traits< Graph2 >::adjacency_iterator
  260. adjacency_iterator;
  261. std::pair< adjacency_iterator, adjacency_iterator > fi_adj;
  262. vertex1_t i, j;
  263. recur:
  264. if (iter != ordered_edges.end())
  265. {
  266. i = source(*iter, G1);
  267. j = target(*iter, G1);
  268. if (dfs_num[i] > dfs_num_k)
  269. {
  270. G2_verts = vertices(G2);
  271. while (G2_verts.first != G2_verts.second)
  272. {
  273. {
  274. vertex2_t u = *G2_verts.first;
  275. vertex1_t kp1 = dfs_vertices[dfs_num_k + 1];
  276. if (invariant1(kp1) == invariant2(u)
  277. && in_S[u] == false)
  278. {
  279. {
  280. f[kp1] = u;
  281. in_S[u] = true;
  282. num_edges_on_k = 0;
  283. match_continuation new_k;
  284. new_k.position = match_continuation::
  285. pos_G2_vertex_loop;
  286. new_k.G2_verts = G2_verts;
  287. new_k.iter = iter;
  288. new_k.dfs_num_k = dfs_num_k;
  289. k.push_back(new_k);
  290. ++dfs_num_k;
  291. goto recur;
  292. }
  293. }
  294. }
  295. G2_loop_k:
  296. ++G2_verts.first;
  297. }
  298. }
  299. else if (dfs_num[j] > dfs_num_k)
  300. {
  301. {
  302. vertex1_t vk = dfs_vertices[dfs_num_k];
  303. num_edges_on_k -= count_if(adjacent_vertices(f[vk], G2),
  304. make_indirect_pmap(in_S));
  305. for (int jj = 0; jj < dfs_num_k; ++jj)
  306. {
  307. vertex1_t j = dfs_vertices[jj];
  308. num_edges_on_k
  309. -= count(adjacent_vertices(f[j], G2), f[vk]);
  310. }
  311. }
  312. if (num_edges_on_k != 0)
  313. goto return_point_false;
  314. fi_adj = adjacent_vertices(f[i], G2);
  315. while (fi_adj.first != fi_adj.second)
  316. {
  317. {
  318. vertex2_t v = *fi_adj.first;
  319. if (invariant2(v) == invariant1(j)
  320. && in_S[v] == false)
  321. {
  322. f[j] = v;
  323. in_S[v] = true;
  324. num_edges_on_k = 1;
  325. BOOST_USING_STD_MAX();
  326. int next_k
  327. = max BOOST_PREVENT_MACRO_SUBSTITUTION(
  328. dfs_num_k,
  329. max BOOST_PREVENT_MACRO_SUBSTITUTION(
  330. dfs_num[i], dfs_num[j]));
  331. match_continuation new_k;
  332. new_k.position
  333. = match_continuation::pos_fi_adj_loop;
  334. new_k.fi_adj = fi_adj;
  335. new_k.iter = iter;
  336. new_k.dfs_num_k = dfs_num_k;
  337. ++iter;
  338. dfs_num_k = next_k;
  339. k.push_back(new_k);
  340. goto recur;
  341. }
  342. }
  343. fi_adj_loop_k:
  344. ++fi_adj.first;
  345. }
  346. }
  347. else
  348. {
  349. if (container_contains(adjacent_vertices(f[i], G2), f[j]))
  350. {
  351. ++num_edges_on_k;
  352. match_continuation new_k;
  353. new_k.position = match_continuation::pos_dfs_num;
  354. k.push_back(new_k);
  355. ++iter;
  356. goto recur;
  357. }
  358. }
  359. }
  360. else
  361. goto return_point_true;
  362. goto return_point_false;
  363. {
  364. return_point_true:
  365. // At this point, there may still be null vertices in the
  366. // mapping for disconnected vertices
  367. map_disconnected_vertices();
  368. return true;
  369. return_point_false:
  370. if (k.empty())
  371. return false;
  372. const match_continuation& this_k = k.back();
  373. switch (this_k.position)
  374. {
  375. case match_continuation::pos_G2_vertex_loop:
  376. {
  377. G2_verts = this_k.G2_verts;
  378. iter = this_k.iter;
  379. dfs_num_k = this_k.dfs_num_k;
  380. k.pop_back();
  381. in_S[*G2_verts.first] = false;
  382. i = source(*iter, G1);
  383. j = target(*iter, G1);
  384. goto G2_loop_k;
  385. }
  386. case match_continuation::pos_fi_adj_loop:
  387. {
  388. fi_adj = this_k.fi_adj;
  389. iter = this_k.iter;
  390. dfs_num_k = this_k.dfs_num_k;
  391. k.pop_back();
  392. in_S[*fi_adj.first] = false;
  393. i = source(*iter, G1);
  394. j = target(*iter, G1);
  395. goto fi_adj_loop_k;
  396. }
  397. case match_continuation::pos_dfs_num:
  398. {
  399. k.pop_back();
  400. goto return_point_false;
  401. }
  402. default:
  403. {
  404. BOOST_ASSERT(!"Bad position");
  405. #ifdef UNDER_CE
  406. exit(-1);
  407. #else
  408. abort();
  409. #endif
  410. }
  411. }
  412. }
  413. }
  414. void map_disconnected_vertices()
  415. {
  416. std::vector< vertex1_t > unmatched_g1_vertices;
  417. BGL_FORALL_VERTICES_T(v, G1, Graph1)
  418. {
  419. if(f[v] == graph_traits< Graph2 >::null_vertex()) {
  420. unmatched_g1_vertices.push_back(v);
  421. }
  422. }
  423. if(!unmatched_g1_vertices.empty())
  424. {
  425. typedef unordered_multimap< invariant_t, vertex2_t > g2_invariant_vertex_multimap;
  426. typedef typename g2_invariant_vertex_multimap::iterator multimap_iter;
  427. g2_invariant_vertex_multimap unmatched_invariants;
  428. BGL_FORALL_VERTICES_T(v, G2, Graph2)
  429. {
  430. if(!in_S[v])
  431. {
  432. unmatched_invariants.emplace(invariant2(v), v);
  433. }
  434. }
  435. typedef typename std::vector< vertex1_t >::iterator v1_iter;
  436. const v1_iter end = unmatched_g1_vertices.end();
  437. for(v1_iter iter = unmatched_g1_vertices.begin(); iter != end; ++iter)
  438. {
  439. invariant_t unmatched_g1_vertex_invariant = invariant1(*iter);
  440. multimap_iter matching_invariant = unmatched_invariants.find(unmatched_g1_vertex_invariant);
  441. BOOST_ASSERT(matching_invariant != unmatched_invariants.end());
  442. f[*iter] = matching_invariant->second;
  443. unmatched_invariants.erase(matching_invariant);
  444. }
  445. }
  446. }
  447. };
  448. template < typename Graph, typename InDegreeMap >
  449. void compute_in_degree(const Graph& g, InDegreeMap in_degree_map)
  450. {
  451. BGL_FORALL_VERTICES_T(v, g, Graph)
  452. put(in_degree_map, v, 0);
  453. BGL_FORALL_VERTICES_T(u, g, Graph)
  454. BGL_FORALL_ADJ_T(u, v, g, Graph)
  455. put(in_degree_map, v, get(in_degree_map, v) + 1);
  456. }
  457. } // namespace detail
  458. template < typename InDegreeMap, typename Graph > class degree_vertex_invariant
  459. {
  460. typedef typename graph_traits< Graph >::vertex_descriptor vertex_t;
  461. typedef typename graph_traits< Graph >::degree_size_type size_type;
  462. public:
  463. typedef vertex_t argument_type;
  464. typedef size_type result_type;
  465. degree_vertex_invariant(const InDegreeMap& in_degree_map, const Graph& g)
  466. : m_in_degree_map(in_degree_map)
  467. , m_max_vertex_in_degree(0)
  468. , m_max_vertex_out_degree(0)
  469. , m_g(g)
  470. {
  471. BGL_FORALL_VERTICES_T(v, g, Graph)
  472. {
  473. m_max_vertex_in_degree
  474. = (std::max)(m_max_vertex_in_degree, get(m_in_degree_map, v));
  475. m_max_vertex_out_degree
  476. = (std::max)(m_max_vertex_out_degree, out_degree(v, g));
  477. }
  478. }
  479. size_type operator()(vertex_t v) const
  480. {
  481. return (m_max_vertex_in_degree + 1) * out_degree(v, m_g)
  482. + get(m_in_degree_map, v);
  483. }
  484. // The largest possible vertex invariant number
  485. size_type max BOOST_PREVENT_MACRO_SUBSTITUTION() const
  486. {
  487. return (m_max_vertex_in_degree + 1) * (m_max_vertex_out_degree + 1);
  488. }
  489. private:
  490. InDegreeMap m_in_degree_map;
  491. size_type m_max_vertex_in_degree;
  492. size_type m_max_vertex_out_degree;
  493. const Graph& m_g;
  494. };
  495. // Count actual number of vertices, even in filtered graphs.
  496. template < typename Graph > size_t count_vertices(const Graph& g)
  497. {
  498. size_t n = 0;
  499. BGL_FORALL_VERTICES_T(v, g, Graph)
  500. {
  501. (void)v;
  502. ++n;
  503. }
  504. return n;
  505. }
  506. template < typename Graph1, typename Graph2, typename IsoMapping,
  507. typename Invariant1, typename Invariant2, typename IndexMap1,
  508. typename IndexMap2 >
  509. bool isomorphism(const Graph1& G1, const Graph2& G2, IsoMapping f,
  510. Invariant1 invariant1, Invariant2 invariant2, std::size_t /* max_invariant */,
  511. IndexMap1 index_map1, IndexMap2 index_map2)
  512. {
  513. // Graph requirements
  514. BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph1 >));
  515. BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph1 >));
  516. BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph2 >));
  517. // BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept<Graph2> ));
  518. typedef typename graph_traits< Graph1 >::vertex_descriptor vertex1_t;
  519. typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2_t;
  520. typedef typename graph_traits< Graph1 >::vertices_size_type size_type;
  521. typedef typename Invariant1::result_type invariant1_t;
  522. typedef typename Invariant2::result_type invariant2_t;
  523. BOOST_STATIC_ASSERT(is_same<invariant1_t, invariant2_t>::value);
  524. // Vertex invariant requirement
  525. BOOST_CONCEPT_ASSERT(
  526. (AdaptableUnaryFunctionConcept< Invariant1, invariant1_t, vertex1_t >));
  527. BOOST_CONCEPT_ASSERT(
  528. (AdaptableUnaryFunctionConcept< Invariant2, invariant2_t, vertex2_t >));
  529. // Property map requirements
  530. BOOST_CONCEPT_ASSERT(
  531. (ReadWritePropertyMapConcept< IsoMapping, vertex1_t >));
  532. typedef typename property_traits< IsoMapping >::value_type IsoMappingValue;
  533. BOOST_STATIC_ASSERT((is_convertible< IsoMappingValue, vertex2_t >::value));
  534. BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< IndexMap1, vertex1_t >));
  535. typedef typename property_traits< IndexMap1 >::value_type IndexMap1Value;
  536. BOOST_STATIC_ASSERT((is_convertible< IndexMap1Value, size_type >::value));
  537. BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept< IndexMap2, vertex2_t >));
  538. typedef typename property_traits< IndexMap2 >::value_type IndexMap2Value;
  539. BOOST_STATIC_ASSERT((is_convertible< IndexMap2Value, size_type >::value));
  540. if (count_vertices(G1) != count_vertices(G2))
  541. return false;
  542. if (count_vertices(G1) == 0 && count_vertices(G2) == 0)
  543. return true;
  544. detail::isomorphism_algo< Graph1, Graph2, IsoMapping, Invariant1,
  545. Invariant2, IndexMap1, IndexMap2 >
  546. algo(G1, G2, f, invariant1, invariant2, 0, index_map1,
  547. index_map2);
  548. return algo.test_isomorphism();
  549. }
  550. namespace detail
  551. {
  552. template < typename Graph1, typename Graph2, typename IsoMapping,
  553. typename IndexMap1, typename IndexMap2, typename P, typename T,
  554. typename R >
  555. bool isomorphism_impl(const Graph1& G1, const Graph2& G2, IsoMapping f,
  556. IndexMap1 index_map1, IndexMap2 index_map2,
  557. const bgl_named_params< P, T, R >& params)
  558. {
  559. std::vector< std::size_t > in_degree1_vec(num_vertices(G1));
  560. typedef safe_iterator_property_map<
  561. std::vector< std::size_t >::iterator, IndexMap1
  562. #ifdef BOOST_NO_STD_ITERATOR_TRAITS
  563. ,
  564. std::size_t, std::size_t&
  565. #endif /* BOOST_NO_STD_ITERATOR_TRAITS */
  566. >
  567. InDeg1;
  568. InDeg1 in_degree1(
  569. in_degree1_vec.begin(), in_degree1_vec.size(), index_map1);
  570. compute_in_degree(G1, in_degree1);
  571. std::vector< std::size_t > in_degree2_vec(num_vertices(G2));
  572. typedef safe_iterator_property_map<
  573. std::vector< std::size_t >::iterator, IndexMap2
  574. #ifdef BOOST_NO_STD_ITERATOR_TRAITS
  575. ,
  576. std::size_t, std::size_t&
  577. #endif /* BOOST_NO_STD_ITERATOR_TRAITS */
  578. >
  579. InDeg2;
  580. InDeg2 in_degree2(
  581. in_degree2_vec.begin(), in_degree2_vec.size(), index_map2);
  582. compute_in_degree(G2, in_degree2);
  583. degree_vertex_invariant< InDeg1, Graph1 > invariant1(in_degree1, G1);
  584. degree_vertex_invariant< InDeg2, Graph2 > invariant2(in_degree2, G2);
  585. return isomorphism(G1, G2, f,
  586. choose_param(get_param(params, vertex_invariant1_t()), invariant1),
  587. choose_param(get_param(params, vertex_invariant2_t()), invariant2),
  588. 0,
  589. index_map1, index_map2);
  590. }
  591. template < typename G, typename Index > struct make_degree_invariant
  592. {
  593. const G& g;
  594. const Index& index;
  595. make_degree_invariant(const G& g, const Index& index)
  596. : g(g), index(index)
  597. {
  598. }
  599. typedef typename boost::graph_traits< G >::degree_size_type
  600. degree_size_type;
  601. typedef shared_array_property_map< degree_size_type, Index >
  602. prop_map_type;
  603. typedef degree_vertex_invariant< prop_map_type, G > result_type;
  604. result_type operator()() const
  605. {
  606. prop_map_type pm = make_shared_array_property_map(
  607. num_vertices(g), degree_size_type(), index);
  608. compute_in_degree(g, pm);
  609. return result_type(pm, g);
  610. }
  611. };
  612. } // namespace detail
  613. namespace graph
  614. {
  615. namespace detail
  616. {
  617. template < typename Graph1, typename Graph2 > struct isomorphism_impl
  618. {
  619. typedef bool result_type;
  620. typedef result_type type;
  621. template < typename ArgPack >
  622. bool operator()(const Graph1& g1, const Graph2& g2,
  623. const ArgPack& arg_pack) const
  624. {
  625. using namespace boost::graph::keywords;
  626. typedef typename boost::detail::override_const_property_result<
  627. ArgPack, tag::vertex_index1_map, boost::vertex_index_t,
  628. Graph1 >::type index1_map_type;
  629. typedef typename boost::detail::override_const_property_result<
  630. ArgPack, tag::vertex_index2_map, boost::vertex_index_t,
  631. Graph2 >::type index2_map_type;
  632. index1_map_type index1_map
  633. = boost::detail::override_const_property(
  634. arg_pack, _vertex_index1_map, g1, boost::vertex_index);
  635. index2_map_type index2_map
  636. = boost::detail::override_const_property(
  637. arg_pack, _vertex_index2_map, g2, boost::vertex_index);
  638. typedef typename graph_traits< Graph2 >::vertex_descriptor
  639. vertex2_t;
  640. typename std::vector< vertex2_t >::size_type n
  641. = (typename std::vector< vertex2_t >::size_type)
  642. num_vertices(g1);
  643. std::vector< vertex2_t > f(n);
  644. typename boost::parameter::lazy_binding< ArgPack,
  645. tag::vertex_invariant1,
  646. boost::detail::make_degree_invariant< Graph1,
  647. index1_map_type > >::type invariant1
  648. = arg_pack[_vertex_invariant1
  649. || boost::detail::make_degree_invariant< Graph1,
  650. index1_map_type >(g1, index1_map)];
  651. typename boost::parameter::lazy_binding< ArgPack,
  652. tag::vertex_invariant2,
  653. boost::detail::make_degree_invariant< Graph2,
  654. index2_map_type > >::type invariant2
  655. = arg_pack[_vertex_invariant2
  656. || boost::detail::make_degree_invariant< Graph2,
  657. index2_map_type >(g2, index2_map)];
  658. return boost::isomorphism(g1, g2,
  659. choose_param(
  660. arg_pack[_isomorphism_map | boost::param_not_found()],
  661. make_shared_array_property_map(
  662. num_vertices(g1), vertex2_t(), index1_map)),
  663. invariant1, invariant2,
  664. 0,
  665. index1_map, index2_map);
  666. }
  667. };
  668. }
  669. BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(isomorphism, 2, 6)
  670. }
  671. // Named parameter interface
  672. BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(isomorphism, 2)
  673. // Verify that the given mapping iso_map from the vertices of g1 to the
  674. // vertices of g2 describes an isomorphism.
  675. // Note: this could be made much faster by specializing based on the graph
  676. // concepts modeled, but since we're verifying an O(n^(lg n)) algorithm,
  677. // O(n^4) won't hurt us.
  678. template < typename Graph1, typename Graph2, typename IsoMap >
  679. inline bool verify_isomorphism(
  680. const Graph1& g1, const Graph2& g2, IsoMap iso_map)
  681. {
  682. #if 0
  683. // problematic for filtered_graph!
  684. if (num_vertices(g1) != num_vertices(g2) || num_edges(g1) != num_edges(g2))
  685. return false;
  686. #endif
  687. BGL_FORALL_EDGES_T(e1, g1, Graph1)
  688. {
  689. bool found_edge = false;
  690. BGL_FORALL_EDGES_T(e2, g2, Graph2)
  691. {
  692. if (source(e2, g2) == get(iso_map, source(e1, g1))
  693. && target(e2, g2) == get(iso_map, target(e1, g1)))
  694. {
  695. found_edge = true;
  696. }
  697. }
  698. if (!found_edge)
  699. return false;
  700. }
  701. return true;
  702. }
  703. } // namespace boost
  704. #ifdef BOOST_ISO_INCLUDED_ITER_MACROS
  705. #undef BOOST_ISO_INCLUDED_ITER_MACROS
  706. #include <boost/graph/iteration_macros_undef.hpp>
  707. #endif
  708. #endif // BOOST_GRAPH_ISOMORPHISM_HPP