annotate DEPENDENCIES/generic/include/boost/graph/is_kuratowski_subgraph.hpp @ 133:4acb5d8d80b6 tip

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