is_kuratowski_subgraph.hpp 11 KB

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