is_kuratowski_subgraph.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. //=======================================================================
  2. // Copyright 2007 Aaron Windsor
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //=======================================================================
  8. #ifndef __IS_KURATOWSKI_SUBGRAPH_HPP__
  9. #define __IS_KURATOWSKI_SUBGRAPH_HPP__
  10. #include <boost/config.hpp>
  11. #include <boost/tuple/tuple.hpp> //for tie
  12. #include <boost/property_map/property_map.hpp>
  13. #include <boost/graph/properties.hpp>
  14. #include <boost/graph/isomorphism.hpp>
  15. #include <boost/graph/adjacency_list.hpp>
  16. #include <algorithm>
  17. #include <vector>
  18. #include <set>
  19. namespace boost
  20. {
  21. namespace detail
  22. {
  23. template < typename Graph > Graph make_K_5()
  24. {
  25. typename graph_traits< Graph >::vertex_iterator vi, vi_end, inner_vi;
  26. Graph K_5(5);
  27. for (boost::tie(vi, vi_end) = vertices(K_5); vi != vi_end; ++vi)
  28. for (inner_vi = next(vi); inner_vi != vi_end; ++inner_vi)
  29. add_edge(*vi, *inner_vi, K_5);
  30. return K_5;
  31. }
  32. template < typename Graph > Graph make_K_3_3()
  33. {
  34. typename graph_traits< Graph >::vertex_iterator vi, vi_end,
  35. bipartition_start, inner_vi;
  36. Graph K_3_3(6);
  37. bipartition_start = next(next(next(vertices(K_3_3).first)));
  38. for (boost::tie(vi, vi_end) = vertices(K_3_3); vi != bipartition_start;
  39. ++vi)
  40. for (inner_vi = bipartition_start; inner_vi != vi_end; ++inner_vi)
  41. add_edge(*vi, *inner_vi, K_3_3);
  42. return K_3_3;
  43. }
  44. template < typename AdjacencyList, typename Vertex >
  45. void contract_edge(AdjacencyList& neighbors, Vertex u, Vertex v)
  46. {
  47. // Remove u from v's neighbor list
  48. neighbors[v].erase(
  49. std::remove(neighbors[v].begin(), neighbors[v].end(), u),
  50. neighbors[v].end());
  51. // Replace any references to u with references to v
  52. typedef
  53. typename AdjacencyList::value_type::iterator adjacency_iterator_t;
  54. adjacency_iterator_t u_neighbor_end = neighbors[u].end();
  55. for (adjacency_iterator_t u_neighbor_itr = neighbors[u].begin();
  56. u_neighbor_itr != u_neighbor_end; ++u_neighbor_itr)
  57. {
  58. Vertex u_neighbor(*u_neighbor_itr);
  59. std::replace(neighbors[u_neighbor].begin(),
  60. neighbors[u_neighbor].end(), u, v);
  61. }
  62. // Remove v from u's neighbor list
  63. neighbors[u].erase(
  64. std::remove(neighbors[u].begin(), neighbors[u].end(), v),
  65. neighbors[u].end());
  66. // Add everything in u's neighbor list to v's neighbor list
  67. std::copy(neighbors[u].begin(), neighbors[u].end(),
  68. std::back_inserter(neighbors[v]));
  69. // Clear u's neighbor list
  70. neighbors[u].clear();
  71. }
  72. enum target_graph_t
  73. {
  74. tg_k_3_3,
  75. tg_k_5
  76. };
  77. } // namespace detail
  78. template < typename Graph, typename ForwardIterator, typename VertexIndexMap >
  79. bool is_kuratowski_subgraph(const Graph& g, ForwardIterator begin,
  80. ForwardIterator end, VertexIndexMap vm)
  81. {
  82. typedef typename graph_traits< Graph >::vertex_descriptor vertex_t;
  83. typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
  84. typedef typename graph_traits< Graph >::edge_descriptor edge_t;
  85. typedef typename graph_traits< Graph >::edges_size_type e_size_t;
  86. typedef typename graph_traits< Graph >::vertices_size_type v_size_t;
  87. typedef typename std::vector< vertex_t > v_list_t;
  88. typedef typename v_list_t::iterator v_list_iterator_t;
  89. typedef iterator_property_map< typename std::vector< v_list_t >::iterator,
  90. VertexIndexMap >
  91. vertex_to_v_list_map_t;
  92. typedef adjacency_list< vecS, vecS, undirectedS > small_graph_t;
  93. detail::target_graph_t target_graph
  94. = detail::tg_k_3_3; // unless we decide otherwise later
  95. static small_graph_t K_5(detail::make_K_5< small_graph_t >());
  96. static small_graph_t K_3_3(detail::make_K_3_3< small_graph_t >());
  97. v_size_t n_vertices(num_vertices(g));
  98. v_size_t max_num_edges(3 * n_vertices - 5);
  99. std::vector< v_list_t > neighbors_vector(n_vertices);
  100. vertex_to_v_list_map_t neighbors(neighbors_vector.begin(), vm);
  101. e_size_t count = 0;
  102. for (ForwardIterator itr = begin; itr != end; ++itr)
  103. {
  104. if (count++ > max_num_edges)
  105. return false;
  106. edge_t e(*itr);
  107. vertex_t u(source(e, g));
  108. vertex_t v(target(e, g));
  109. neighbors[u].push_back(v);
  110. neighbors[v].push_back(u);
  111. }
  112. for (v_size_t max_size = 2; max_size < 5; ++max_size)
  113. {
  114. vertex_iterator_t vi, vi_end;
  115. for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
  116. {
  117. vertex_t v(*vi);
  118. // a hack to make sure we don't contract the middle edge of a path
  119. // of four degree-3 vertices
  120. if (max_size == 4 && neighbors[v].size() == 3)
  121. {
  122. if (neighbors[neighbors[v][0]].size()
  123. + neighbors[neighbors[v][1]].size()
  124. + neighbors[neighbors[v][2]].size()
  125. < 11 // so, it has two degree-3 neighbors
  126. )
  127. continue;
  128. }
  129. while (neighbors[v].size() > 0 && neighbors[v].size() < max_size)
  130. {
  131. // Find one of v's neighbors u such that v and u
  132. // have no neighbors in common. We'll look for such a
  133. // neighbor with a naive cubic-time algorithm since the
  134. // max size of any of the neighbor sets we'll consider
  135. // merging is 3
  136. bool neighbor_sets_intersect = false;
  137. vertex_t min_u = graph_traits< Graph >::null_vertex();
  138. vertex_t u;
  139. v_list_iterator_t v_neighbor_end = neighbors[v].end();
  140. for (v_list_iterator_t v_neighbor_itr = neighbors[v].begin();
  141. v_neighbor_itr != v_neighbor_end; ++v_neighbor_itr)
  142. {
  143. neighbor_sets_intersect = false;
  144. u = *v_neighbor_itr;
  145. v_list_iterator_t u_neighbor_end = neighbors[u].end();
  146. for (v_list_iterator_t u_neighbor_itr
  147. = neighbors[u].begin();
  148. u_neighbor_itr != u_neighbor_end
  149. && !neighbor_sets_intersect;
  150. ++u_neighbor_itr)
  151. {
  152. for (v_list_iterator_t inner_v_neighbor_itr
  153. = neighbors[v].begin();
  154. inner_v_neighbor_itr != v_neighbor_end;
  155. ++inner_v_neighbor_itr)
  156. {
  157. if (*u_neighbor_itr == *inner_v_neighbor_itr)
  158. {
  159. neighbor_sets_intersect = true;
  160. break;
  161. }
  162. }
  163. }
  164. if (!neighbor_sets_intersect
  165. && (min_u == graph_traits< Graph >::null_vertex()
  166. || neighbors[u].size() < neighbors[min_u].size()))
  167. {
  168. min_u = u;
  169. }
  170. }
  171. if (min_u == graph_traits< Graph >::null_vertex())
  172. // Exited the loop without finding an appropriate neighbor
  173. // of v, so v must be a lost cause. Move on to other
  174. // vertices.
  175. break;
  176. else
  177. u = min_u;
  178. detail::contract_edge(neighbors, u, v);
  179. } // end iteration over v's neighbors
  180. } // end iteration through vertices v
  181. if (max_size == 3)
  182. {
  183. // check to see whether we should go on to find a K_5
  184. for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
  185. if (neighbors[*vi].size() == 4)
  186. {
  187. target_graph = detail::tg_k_5;
  188. break;
  189. }
  190. if (target_graph == detail::tg_k_3_3)
  191. break;
  192. }
  193. } // end iteration through max degree 2,3, and 4
  194. // Now, there should only be 5 or 6 vertices with any neighbors. Find them.
  195. v_list_t main_vertices;
  196. vertex_iterator_t vi, vi_end;
  197. for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
  198. {
  199. if (!neighbors[*vi].empty())
  200. main_vertices.push_back(*vi);
  201. }
  202. // create a graph isomorphic to the contracted graph to test
  203. // against K_5 and K_3_3
  204. small_graph_t contracted_graph(main_vertices.size());
  205. std::map< vertex_t,
  206. typename graph_traits< small_graph_t >::vertex_descriptor >
  207. contracted_vertex_map;
  208. typename v_list_t::iterator itr, itr_end;
  209. itr_end = main_vertices.end();
  210. typename graph_traits< small_graph_t >::vertex_iterator si
  211. = vertices(contracted_graph).first;
  212. for (itr = main_vertices.begin(); itr != itr_end; ++itr, ++si)
  213. {
  214. contracted_vertex_map[*itr] = *si;
  215. }
  216. typename v_list_t::iterator jtr, jtr_end;
  217. for (itr = main_vertices.begin(); itr != itr_end; ++itr)
  218. {
  219. jtr_end = neighbors[*itr].end();
  220. for (jtr = neighbors[*itr].begin(); jtr != jtr_end; ++jtr)
  221. {
  222. if (get(vm, *itr) < get(vm, *jtr))
  223. {
  224. add_edge(contracted_vertex_map[*itr],
  225. contracted_vertex_map[*jtr], contracted_graph);
  226. }
  227. }
  228. }
  229. if (target_graph == detail::tg_k_5)
  230. {
  231. return boost::isomorphism(K_5, contracted_graph);
  232. }
  233. else // target_graph == tg_k_3_3
  234. {
  235. return boost::isomorphism(K_3_3, contracted_graph);
  236. }
  237. }
  238. template < typename Graph, typename ForwardIterator >
  239. bool is_kuratowski_subgraph(
  240. const Graph& g, ForwardIterator begin, ForwardIterator end)
  241. {
  242. return is_kuratowski_subgraph(g, begin, end, get(vertex_index, g));
  243. }
  244. }
  245. #endif //__IS_KURATOWSKI_SUBGRAPH_HPP__