annotate DEPENDENCIES/generic/include/boost/graph/planar_detail/boyer_myrvold_impl.hpp @ 118:770eb830ec19 emscripten

Typo fix
author Chris Cannam
date Wed, 18 May 2016 16:14:08 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 //=======================================================================
Chris@16 2 // Copyright (c) Aaron Windsor 2007
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 __BOYER_MYRVOLD_IMPL_HPP__
Chris@16 9 #define __BOYER_MYRVOLD_IMPL_HPP__
Chris@16 10
Chris@16 11 #include <vector>
Chris@16 12 #include <list>
Chris@16 13 #include <boost/next_prior.hpp>
Chris@16 14 #include <boost/config.hpp> //for std::min macros
Chris@16 15 #include <boost/shared_ptr.hpp>
Chris@16 16 #include <boost/tuple/tuple.hpp>
Chris@16 17 #include <boost/property_map/property_map.hpp>
Chris@16 18 #include <boost/graph/graph_traits.hpp>
Chris@16 19 #include <boost/graph/depth_first_search.hpp>
Chris@16 20 #include <boost/graph/planar_detail/face_handles.hpp>
Chris@16 21 #include <boost/graph/planar_detail/face_iterators.hpp>
Chris@16 22 #include <boost/graph/planar_detail/bucket_sort.hpp>
Chris@16 23
Chris@16 24
Chris@16 25
Chris@16 26 namespace boost
Chris@16 27 {
Chris@16 28 namespace detail {
Chris@16 29 enum bm_case_t{BM_NO_CASE_CHOSEN, BM_CASE_A, BM_CASE_B, BM_CASE_C, BM_CASE_D, BM_CASE_E};
Chris@16 30 }
Chris@16 31
Chris@16 32 template<typename LowPointMap, typename DFSParentMap,
Chris@16 33 typename DFSNumberMap, typename LeastAncestorMap,
Chris@16 34 typename DFSParentEdgeMap, typename SizeType>
Chris@16 35 struct planar_dfs_visitor : public dfs_visitor<>
Chris@16 36 {
Chris@16 37 planar_dfs_visitor(LowPointMap lpm, DFSParentMap dfs_p,
Chris@16 38 DFSNumberMap dfs_n, LeastAncestorMap lam,
Chris@16 39 DFSParentEdgeMap dfs_edge)
Chris@16 40 : low(lpm),
Chris@16 41 parent(dfs_p),
Chris@16 42 df_number(dfs_n),
Chris@16 43 least_ancestor(lam),
Chris@16 44 df_edge(dfs_edge),
Chris@16 45 count(0)
Chris@16 46 {}
Chris@16 47
Chris@16 48
Chris@16 49 template <typename Vertex, typename Graph>
Chris@16 50 void start_vertex(const Vertex& u, Graph&)
Chris@16 51 {
Chris@16 52 put(parent, u, u);
Chris@16 53 put(least_ancestor, u, count);
Chris@16 54 }
Chris@16 55
Chris@16 56
Chris@16 57 template <typename Vertex, typename Graph>
Chris@16 58 void discover_vertex(const Vertex& u, Graph&)
Chris@16 59 {
Chris@16 60 put(low, u, count);
Chris@16 61 put(df_number, u, count);
Chris@16 62 ++count;
Chris@16 63 }
Chris@16 64
Chris@16 65 template <typename Edge, typename Graph>
Chris@16 66 void tree_edge(const Edge& e, Graph& g)
Chris@16 67 {
Chris@16 68 typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
Chris@16 69 vertex_t s(source(e,g));
Chris@16 70 vertex_t t(target(e,g));
Chris@16 71
Chris@16 72 put(parent, t, s);
Chris@16 73 put(df_edge, t, e);
Chris@16 74 put(least_ancestor, t, get(df_number, s));
Chris@16 75 }
Chris@16 76
Chris@16 77 template <typename Edge, typename Graph>
Chris@16 78 void back_edge(const Edge& e, Graph& g)
Chris@16 79 {
Chris@16 80 typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
Chris@16 81 typedef typename graph_traits<Graph>::vertices_size_type v_size_t;
Chris@16 82
Chris@16 83 vertex_t s(source(e,g));
Chris@16 84 vertex_t t(target(e,g));
Chris@16 85 BOOST_USING_STD_MIN();
Chris@16 86
Chris@16 87 if ( t != get(parent, s) ) {
Chris@16 88 v_size_t s_low_df_number = get(low, s);
Chris@16 89 v_size_t t_df_number = get(df_number, t);
Chris@16 90 v_size_t s_least_ancestor_df_number = get(least_ancestor, s);
Chris@16 91
Chris@16 92 put(low, s,
Chris@16 93 min BOOST_PREVENT_MACRO_SUBSTITUTION(s_low_df_number,
Chris@16 94 t_df_number)
Chris@16 95 );
Chris@16 96
Chris@16 97 put(least_ancestor, s,
Chris@16 98 min BOOST_PREVENT_MACRO_SUBSTITUTION(s_least_ancestor_df_number,
Chris@16 99 t_df_number
Chris@16 100 )
Chris@16 101 );
Chris@16 102
Chris@16 103 }
Chris@16 104 }
Chris@16 105
Chris@16 106 template <typename Vertex, typename Graph>
Chris@16 107 void finish_vertex(const Vertex& u, Graph&)
Chris@16 108 {
Chris@16 109 typedef typename graph_traits<Graph>::vertices_size_type v_size_t;
Chris@16 110
Chris@16 111 Vertex u_parent = get(parent, u);
Chris@16 112 v_size_t u_parent_lowpoint = get(low, u_parent);
Chris@16 113 v_size_t u_lowpoint = get(low, u);
Chris@16 114 BOOST_USING_STD_MIN();
Chris@16 115
Chris@16 116 if (u_parent != u)
Chris@16 117 {
Chris@16 118 put(low, u_parent,
Chris@16 119 min BOOST_PREVENT_MACRO_SUBSTITUTION(u_lowpoint,
Chris@16 120 u_parent_lowpoint
Chris@16 121 )
Chris@16 122 );
Chris@16 123 }
Chris@16 124 }
Chris@16 125
Chris@16 126 LowPointMap low;
Chris@16 127 DFSParentMap parent;
Chris@16 128 DFSNumberMap df_number;
Chris@16 129 LeastAncestorMap least_ancestor;
Chris@16 130 DFSParentEdgeMap df_edge;
Chris@16 131 SizeType count;
Chris@16 132
Chris@16 133 };
Chris@16 134
Chris@16 135
Chris@16 136
Chris@16 137
Chris@16 138
Chris@16 139
Chris@16 140 template <typename Graph,
Chris@16 141 typename VertexIndexMap,
Chris@16 142 typename StoreOldHandlesPolicy = graph::detail::store_old_handles,
Chris@16 143 typename StoreEmbeddingPolicy = graph::detail::recursive_lazy_list
Chris@16 144 >
Chris@16 145 class boyer_myrvold_impl
Chris@16 146 {
Chris@16 147
Chris@16 148 typedef typename graph_traits<Graph>::vertices_size_type v_size_t;
Chris@16 149 typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
Chris@16 150 typedef typename graph_traits<Graph>::edge_descriptor edge_t;
Chris@16 151 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
Chris@16 152 typedef typename graph_traits<Graph>::edge_iterator edge_iterator_t;
Chris@16 153 typedef typename graph_traits<Graph>::out_edge_iterator
Chris@16 154 out_edge_iterator_t;
Chris@16 155 typedef graph::detail::face_handle
Chris@16 156 <Graph, StoreOldHandlesPolicy, StoreEmbeddingPolicy> face_handle_t;
Chris@16 157 typedef std::vector<vertex_t> vertex_vector_t;
Chris@16 158 typedef std::vector<edge_t> edge_vector_t;
Chris@16 159 typedef std::list<vertex_t> vertex_list_t;
Chris@16 160 typedef std::list< face_handle_t > face_handle_list_t;
Chris@16 161 typedef boost::shared_ptr< face_handle_list_t > face_handle_list_ptr_t;
Chris@16 162 typedef boost::shared_ptr< vertex_list_t > vertex_list_ptr_t;
Chris@16 163 typedef boost::tuple<vertex_t, bool, bool> merge_stack_frame_t;
Chris@16 164 typedef std::vector<merge_stack_frame_t> merge_stack_t;
Chris@16 165
Chris@16 166 template <typename T>
Chris@16 167 struct map_vertex_to_
Chris@16 168 {
Chris@16 169 typedef iterator_property_map
Chris@16 170 <typename std::vector<T>::iterator, VertexIndexMap> type;
Chris@16 171 };
Chris@16 172
Chris@16 173 typedef typename map_vertex_to_<v_size_t>::type vertex_to_v_size_map_t;
Chris@16 174 typedef typename map_vertex_to_<vertex_t>::type vertex_to_vertex_map_t;
Chris@16 175 typedef typename map_vertex_to_<edge_t>::type vertex_to_edge_map_t;
Chris@16 176 typedef typename map_vertex_to_<vertex_list_ptr_t>::type
Chris@16 177 vertex_to_vertex_list_ptr_map_t;
Chris@16 178 typedef typename map_vertex_to_< edge_vector_t >::type
Chris@16 179 vertex_to_edge_vector_map_t;
Chris@16 180 typedef typename map_vertex_to_<bool>::type vertex_to_bool_map_t;
Chris@16 181 typedef typename map_vertex_to_<face_handle_t>::type
Chris@16 182 vertex_to_face_handle_map_t;
Chris@16 183 typedef typename map_vertex_to_<face_handle_list_ptr_t>::type
Chris@16 184 vertex_to_face_handle_list_ptr_map_t;
Chris@16 185 typedef typename map_vertex_to_<typename vertex_list_t::iterator>::type
Chris@16 186 vertex_to_separated_node_map_t;
Chris@16 187
Chris@16 188 template <typename BicompSideToTraverse = single_side,
Chris@16 189 typename VisitorType = lead_visitor,
Chris@16 190 typename Time = current_iteration>
Chris@16 191 struct face_vertex_iterator
Chris@16 192 {
Chris@16 193 typedef face_iterator<Graph,
Chris@16 194 vertex_to_face_handle_map_t,
Chris@16 195 vertex_t,
Chris@16 196 BicompSideToTraverse,
Chris@16 197 VisitorType,
Chris@16 198 Time>
Chris@16 199 type;
Chris@16 200 };
Chris@16 201
Chris@16 202 template <typename BicompSideToTraverse = single_side,
Chris@16 203 typename Time = current_iteration>
Chris@16 204 struct face_edge_iterator
Chris@16 205 {
Chris@16 206 typedef face_iterator<Graph,
Chris@16 207 vertex_to_face_handle_map_t,
Chris@16 208 edge_t,
Chris@16 209 BicompSideToTraverse,
Chris@16 210 lead_visitor,
Chris@16 211 Time>
Chris@16 212 type;
Chris@16 213 };
Chris@16 214
Chris@16 215
Chris@16 216
Chris@16 217 public:
Chris@16 218
Chris@16 219
Chris@16 220
Chris@16 221 boyer_myrvold_impl(const Graph& arg_g, VertexIndexMap arg_vm):
Chris@16 222 g(arg_g),
Chris@16 223 vm(arg_vm),
Chris@16 224
Chris@16 225 low_point_vector(num_vertices(g)),
Chris@16 226 dfs_parent_vector(num_vertices(g)),
Chris@16 227 dfs_number_vector(num_vertices(g)),
Chris@16 228 least_ancestor_vector(num_vertices(g)),
Chris@16 229 pertinent_roots_vector(num_vertices(g)),
Chris@16 230 backedge_flag_vector(num_vertices(g), num_vertices(g) + 1),
Chris@16 231 visited_vector(num_vertices(g), num_vertices(g) + 1),
Chris@16 232 face_handles_vector(num_vertices(g)),
Chris@16 233 dfs_child_handles_vector(num_vertices(g)),
Chris@16 234 separated_dfs_child_list_vector(num_vertices(g)),
Chris@16 235 separated_node_in_parent_list_vector(num_vertices(g)),
Chris@16 236 canonical_dfs_child_vector(num_vertices(g)),
Chris@16 237 flipped_vector(num_vertices(g), false),
Chris@16 238 backedges_vector(num_vertices(g)),
Chris@16 239 dfs_parent_edge_vector(num_vertices(g)),
Chris@16 240
Chris@16 241 vertices_by_dfs_num(num_vertices(g)),
Chris@16 242
Chris@16 243 low_point(low_point_vector.begin(), vm),
Chris@16 244 dfs_parent(dfs_parent_vector.begin(), vm),
Chris@16 245 dfs_number(dfs_number_vector.begin(), vm),
Chris@16 246 least_ancestor(least_ancestor_vector.begin(), vm),
Chris@16 247 pertinent_roots(pertinent_roots_vector.begin(), vm),
Chris@16 248 backedge_flag(backedge_flag_vector.begin(), vm),
Chris@16 249 visited(visited_vector.begin(), vm),
Chris@16 250 face_handles(face_handles_vector.begin(), vm),
Chris@16 251 dfs_child_handles(dfs_child_handles_vector.begin(), vm),
Chris@16 252 separated_dfs_child_list(separated_dfs_child_list_vector.begin(), vm),
Chris@16 253 separated_node_in_parent_list
Chris@16 254 (separated_node_in_parent_list_vector.begin(), vm),
Chris@16 255 canonical_dfs_child(canonical_dfs_child_vector.begin(), vm),
Chris@16 256 flipped(flipped_vector.begin(), vm),
Chris@16 257 backedges(backedges_vector.begin(), vm),
Chris@16 258 dfs_parent_edge(dfs_parent_edge_vector.begin(), vm)
Chris@16 259
Chris@16 260 {
Chris@16 261
Chris@16 262 planar_dfs_visitor
Chris@16 263 <vertex_to_v_size_map_t, vertex_to_vertex_map_t,
Chris@16 264 vertex_to_v_size_map_t, vertex_to_v_size_map_t,
Chris@16 265 vertex_to_edge_map_t, v_size_t> vis
Chris@16 266 (low_point, dfs_parent, dfs_number, least_ancestor, dfs_parent_edge);
Chris@16 267
Chris@16 268 // Perform a depth-first search to find each vertex's low point, least
Chris@16 269 // ancestor, and dfs tree information
Chris@16 270 depth_first_search(g, visitor(vis).vertex_index_map(vm));
Chris@16 271
Chris@16 272 // Sort vertices by their lowpoint - need this later in the constructor
Chris@16 273 vertex_vector_t vertices_by_lowpoint(num_vertices(g));
Chris@16 274 std::copy( vertices(g).first, vertices(g).second,
Chris@16 275 vertices_by_lowpoint.begin()
Chris@16 276 );
Chris@16 277 bucket_sort(vertices_by_lowpoint.begin(),
Chris@16 278 vertices_by_lowpoint.end(),
Chris@16 279 low_point,
Chris@16 280 num_vertices(g)
Chris@16 281 );
Chris@16 282
Chris@16 283 // Sort vertices by their dfs number - need this to iterate by reverse
Chris@16 284 // DFS number in the main loop.
Chris@16 285 std::copy( vertices(g).first, vertices(g).second,
Chris@16 286 vertices_by_dfs_num.begin()
Chris@16 287 );
Chris@16 288 bucket_sort(vertices_by_dfs_num.begin(),
Chris@16 289 vertices_by_dfs_num.end(),
Chris@16 290 dfs_number,
Chris@16 291 num_vertices(g)
Chris@16 292 );
Chris@16 293
Chris@16 294 // Initialize face handles. A face handle is an abstraction that serves
Chris@16 295 // two uses in our implementation - it allows us to efficiently move
Chris@16 296 // along the outer face of embedded bicomps in a partially embedded
Chris@16 297 // graph, and it provides storage for the planar embedding. Face
Chris@16 298 // handles are implemented by a sequence of edges and are associated
Chris@16 299 // with a particular vertex - the sequence of edges represents the
Chris@16 300 // current embedding of edges around that vertex, and the first and
Chris@16 301 // last edges in the sequence represent the pair of edges on the outer
Chris@16 302 // face that are adjacent to the associated vertex. This lets us embed
Chris@16 303 // edges in the graph by just pushing them on the front or back of the
Chris@16 304 // sequence of edges held by the face handles.
Chris@16 305 //
Chris@16 306 // Our algorithm starts with a DFS tree of edges (where every vertex is
Chris@16 307 // an articulation point and every edge is a singleton bicomp) and
Chris@16 308 // repeatedly merges bicomps by embedding additional edges. Note that
Chris@16 309 // any bicomp at any point in the algorithm can be associated with a
Chris@16 310 // unique edge connecting the vertex of that bicomp with the lowest DFS
Chris@16 311 // number (which we refer to as the "root" of the bicomp) with its DFS
Chris@16 312 // child in the bicomp: the existence of two such edges would contradict
Chris@16 313 // the properties of a DFS tree. We refer to the DFS child of the root
Chris@16 314 // of a bicomp as the "canonical DFS child" of the bicomp. Note that a
Chris@16 315 // vertex can be the root of more than one bicomp.
Chris@16 316 //
Chris@16 317 // We move around the external faces of a bicomp using a few property
Chris@16 318 // maps, which we'll initialize presently:
Chris@16 319 //
Chris@16 320 // - face_handles: maps a vertex to a face handle that can be used to
Chris@16 321 // move "up" a bicomp. For a vertex that isn't an articulation point,
Chris@16 322 // this holds the face handles that can be used to move around that
Chris@16 323 // vertex's unique bicomp. For a vertex that is an articulation point,
Chris@16 324 // this holds the face handles associated with the unique bicomp that
Chris@16 325 // the vertex is NOT the root of. These handles can therefore be used
Chris@16 326 // to move from any point on the outer face of the tree of bicomps
Chris@16 327 // around the current outer face towards the root of the DFS tree.
Chris@16 328 //
Chris@16 329 // - dfs_child_handles: these are used to hold face handles for
Chris@16 330 // vertices that are articulation points - dfs_child_handles[v] holds
Chris@16 331 // the face handles corresponding to vertex u in the bicomp with root
Chris@16 332 // u and canonical DFS child v.
Chris@16 333 //
Chris@16 334 // - canonical_dfs_child: this property map allows one to determine the
Chris@16 335 // canonical DFS child of a bicomp while traversing the outer face.
Chris@16 336 // This property map is only valid when applied to one of the two
Chris@16 337 // vertices adjacent to the root of the bicomp on the outer face. To
Chris@16 338 // be more precise, if v is the canonical DFS child of a bicomp,
Chris@16 339 // canonical_dfs_child[dfs_child_handles[v].first_vertex()] == v and
Chris@16 340 // canonical_dfs_child[dfs_child_handles[v].second_vertex()] == v.
Chris@16 341 //
Chris@16 342 // - pertinent_roots: given a vertex v, pertinent_roots[v] contains a
Chris@16 343 // list of face handles pointing to the top of bicomps that need to
Chris@16 344 // be visited by the current walkdown traversal (since they lead to
Chris@16 345 // backedges that need to be embedded). These lists are populated by
Chris@16 346 // the walkup and consumed by the walkdown.
Chris@16 347
Chris@16 348 vertex_iterator_t vi, vi_end;
Chris@16 349 for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
Chris@16 350 {
Chris@16 351 vertex_t v(*vi);
Chris@16 352 vertex_t parent = dfs_parent[v];
Chris@16 353
Chris@16 354 if (parent != v)
Chris@16 355 {
Chris@16 356 edge_t parent_edge = dfs_parent_edge[v];
Chris@16 357 add_to_embedded_edges(parent_edge, StoreOldHandlesPolicy());
Chris@16 358 face_handles[v] = face_handle_t(v, parent_edge, g);
Chris@16 359 dfs_child_handles[v] = face_handle_t(parent, parent_edge, g);
Chris@16 360 }
Chris@16 361 else
Chris@16 362 {
Chris@16 363 face_handles[v] = face_handle_t(v);
Chris@16 364 dfs_child_handles[v] = face_handle_t(parent);
Chris@16 365 }
Chris@16 366
Chris@16 367 canonical_dfs_child[v] = v;
Chris@16 368 pertinent_roots[v] = face_handle_list_ptr_t(new face_handle_list_t);
Chris@16 369 separated_dfs_child_list[v] = vertex_list_ptr_t(new vertex_list_t);
Chris@16 370
Chris@16 371 }
Chris@16 372
Chris@16 373 // We need to create a list of not-yet-merged depth-first children for
Chris@16 374 // each vertex that will be updated as bicomps get merged. We sort each
Chris@16 375 // list by ascending lowpoint, which allows the externally_active
Chris@16 376 // function to run in constant time, and we keep a pointer to each
Chris@16 377 // vertex's representation in its parent's list, which allows merging
Chris@16 378 //in constant time.
Chris@16 379
Chris@16 380 for(typename vertex_vector_t::iterator itr =
Chris@16 381 vertices_by_lowpoint.begin();
Chris@16 382 itr != vertices_by_lowpoint.end(); ++itr)
Chris@16 383 {
Chris@16 384 vertex_t v(*itr);
Chris@16 385 vertex_t parent(dfs_parent[v]);
Chris@16 386 if (v != parent)
Chris@16 387 {
Chris@16 388 separated_node_in_parent_list[v] =
Chris@16 389 separated_dfs_child_list[parent]->insert
Chris@16 390 (separated_dfs_child_list[parent]->end(), v);
Chris@16 391 }
Chris@16 392 }
Chris@16 393
Chris@16 394 // The merge stack holds path information during a walkdown iteration
Chris@16 395 merge_stack.reserve(num_vertices(g));
Chris@16 396
Chris@16 397 }
Chris@16 398
Chris@16 399
Chris@16 400
Chris@16 401
Chris@16 402
Chris@16 403
Chris@16 404 bool is_planar()
Chris@16 405 {
Chris@16 406
Chris@16 407 // This is the main algorithm: starting with a DFS tree of embedded
Chris@16 408 // edges (which, since it's a tree, is planar), iterate through all
Chris@16 409 // vertices by reverse DFS number, attempting to embed all backedges
Chris@16 410 // connecting the current vertex to vertices with higher DFS numbers.
Chris@16 411 //
Chris@16 412 // The walkup is a procedure that examines all such backedges and sets
Chris@16 413 // up the required data structures so that they can be searched by the
Chris@16 414 // walkdown in linear time. The walkdown does the actual work of
Chris@16 415 // embedding edges and flipping bicomps, and can identify when it has
Chris@16 416 // come across a kuratowski subgraph.
Chris@16 417 //
Chris@16 418 // store_old_face_handles caches face handles from the previous
Chris@16 419 // iteration - this is used only for the kuratowski subgraph isolation,
Chris@16 420 // and is therefore dispatched based on the StoreOldHandlesPolicy.
Chris@16 421 //
Chris@16 422 // clean_up_embedding does some clean-up and fills in values that have
Chris@16 423 // to be computed lazily during the actual execution of the algorithm
Chris@16 424 // (for instance, whether or not a bicomp is flipped in the final
Chris@16 425 // embedding). It's dispatched on the the StoreEmbeddingPolicy, since
Chris@16 426 // it's not needed if an embedding isn't desired.
Chris@16 427
Chris@16 428 typename vertex_vector_t::reverse_iterator vi, vi_end;
Chris@16 429
Chris@16 430 vi_end = vertices_by_dfs_num.rend();
Chris@16 431 for(vi = vertices_by_dfs_num.rbegin(); vi != vi_end; ++vi)
Chris@16 432 {
Chris@16 433
Chris@16 434 store_old_face_handles(StoreOldHandlesPolicy());
Chris@16 435
Chris@16 436 vertex_t v(*vi);
Chris@16 437
Chris@16 438 walkup(v);
Chris@16 439
Chris@16 440 if (!walkdown(v))
Chris@16 441 return false;
Chris@16 442
Chris@16 443 }
Chris@16 444
Chris@16 445 clean_up_embedding(StoreEmbeddingPolicy());
Chris@16 446
Chris@16 447 return true;
Chris@16 448
Chris@16 449 }
Chris@16 450
Chris@16 451
Chris@16 452
Chris@16 453
Chris@16 454
Chris@16 455
Chris@16 456 private:
Chris@16 457
Chris@16 458
Chris@16 459
Chris@16 460
Chris@16 461
Chris@16 462 void walkup(vertex_t v)
Chris@16 463 {
Chris@16 464
Chris@16 465 // The point of the walkup is to follow all backedges from v to
Chris@16 466 // vertices with higher DFS numbers, and update pertinent_roots
Chris@16 467 // for the bicomp roots on the path from backedge endpoints up
Chris@16 468 // to v. This will set the stage for the walkdown to efficiently
Chris@16 469 // traverse the graph of bicomps down from v.
Chris@16 470
Chris@16 471 typedef typename face_vertex_iterator<both_sides>::type walkup_iterator_t;
Chris@16 472
Chris@16 473 out_edge_iterator_t oi, oi_end;
Chris@16 474 for(boost::tie(oi,oi_end) = out_edges(v,g); oi != oi_end; ++oi)
Chris@16 475 {
Chris@16 476 edge_t e(*oi);
Chris@16 477 vertex_t e_source(source(e,g));
Chris@16 478 vertex_t e_target(target(e,g));
Chris@16 479
Chris@16 480 if (e_source == e_target)
Chris@16 481 {
Chris@16 482 self_loops.push_back(e);
Chris@16 483 continue;
Chris@16 484 }
Chris@16 485
Chris@16 486 vertex_t w(e_source == v ? e_target : e_source);
Chris@16 487
Chris@16 488 //continue if not a back edge or already embedded
Chris@16 489 if (dfs_number[w] < dfs_number[v] || e == dfs_parent_edge[w])
Chris@16 490 continue;
Chris@16 491
Chris@16 492 backedges[w].push_back(e);
Chris@16 493
Chris@16 494 v_size_t timestamp = dfs_number[v];
Chris@16 495 backedge_flag[w] = timestamp;
Chris@16 496
Chris@16 497 walkup_iterator_t walkup_itr(w, face_handles);
Chris@16 498 walkup_iterator_t walkup_end;
Chris@16 499 vertex_t lead_vertex = w;
Chris@16 500
Chris@16 501 while (true)
Chris@16 502 {
Chris@16 503
Chris@16 504 // Move to the root of the current bicomp or the first visited
Chris@16 505 // vertex on the bicomp by going up each side in parallel
Chris@16 506
Chris@16 507 while(walkup_itr != walkup_end &&
Chris@16 508 visited[*walkup_itr] != timestamp
Chris@16 509 )
Chris@16 510 {
Chris@16 511 lead_vertex = *walkup_itr;
Chris@16 512 visited[lead_vertex] = timestamp;
Chris@16 513 ++walkup_itr;
Chris@16 514 }
Chris@16 515
Chris@16 516 // If we've found the root of a bicomp through a path we haven't
Chris@16 517 // seen before, update pertinent_roots with a handle to the
Chris@16 518 // current bicomp. Otherwise, we've just seen a path we've been
Chris@16 519 // up before, so break out of the main while loop.
Chris@16 520
Chris@16 521 if (walkup_itr == walkup_end)
Chris@16 522 {
Chris@16 523 vertex_t dfs_child = canonical_dfs_child[lead_vertex];
Chris@16 524 vertex_t parent = dfs_parent[dfs_child];
Chris@16 525
Chris@16 526 visited[dfs_child_handles[dfs_child].first_vertex()]
Chris@16 527 = timestamp;
Chris@16 528 visited[dfs_child_handles[dfs_child].second_vertex()]
Chris@16 529 = timestamp;
Chris@16 530
Chris@16 531 if (low_point[dfs_child] < dfs_number[v] ||
Chris@16 532 least_ancestor[dfs_child] < dfs_number[v]
Chris@16 533 )
Chris@16 534 {
Chris@16 535 pertinent_roots[parent]->push_back
Chris@16 536 (dfs_child_handles[dfs_child]);
Chris@16 537 }
Chris@16 538 else
Chris@16 539 {
Chris@16 540 pertinent_roots[parent]->push_front
Chris@16 541 (dfs_child_handles[dfs_child]);
Chris@16 542 }
Chris@16 543
Chris@16 544 if (parent != v && visited[parent] != timestamp)
Chris@16 545 {
Chris@16 546 walkup_itr = walkup_iterator_t(parent, face_handles);
Chris@16 547 lead_vertex = parent;
Chris@16 548 }
Chris@16 549 else
Chris@16 550 break;
Chris@16 551 }
Chris@16 552 else
Chris@16 553 break;
Chris@16 554 }
Chris@16 555
Chris@16 556 }
Chris@16 557
Chris@16 558 }
Chris@16 559
Chris@16 560
Chris@16 561
Chris@16 562
Chris@16 563
Chris@16 564
Chris@16 565
Chris@16 566 bool walkdown(vertex_t v)
Chris@16 567 {
Chris@16 568 // This procedure is where all of the action is - pertinent_roots
Chris@16 569 // has already been set up by the walkup, so we just need to move
Chris@16 570 // down bicomps from v until we find vertices that have been
Chris@16 571 // labeled as backedge endpoints. Once we find such a vertex, we
Chris@16 572 // embed the corresponding edge and glue together the bicomps on
Chris@16 573 // the path connecting the two vertices in the edge. This may
Chris@16 574 // involve flipping bicomps along the way.
Chris@16 575
Chris@16 576 vertex_t w; //the other endpoint of the edge we're embedding
Chris@16 577
Chris@16 578 while (!pertinent_roots[v]->empty())
Chris@16 579 {
Chris@16 580
Chris@16 581 face_handle_t root_face_handle = pertinent_roots[v]->front();
Chris@16 582 face_handle_t curr_face_handle = root_face_handle;
Chris@16 583 pertinent_roots[v]->pop_front();
Chris@16 584
Chris@16 585 merge_stack.clear();
Chris@16 586
Chris@16 587 while(true)
Chris@16 588 {
Chris@16 589
Chris@16 590 typename face_vertex_iterator<>::type
Chris@16 591 first_face_itr, second_face_itr, face_end;
Chris@16 592 vertex_t first_side_vertex
Chris@16 593 = graph_traits<Graph>::null_vertex();
Chris@16 594 vertex_t second_side_vertex;
Chris@16 595 vertex_t first_tail, second_tail;
Chris@16 596
Chris@16 597 first_tail = second_tail = curr_face_handle.get_anchor();
Chris@16 598 first_face_itr = typename face_vertex_iterator<>::type
Chris@16 599 (curr_face_handle, face_handles, first_side());
Chris@16 600 second_face_itr = typename face_vertex_iterator<>::type
Chris@16 601 (curr_face_handle, face_handles, second_side());
Chris@16 602
Chris@16 603 for(; first_face_itr != face_end; ++first_face_itr)
Chris@16 604 {
Chris@16 605 vertex_t face_vertex(*first_face_itr);
Chris@16 606 if (pertinent(face_vertex, v) ||
Chris@16 607 externally_active(face_vertex, v)
Chris@16 608 )
Chris@16 609 {
Chris@16 610 first_side_vertex = face_vertex;
Chris@16 611 second_side_vertex = face_vertex;
Chris@16 612 break;
Chris@16 613 }
Chris@16 614 first_tail = face_vertex;
Chris@16 615 }
Chris@16 616
Chris@16 617 if (first_side_vertex == graph_traits<Graph>::null_vertex() ||
Chris@16 618 first_side_vertex == curr_face_handle.get_anchor()
Chris@16 619 )
Chris@16 620 break;
Chris@16 621
Chris@16 622 for(;second_face_itr != face_end; ++second_face_itr)
Chris@16 623 {
Chris@16 624 vertex_t face_vertex(*second_face_itr);
Chris@16 625 if (pertinent(face_vertex, v) ||
Chris@16 626 externally_active(face_vertex, v)
Chris@16 627 )
Chris@16 628 {
Chris@16 629 second_side_vertex = face_vertex;
Chris@16 630 break;
Chris@16 631 }
Chris@16 632 second_tail = face_vertex;
Chris@16 633 }
Chris@16 634
Chris@16 635 vertex_t chosen;
Chris@16 636 bool chose_first_upper_path;
Chris@16 637 if (internally_active(first_side_vertex, v))
Chris@16 638 {
Chris@16 639 chosen = first_side_vertex;
Chris@16 640 chose_first_upper_path = true;
Chris@16 641 }
Chris@16 642 else if (internally_active(second_side_vertex, v))
Chris@16 643 {
Chris@16 644 chosen = second_side_vertex;
Chris@16 645 chose_first_upper_path = false;
Chris@16 646 }
Chris@16 647 else if (pertinent(first_side_vertex, v))
Chris@16 648 {
Chris@16 649 chosen = first_side_vertex;
Chris@16 650 chose_first_upper_path = true;
Chris@16 651 }
Chris@16 652 else if (pertinent(second_side_vertex, v))
Chris@16 653 {
Chris@16 654 chosen = second_side_vertex;
Chris@16 655 chose_first_upper_path = false;
Chris@16 656 }
Chris@16 657 else
Chris@16 658 {
Chris@16 659
Chris@16 660 // If there's a pertinent vertex on the lower face
Chris@16 661 // between the first_face_itr and the second_face_itr,
Chris@16 662 // this graph isn't planar.
Chris@16 663 for(;
Chris@16 664 *first_face_itr != second_side_vertex;
Chris@16 665 ++first_face_itr
Chris@16 666 )
Chris@16 667 {
Chris@16 668 vertex_t p(*first_face_itr);
Chris@16 669 if (pertinent(p,v))
Chris@16 670 {
Chris@16 671 //Found a Kuratowski subgraph
Chris@16 672 kuratowski_v = v;
Chris@16 673 kuratowski_x = first_side_vertex;
Chris@16 674 kuratowski_y = second_side_vertex;
Chris@16 675 return false;
Chris@16 676 }
Chris@16 677 }
Chris@16 678
Chris@16 679 // Otherwise, the fact that we didn't find a pertinent
Chris@16 680 // vertex on this face is fine - we should set the
Chris@16 681 // short-circuit edges and break out of this loop to
Chris@16 682 // start looking at a different pertinent root.
Chris@16 683
Chris@16 684 if (first_side_vertex == second_side_vertex)
Chris@16 685 {
Chris@16 686 if (first_tail != v)
Chris@16 687 {
Chris@16 688 vertex_t first
Chris@16 689 = face_handles[first_tail].first_vertex();
Chris@16 690 vertex_t second
Chris@16 691 = face_handles[first_tail].second_vertex();
Chris@16 692 boost::tie(first_side_vertex, first_tail)
Chris@16 693 = make_tuple(first_tail,
Chris@16 694 first == first_side_vertex ?
Chris@16 695 second : first
Chris@16 696 );
Chris@16 697 }
Chris@16 698 else if (second_tail != v)
Chris@16 699 {
Chris@16 700 vertex_t first
Chris@16 701 = face_handles[second_tail].first_vertex();
Chris@16 702 vertex_t second
Chris@16 703 = face_handles[second_tail].second_vertex();
Chris@16 704 boost::tie(second_side_vertex, second_tail)
Chris@16 705 = make_tuple(second_tail,
Chris@16 706 first == second_side_vertex ?
Chris@16 707 second : first);
Chris@16 708 }
Chris@16 709 else
Chris@16 710 break;
Chris@16 711 }
Chris@16 712
Chris@16 713 canonical_dfs_child[first_side_vertex]
Chris@16 714 = canonical_dfs_child[root_face_handle.first_vertex()];
Chris@16 715 canonical_dfs_child[second_side_vertex]
Chris@16 716 = canonical_dfs_child[root_face_handle.second_vertex()];
Chris@16 717 root_face_handle.set_first_vertex(first_side_vertex);
Chris@16 718 root_face_handle.set_second_vertex(second_side_vertex);
Chris@16 719
Chris@16 720 if (face_handles[first_side_vertex].first_vertex() ==
Chris@16 721 first_tail
Chris@16 722 )
Chris@16 723 face_handles[first_side_vertex].set_first_vertex(v);
Chris@16 724 else
Chris@16 725 face_handles[first_side_vertex].set_second_vertex(v);
Chris@16 726
Chris@16 727 if (face_handles[second_side_vertex].first_vertex() ==
Chris@16 728 second_tail
Chris@16 729 )
Chris@16 730 face_handles[second_side_vertex].set_first_vertex(v);
Chris@16 731 else
Chris@16 732 face_handles[second_side_vertex].set_second_vertex(v);
Chris@16 733
Chris@16 734 break;
Chris@16 735
Chris@16 736 }
Chris@16 737
Chris@16 738
Chris@16 739 // When we unwind the stack, we need to know which direction
Chris@16 740 // we came down from on the top face handle
Chris@16 741
Chris@16 742 bool chose_first_lower_path =
Chris@16 743 (chose_first_upper_path &&
Chris@16 744 face_handles[chosen].first_vertex() == first_tail)
Chris@16 745 ||
Chris@16 746 (!chose_first_upper_path &&
Chris@16 747 face_handles[chosen].first_vertex() == second_tail);
Chris@16 748
Chris@16 749 //If there's a backedge at the chosen vertex, embed it now
Chris@16 750 if (backedge_flag[chosen] == dfs_number[v])
Chris@16 751 {
Chris@16 752 w = chosen;
Chris@16 753
Chris@16 754 backedge_flag[chosen] = num_vertices(g) + 1;
Chris@16 755 add_to_merge_points(chosen, StoreOldHandlesPolicy());
Chris@16 756
Chris@16 757 typename edge_vector_t::iterator ei, ei_end;
Chris@16 758 ei_end = backedges[chosen].end();
Chris@16 759 for(ei = backedges[chosen].begin(); ei != ei_end; ++ei)
Chris@16 760 {
Chris@16 761 edge_t e(*ei);
Chris@16 762 add_to_embedded_edges(e, StoreOldHandlesPolicy());
Chris@16 763
Chris@16 764 if (chose_first_lower_path)
Chris@16 765 face_handles[chosen].push_first(e, g);
Chris@16 766 else
Chris@16 767 face_handles[chosen].push_second(e, g);
Chris@16 768 }
Chris@16 769
Chris@16 770 }
Chris@16 771 else
Chris@16 772 {
Chris@16 773 merge_stack.push_back(make_tuple
Chris@16 774 (chosen, chose_first_upper_path, chose_first_lower_path)
Chris@16 775 );
Chris@16 776 curr_face_handle = *pertinent_roots[chosen]->begin();
Chris@16 777 continue;
Chris@16 778 }
Chris@16 779
Chris@16 780 //Unwind the merge stack to the root, merging all bicomps
Chris@16 781
Chris@16 782 bool bottom_path_follows_first;
Chris@16 783 bool top_path_follows_first;
Chris@16 784 bool next_bottom_follows_first = chose_first_upper_path;
Chris@16 785 face_handle_t top_handle, bottom_handle;
Chris@16 786
Chris@16 787 vertex_t merge_point = chosen;
Chris@16 788
Chris@16 789 while(!merge_stack.empty())
Chris@16 790 {
Chris@16 791
Chris@16 792 bottom_path_follows_first = next_bottom_follows_first;
Chris@16 793 boost::tie(merge_point,
Chris@16 794 next_bottom_follows_first,
Chris@16 795 top_path_follows_first
Chris@16 796 ) = merge_stack.back();
Chris@16 797 merge_stack.pop_back();
Chris@16 798
Chris@16 799 face_handle_t top_handle(face_handles[merge_point]);
Chris@16 800 face_handle_t bottom_handle
Chris@16 801 (*pertinent_roots[merge_point]->begin());
Chris@16 802
Chris@16 803 vertex_t bottom_dfs_child = canonical_dfs_child
Chris@16 804 [pertinent_roots[merge_point]->begin()->first_vertex()];
Chris@16 805
Chris@16 806 remove_vertex_from_separated_dfs_child_list(
Chris@16 807 canonical_dfs_child
Chris@16 808 [pertinent_roots[merge_point]->begin()->first_vertex()]
Chris@16 809 );
Chris@16 810
Chris@16 811 pertinent_roots[merge_point]->pop_front();
Chris@16 812
Chris@16 813 add_to_merge_points(top_handle.get_anchor(),
Chris@16 814 StoreOldHandlesPolicy()
Chris@16 815 );
Chris@16 816
Chris@16 817 if (top_path_follows_first && bottom_path_follows_first)
Chris@16 818 {
Chris@16 819 bottom_handle.flip();
Chris@16 820 top_handle.glue_first_to_second(bottom_handle);
Chris@16 821 }
Chris@16 822 else if (!top_path_follows_first &&
Chris@16 823 bottom_path_follows_first
Chris@16 824 )
Chris@16 825 {
Chris@16 826 flipped[bottom_dfs_child] = true;
Chris@16 827 top_handle.glue_second_to_first(bottom_handle);
Chris@16 828 }
Chris@16 829 else if (top_path_follows_first &&
Chris@16 830 !bottom_path_follows_first
Chris@16 831 )
Chris@16 832 {
Chris@16 833 flipped[bottom_dfs_child] = true;
Chris@16 834 top_handle.glue_first_to_second(bottom_handle);
Chris@16 835 }
Chris@16 836 else //!top_path_follows_first && !bottom_path_follows_first
Chris@16 837 {
Chris@16 838 bottom_handle.flip();
Chris@16 839 top_handle.glue_second_to_first(bottom_handle);
Chris@16 840 }
Chris@16 841
Chris@16 842 }
Chris@16 843
Chris@16 844 //Finally, embed all edges (v,w) at their upper end points
Chris@16 845 canonical_dfs_child[w]
Chris@16 846 = canonical_dfs_child[root_face_handle.first_vertex()];
Chris@16 847
Chris@16 848 add_to_merge_points(root_face_handle.get_anchor(),
Chris@16 849 StoreOldHandlesPolicy()
Chris@16 850 );
Chris@16 851
Chris@16 852 typename edge_vector_t::iterator ei, ei_end;
Chris@16 853 ei_end = backedges[chosen].end();
Chris@16 854 for(ei = backedges[chosen].begin(); ei != ei_end; ++ei)
Chris@16 855 {
Chris@16 856 if (next_bottom_follows_first)
Chris@16 857 root_face_handle.push_first(*ei, g);
Chris@16 858 else
Chris@16 859 root_face_handle.push_second(*ei, g);
Chris@16 860 }
Chris@16 861
Chris@16 862 backedges[chosen].clear();
Chris@16 863 curr_face_handle = root_face_handle;
Chris@16 864
Chris@16 865 }//while(true)
Chris@16 866
Chris@16 867 }//while(!pertinent_roots[v]->empty())
Chris@16 868
Chris@16 869 return true;
Chris@16 870
Chris@16 871 }
Chris@16 872
Chris@16 873
Chris@16 874
Chris@16 875
Chris@16 876
Chris@16 877
Chris@16 878 void store_old_face_handles(graph::detail::no_old_handles) {}
Chris@16 879
Chris@16 880 void store_old_face_handles(graph::detail::store_old_handles)
Chris@16 881 {
Chris@16 882 for(typename std::vector<vertex_t>::iterator mp_itr
Chris@16 883 = current_merge_points.begin();
Chris@16 884 mp_itr != current_merge_points.end(); ++mp_itr)
Chris@16 885 {
Chris@16 886 face_handles[*mp_itr].store_old_face_handles();
Chris@16 887 }
Chris@16 888 current_merge_points.clear();
Chris@16 889 }
Chris@16 890
Chris@16 891
Chris@16 892 void add_to_merge_points(vertex_t, graph::detail::no_old_handles) {}
Chris@16 893
Chris@16 894 void add_to_merge_points(vertex_t v, graph::detail::store_old_handles)
Chris@16 895 {
Chris@16 896 current_merge_points.push_back(v);
Chris@16 897 }
Chris@16 898
Chris@16 899
Chris@16 900 void add_to_embedded_edges(edge_t, graph::detail::no_old_handles) {}
Chris@16 901
Chris@16 902 void add_to_embedded_edges(edge_t e, graph::detail::store_old_handles)
Chris@16 903 {
Chris@16 904 embedded_edges.push_back(e);
Chris@16 905 }
Chris@16 906
Chris@16 907
Chris@16 908
Chris@16 909
Chris@16 910 void clean_up_embedding(graph::detail::no_embedding) {}
Chris@16 911
Chris@16 912 void clean_up_embedding(graph::detail::store_embedding)
Chris@16 913 {
Chris@16 914
Chris@16 915 // If the graph isn't biconnected, we'll still have entries
Chris@16 916 // in the separated_dfs_child_list for some vertices. Since
Chris@16 917 // these represent articulation points, we can obtain a
Chris@16 918 // planar embedding no matter what order we embed them in.
Chris@16 919
Chris@16 920 vertex_iterator_t xi, xi_end;
Chris@16 921 for(boost::tie(xi,xi_end) = vertices(g); xi != xi_end; ++xi)
Chris@16 922 {
Chris@16 923 if (!separated_dfs_child_list[*xi]->empty())
Chris@16 924 {
Chris@16 925 typename vertex_list_t::iterator yi, yi_end;
Chris@16 926 yi_end = separated_dfs_child_list[*xi]->end();
Chris@16 927 for(yi = separated_dfs_child_list[*xi]->begin();
Chris@16 928 yi != yi_end; ++yi
Chris@16 929 )
Chris@16 930 {
Chris@16 931 dfs_child_handles[*yi].flip();
Chris@16 932 face_handles[*xi].glue_first_to_second
Chris@16 933 (dfs_child_handles[*yi]);
Chris@16 934 }
Chris@16 935 }
Chris@16 936 }
Chris@16 937
Chris@16 938 // Up until this point, we've flipped bicomps lazily by setting
Chris@16 939 // flipped[v] to true if the bicomp rooted at v was flipped (the
Chris@16 940 // lazy aspect of this flip is that all descendents of that vertex
Chris@16 941 // need to have their orientations reversed as well). Now, we
Chris@16 942 // traverse the DFS tree by DFS number and perform the actual
Chris@16 943 // flipping as needed
Chris@16 944
Chris@16 945 typedef typename vertex_vector_t::iterator vertex_vector_itr_t;
Chris@16 946 vertex_vector_itr_t vi_end = vertices_by_dfs_num.end();
Chris@16 947 for(vertex_vector_itr_t vi = vertices_by_dfs_num.begin();
Chris@16 948 vi != vi_end; ++vi
Chris@16 949 )
Chris@16 950 {
Chris@16 951 vertex_t v(*vi);
Chris@16 952 bool v_flipped = flipped[v];
Chris@16 953 bool p_flipped = flipped[dfs_parent[v]];
Chris@16 954 if (v_flipped && !p_flipped)
Chris@16 955 {
Chris@16 956 face_handles[v].flip();
Chris@16 957 }
Chris@16 958 else if (p_flipped && !v_flipped)
Chris@16 959 {
Chris@16 960 face_handles[v].flip();
Chris@16 961 flipped[v] = true;
Chris@16 962 }
Chris@16 963 else
Chris@16 964 {
Chris@16 965 flipped[v] = false;
Chris@16 966 }
Chris@16 967 }
Chris@16 968
Chris@16 969 // If there are any self-loops in the graph, they were flagged
Chris@16 970 // during the walkup, and we should add them to the embedding now.
Chris@16 971 // Adding a self loop anywhere in the embedding could never
Chris@16 972 // invalidate the embedding, but they would complicate the traversal
Chris@16 973 // if they were added during the walkup/walkdown.
Chris@16 974
Chris@16 975 typename edge_vector_t::iterator ei, ei_end;
Chris@16 976 ei_end = self_loops.end();
Chris@16 977 for(ei = self_loops.begin(); ei != ei_end; ++ei)
Chris@16 978 {
Chris@16 979 edge_t e(*ei);
Chris@16 980 face_handles[source(e,g)].push_second(e,g);
Chris@16 981 }
Chris@16 982
Chris@16 983 }
Chris@16 984
Chris@16 985
Chris@16 986
Chris@16 987
Chris@16 988
Chris@16 989 bool pertinent(vertex_t w, vertex_t v)
Chris@16 990 {
Chris@16 991 // w is pertinent with respect to v if there is a backedge (v,w) or if
Chris@16 992 // w is the root of a bicomp that contains a pertinent vertex.
Chris@16 993
Chris@16 994 return backedge_flag[w] == dfs_number[v] || !pertinent_roots[w]->empty();
Chris@16 995 }
Chris@16 996
Chris@16 997
Chris@16 998
Chris@16 999 bool externally_active(vertex_t w, vertex_t v)
Chris@16 1000 {
Chris@16 1001 // Let a be any proper depth-first search ancestor of v. w is externally
Chris@16 1002 // active with respect to v if there exists a backedge (a,w) or a
Chris@16 1003 // backedge (a,w_0) for some w_0 in a descendent bicomp of w.
Chris@16 1004
Chris@16 1005 v_size_t dfs_number_of_v = dfs_number[v];
Chris@16 1006 return (least_ancestor[w] < dfs_number_of_v) ||
Chris@16 1007 (!separated_dfs_child_list[w]->empty() &&
Chris@16 1008 low_point[separated_dfs_child_list[w]->front()] < dfs_number_of_v);
Chris@16 1009 }
Chris@16 1010
Chris@16 1011
Chris@16 1012
Chris@16 1013 bool internally_active(vertex_t w, vertex_t v)
Chris@16 1014 {
Chris@16 1015 return pertinent(w,v) && !externally_active(w,v);
Chris@16 1016 }
Chris@16 1017
Chris@16 1018
Chris@16 1019
Chris@16 1020
Chris@16 1021 void remove_vertex_from_separated_dfs_child_list(vertex_t v)
Chris@16 1022 {
Chris@16 1023 typename vertex_list_t::iterator to_delete
Chris@16 1024 = separated_node_in_parent_list[v];
Chris@16 1025 garbage.splice(garbage.end(),
Chris@16 1026 *separated_dfs_child_list[dfs_parent[v]],
Chris@16 1027 to_delete,
Chris@16 1028 boost::next(to_delete)
Chris@16 1029 );
Chris@16 1030 }
Chris@16 1031
Chris@16 1032
Chris@16 1033
Chris@16 1034
Chris@16 1035
Chris@16 1036 // End of the implementation of the basic Boyer-Myrvold Algorithm. The rest
Chris@16 1037 // of the code below implements the isolation of a Kuratowski subgraph in
Chris@16 1038 // the case that the input graph is not planar. This is by far the most
Chris@16 1039 // complicated part of the implementation.
Chris@16 1040
Chris@16 1041
Chris@16 1042
Chris@16 1043
Chris@16 1044 public:
Chris@16 1045
Chris@16 1046
Chris@16 1047
Chris@16 1048
Chris@16 1049 template <typename EdgeToBoolPropertyMap, typename EdgeContainer>
Chris@16 1050 vertex_t kuratowski_walkup(vertex_t v,
Chris@16 1051 EdgeToBoolPropertyMap forbidden_edge,
Chris@16 1052 EdgeToBoolPropertyMap goal_edge,
Chris@16 1053 EdgeToBoolPropertyMap is_embedded,
Chris@16 1054 EdgeContainer& path_edges
Chris@16 1055 )
Chris@16 1056 {
Chris@16 1057 vertex_t current_endpoint;
Chris@16 1058 bool seen_goal_edge = false;
Chris@16 1059 out_edge_iterator_t oi, oi_end;
Chris@16 1060
Chris@16 1061 for(boost::tie(oi,oi_end) = out_edges(v,g); oi != oi_end; ++oi)
Chris@16 1062 forbidden_edge[*oi] = true;
Chris@16 1063
Chris@16 1064 for(boost::tie(oi,oi_end) = out_edges(v,g); oi != oi_end; ++oi)
Chris@16 1065 {
Chris@16 1066 path_edges.clear();
Chris@16 1067
Chris@16 1068 edge_t e(*oi);
Chris@16 1069 current_endpoint = target(*oi,g) == v ?
Chris@16 1070 source(*oi,g) : target(*oi,g);
Chris@16 1071
Chris@16 1072 if (dfs_number[current_endpoint] < dfs_number[v] ||
Chris@16 1073 is_embedded[e] ||
Chris@16 1074 v == current_endpoint //self-loop
Chris@16 1075 )
Chris@16 1076 {
Chris@16 1077 //Not a backedge
Chris@16 1078 continue;
Chris@16 1079 }
Chris@16 1080
Chris@16 1081 path_edges.push_back(e);
Chris@16 1082 if (goal_edge[e])
Chris@16 1083 {
Chris@16 1084 return current_endpoint;
Chris@16 1085 }
Chris@16 1086
Chris@16 1087 typedef typename face_edge_iterator<>::type walkup_itr_t;
Chris@16 1088
Chris@16 1089 walkup_itr_t
Chris@16 1090 walkup_itr(current_endpoint, face_handles, first_side());
Chris@16 1091 walkup_itr_t walkup_end;
Chris@16 1092
Chris@16 1093 seen_goal_edge = false;
Chris@16 1094
Chris@16 1095 while (true)
Chris@16 1096 {
Chris@16 1097
Chris@16 1098 if (walkup_itr != walkup_end && forbidden_edge[*walkup_itr])
Chris@16 1099 break;
Chris@16 1100
Chris@16 1101 while(walkup_itr != walkup_end &&
Chris@16 1102 !goal_edge[*walkup_itr] &&
Chris@16 1103 !forbidden_edge[*walkup_itr]
Chris@16 1104 )
Chris@16 1105 {
Chris@16 1106 edge_t f(*walkup_itr);
Chris@16 1107 forbidden_edge[f] = true;
Chris@16 1108 path_edges.push_back(f);
Chris@16 1109 current_endpoint =
Chris@16 1110 source(f, g) == current_endpoint ?
Chris@16 1111 target(f, g) :
Chris@16 1112 source(f,g);
Chris@16 1113 ++walkup_itr;
Chris@16 1114 }
Chris@16 1115
Chris@16 1116 if (walkup_itr != walkup_end && goal_edge[*walkup_itr])
Chris@16 1117 {
Chris@16 1118 path_edges.push_back(*walkup_itr);
Chris@16 1119 seen_goal_edge = true;
Chris@16 1120 break;
Chris@16 1121 }
Chris@16 1122
Chris@16 1123 walkup_itr
Chris@16 1124 = walkup_itr_t(current_endpoint, face_handles, first_side());
Chris@16 1125
Chris@16 1126 }
Chris@16 1127
Chris@16 1128 if (seen_goal_edge)
Chris@16 1129 break;
Chris@16 1130
Chris@16 1131 }
Chris@16 1132
Chris@16 1133 if (seen_goal_edge)
Chris@16 1134 return current_endpoint;
Chris@16 1135 else
Chris@16 1136 return graph_traits<Graph>::null_vertex();
Chris@16 1137
Chris@16 1138 }
Chris@16 1139
Chris@16 1140
Chris@16 1141
Chris@16 1142
Chris@16 1143
Chris@16 1144
Chris@16 1145
Chris@16 1146
Chris@16 1147 template <typename OutputIterator, typename EdgeIndexMap>
Chris@16 1148 void extract_kuratowski_subgraph(OutputIterator o_itr, EdgeIndexMap em)
Chris@16 1149 {
Chris@16 1150
Chris@16 1151 // If the main algorithm has failed to embed one of the back-edges from
Chris@16 1152 // a vertex v, we can use the current state of the algorithm to isolate
Chris@16 1153 // a Kuratowksi subgraph. The isolation process breaks down into five
Chris@16 1154 // cases, A - E. The general configuration of all five cases is shown in
Chris@16 1155 // figure 1. There is a vertex v from which the planar
Chris@16 1156 // v embedding process could not proceed. This means that
Chris@16 1157 // | there exists some bicomp containing three vertices
Chris@16 1158 // ----- x,y, and z as shown such that x and y are externally
Chris@16 1159 // | | active with respect to v (which means that there are
Chris@16 1160 // x y two vertices x_0 and y_0 such that (1) both x_0 and
Chris@16 1161 // | | y_0 are proper depth-first search ancestors of v and
Chris@16 1162 // --z-- (2) there are two disjoint paths, one connecting x
Chris@16 1163 // and x_0 and one connecting y and y_0, both consisting
Chris@16 1164 // fig. 1 entirely of unembedded edges). Furthermore, there
Chris@16 1165 // exists a vertex z_0 such that z is a depth-first
Chris@16 1166 // search ancestor of z_0 and (v,z_0) is an unembedded back-edge from v.
Chris@16 1167 // x,y and z all exist on the same bicomp, which consists entirely of
Chris@16 1168 // embedded edges. The five subcases break down as follows, and are
Chris@16 1169 // handled by the algorithm logically in the order A-E: First, if v is
Chris@16 1170 // not on the same bicomp as x,y, and z, a K_3_3 can be isolated - this
Chris@16 1171 // is case A. So, we'll assume that v is on the same bicomp as x,y, and
Chris@16 1172 // z. If z_0 is on a different bicomp than x,y, and z, a K_3_3 can also
Chris@16 1173 // be isolated - this is a case B - so we'll assume from now on that v
Chris@16 1174 // is on the same bicomp as x, y, and z=z_0. In this case, one can use
Chris@16 1175 // properties of the Boyer-Myrvold algorithm to show the existence of an
Chris@16 1176 // "x-y path" connecting some vertex on the "left side" of the x,y,z
Chris@16 1177 // bicomp with some vertex on the "right side" of the bicomp (where the
Chris@16 1178 // left and right are split by a line drawn through v and z.If either of
Chris@16 1179 // the endpoints of the x-y path is above x or y on the bicomp, a K_3_3
Chris@16 1180 // can be isolated - this is a case C. Otherwise, both endpoints are at
Chris@16 1181 // or below x and y on the bicomp. If there is a vertex alpha on the x-y
Chris@16 1182 // path such that alpha is not x or y and there's a path from alpha to v
Chris@16 1183 // that's disjoint from any of the edges on the bicomp and the x-y path,
Chris@16 1184 // a K_3_3 can be isolated - this is a case D. Otherwise, properties of
Chris@16 1185 // the Boyer-Myrvold algorithm can be used to show that another vertex
Chris@16 1186 // w exists on the lower half of the bicomp such that w is externally
Chris@16 1187 // active with respect to v. w can then be used to isolate a K_5 - this
Chris@16 1188 // is the configuration of case E.
Chris@16 1189
Chris@16 1190 vertex_iterator_t vi, vi_end;
Chris@16 1191 edge_iterator_t ei, ei_end;
Chris@16 1192 out_edge_iterator_t oei, oei_end;
Chris@16 1193 typename std::vector<edge_t>::iterator xi, xi_end;
Chris@16 1194
Chris@16 1195 // Clear the short-circuit edges - these are needed for the planar
Chris@16 1196 // testing/embedding algorithm to run in linear time, but they'll
Chris@16 1197 // complicate the kuratowski subgraph isolation
Chris@16 1198 for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
Chris@16 1199 {
Chris@16 1200 face_handles[*vi].reset_vertex_cache();
Chris@16 1201 dfs_child_handles[*vi].reset_vertex_cache();
Chris@16 1202 }
Chris@16 1203
Chris@16 1204 vertex_t v = kuratowski_v;
Chris@16 1205 vertex_t x = kuratowski_x;
Chris@16 1206 vertex_t y = kuratowski_y;
Chris@16 1207
Chris@16 1208 typedef iterator_property_map
Chris@16 1209 <typename std::vector<bool>::iterator, EdgeIndexMap>
Chris@16 1210 edge_to_bool_map_t;
Chris@16 1211
Chris@16 1212 std::vector<bool> is_in_subgraph_vector(num_edges(g), false);
Chris@16 1213 edge_to_bool_map_t is_in_subgraph(is_in_subgraph_vector.begin(), em);
Chris@16 1214
Chris@16 1215 std::vector<bool> is_embedded_vector(num_edges(g), false);
Chris@16 1216 edge_to_bool_map_t is_embedded(is_embedded_vector.begin(), em);
Chris@16 1217
Chris@16 1218 typename std::vector<edge_t>::iterator embedded_itr, embedded_end;
Chris@16 1219 embedded_end = embedded_edges.end();
Chris@16 1220 for(embedded_itr = embedded_edges.begin();
Chris@16 1221 embedded_itr != embedded_end; ++embedded_itr
Chris@16 1222 )
Chris@16 1223 is_embedded[*embedded_itr] = true;
Chris@16 1224
Chris@16 1225 // upper_face_vertex is true for x,y, and all vertices above x and y in
Chris@16 1226 // the bicomp
Chris@16 1227 std::vector<bool> upper_face_vertex_vector(num_vertices(g), false);
Chris@16 1228 vertex_to_bool_map_t upper_face_vertex
Chris@16 1229 (upper_face_vertex_vector.begin(), vm);
Chris@16 1230
Chris@16 1231 std::vector<bool> lower_face_vertex_vector(num_vertices(g), false);
Chris@16 1232 vertex_to_bool_map_t lower_face_vertex
Chris@16 1233 (lower_face_vertex_vector.begin(), vm);
Chris@16 1234
Chris@16 1235 // These next few variable declarations are all things that we need
Chris@16 1236 // to find.
Chris@16 1237 vertex_t z;
Chris@16 1238 vertex_t bicomp_root;
Chris@16 1239 vertex_t w = graph_traits<Graph>::null_vertex();
Chris@16 1240 face_handle_t w_handle;
Chris@16 1241 face_handle_t v_dfchild_handle;
Chris@16 1242 vertex_t first_x_y_path_endpoint = graph_traits<Graph>::null_vertex();
Chris@16 1243 vertex_t second_x_y_path_endpoint = graph_traits<Graph>::null_vertex();
Chris@16 1244 vertex_t w_ancestor = v;
Chris@16 1245
Chris@16 1246 detail::bm_case_t chosen_case = detail::BM_NO_CASE_CHOSEN;
Chris@16 1247
Chris@16 1248 std::vector<edge_t> x_external_path;
Chris@16 1249 std::vector<edge_t> y_external_path;
Chris@16 1250 std::vector<edge_t> case_d_edges;
Chris@16 1251
Chris@16 1252 std::vector<edge_t> z_v_path;
Chris@16 1253 std::vector<edge_t> w_path;
Chris@16 1254
Chris@16 1255 //first, use a walkup to find a path from V that starts with a
Chris@16 1256 //backedge from V, then goes up until it hits either X or Y
Chris@16 1257 //(but doesn't find X or Y as the root of a bicomp)
Chris@16 1258
Chris@16 1259 typename face_vertex_iterator<>::type
Chris@16 1260 x_upper_itr(x, face_handles, first_side());
Chris@16 1261 typename face_vertex_iterator<>::type
Chris@16 1262 x_lower_itr(x, face_handles, second_side());
Chris@16 1263 typename face_vertex_iterator<>::type face_itr, face_end;
Chris@16 1264
Chris@16 1265 // Don't know which path from x is the upper or lower path -
Chris@16 1266 // we'll find out here
Chris@16 1267 for(face_itr = x_upper_itr; face_itr != face_end; ++face_itr)
Chris@16 1268 {
Chris@16 1269 if (*face_itr == y)
Chris@16 1270 {
Chris@16 1271 std::swap(x_upper_itr, x_lower_itr);
Chris@16 1272 break;
Chris@16 1273 }
Chris@16 1274 }
Chris@16 1275
Chris@16 1276 upper_face_vertex[x] = true;
Chris@16 1277
Chris@16 1278 vertex_t current_vertex = x;
Chris@16 1279 vertex_t previous_vertex;
Chris@16 1280 for(face_itr = x_upper_itr; face_itr != face_end; ++face_itr)
Chris@16 1281 {
Chris@16 1282 previous_vertex = current_vertex;
Chris@16 1283 current_vertex = *face_itr;
Chris@16 1284 upper_face_vertex[current_vertex] = true;
Chris@16 1285 }
Chris@16 1286
Chris@16 1287 v_dfchild_handle
Chris@16 1288 = dfs_child_handles[canonical_dfs_child[previous_vertex]];
Chris@16 1289
Chris@16 1290 for(face_itr = x_lower_itr; *face_itr != y; ++face_itr)
Chris@16 1291 {
Chris@16 1292 vertex_t current_vertex(*face_itr);
Chris@16 1293 lower_face_vertex[current_vertex] = true;
Chris@16 1294
Chris@16 1295 typename face_handle_list_t::iterator roots_itr, roots_end;
Chris@16 1296
Chris@16 1297 if (w == graph_traits<Graph>::null_vertex()) //haven't found a w yet
Chris@16 1298 {
Chris@16 1299 roots_end = pertinent_roots[current_vertex]->end();
Chris@16 1300 for(roots_itr = pertinent_roots[current_vertex]->begin();
Chris@16 1301 roots_itr != roots_end; ++roots_itr
Chris@16 1302 )
Chris@16 1303 {
Chris@16 1304 if (low_point[canonical_dfs_child[roots_itr->first_vertex()]]
Chris@16 1305 < dfs_number[v]
Chris@16 1306 )
Chris@16 1307 {
Chris@16 1308 w = current_vertex;
Chris@16 1309 w_handle = *roots_itr;
Chris@16 1310 break;
Chris@16 1311 }
Chris@16 1312 }
Chris@16 1313 }
Chris@16 1314
Chris@16 1315 }
Chris@16 1316
Chris@16 1317 for(; face_itr != face_end; ++face_itr)
Chris@16 1318 {
Chris@16 1319 vertex_t current_vertex(*face_itr);
Chris@16 1320 upper_face_vertex[current_vertex] = true;
Chris@16 1321 bicomp_root = current_vertex;
Chris@16 1322 }
Chris@16 1323
Chris@16 1324 typedef typename face_edge_iterator<>::type walkup_itr_t;
Chris@16 1325
Chris@16 1326 std::vector<bool> outer_face_edge_vector(num_edges(g), false);
Chris@16 1327 edge_to_bool_map_t outer_face_edge(outer_face_edge_vector.begin(), em);
Chris@16 1328
Chris@16 1329 walkup_itr_t walkup_end;
Chris@16 1330 for(walkup_itr_t walkup_itr(x, face_handles, first_side());
Chris@16 1331 walkup_itr != walkup_end; ++walkup_itr
Chris@16 1332 )
Chris@16 1333 {
Chris@16 1334 outer_face_edge[*walkup_itr] = true;
Chris@16 1335 is_in_subgraph[*walkup_itr] = true;
Chris@16 1336 }
Chris@16 1337
Chris@16 1338 for(walkup_itr_t walkup_itr(x, face_handles, second_side());
Chris@16 1339 walkup_itr != walkup_end; ++walkup_itr
Chris@16 1340 )
Chris@16 1341 {
Chris@16 1342 outer_face_edge[*walkup_itr] = true;
Chris@16 1343 is_in_subgraph[*walkup_itr] = true;
Chris@16 1344 }
Chris@16 1345
Chris@16 1346 std::vector<bool> forbidden_edge_vector(num_edges(g), false);
Chris@16 1347 edge_to_bool_map_t forbidden_edge(forbidden_edge_vector.begin(), em);
Chris@16 1348
Chris@16 1349 std::vector<bool> goal_edge_vector(num_edges(g), false);
Chris@16 1350 edge_to_bool_map_t goal_edge(goal_edge_vector.begin(), em);
Chris@16 1351
Chris@16 1352
Chris@16 1353 //Find external path to x and to y
Chris@16 1354
Chris@16 1355 for(boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
Chris@16 1356 {
Chris@16 1357 edge_t e(*ei);
Chris@16 1358 goal_edge[e]
Chris@16 1359 = !outer_face_edge[e] && (source(e,g) == x || target(e,g) == x);
Chris@16 1360 forbidden_edge[*ei] = outer_face_edge[*ei];
Chris@16 1361 }
Chris@16 1362
Chris@16 1363 vertex_t x_ancestor = v;
Chris@16 1364 vertex_t x_endpoint = graph_traits<Graph>::null_vertex();
Chris@16 1365
Chris@16 1366 while(x_endpoint == graph_traits<Graph>::null_vertex())
Chris@16 1367 {
Chris@16 1368 x_ancestor = dfs_parent[x_ancestor];
Chris@16 1369 x_endpoint = kuratowski_walkup(x_ancestor,
Chris@16 1370 forbidden_edge,
Chris@16 1371 goal_edge,
Chris@16 1372 is_embedded,
Chris@16 1373 x_external_path
Chris@16 1374 );
Chris@16 1375
Chris@16 1376 }
Chris@16 1377
Chris@16 1378
Chris@16 1379 for(boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
Chris@16 1380 {
Chris@16 1381 edge_t e(*ei);
Chris@16 1382 goal_edge[e]
Chris@16 1383 = !outer_face_edge[e] && (source(e,g) == y || target(e,g) == y);
Chris@16 1384 forbidden_edge[*ei] = outer_face_edge[*ei];
Chris@16 1385 }
Chris@16 1386
Chris@16 1387 vertex_t y_ancestor = v;
Chris@16 1388 vertex_t y_endpoint = graph_traits<Graph>::null_vertex();
Chris@16 1389
Chris@16 1390 while(y_endpoint == graph_traits<Graph>::null_vertex())
Chris@16 1391 {
Chris@16 1392 y_ancestor = dfs_parent[y_ancestor];
Chris@16 1393 y_endpoint = kuratowski_walkup(y_ancestor,
Chris@16 1394 forbidden_edge,
Chris@16 1395 goal_edge,
Chris@16 1396 is_embedded,
Chris@16 1397 y_external_path
Chris@16 1398 );
Chris@16 1399
Chris@16 1400 }
Chris@16 1401
Chris@16 1402
Chris@16 1403 vertex_t parent, child;
Chris@16 1404
Chris@16 1405 //If v isn't on the same bicomp as x and y, it's a case A
Chris@16 1406 if (bicomp_root != v)
Chris@16 1407 {
Chris@16 1408 chosen_case = detail::BM_CASE_A;
Chris@16 1409
Chris@16 1410 for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
Chris@16 1411 if (lower_face_vertex[*vi])
Chris@16 1412 for(boost::tie(oei,oei_end) = out_edges(*vi,g); oei != oei_end; ++oei)
Chris@16 1413 if(!outer_face_edge[*oei])
Chris@16 1414 goal_edge[*oei] = true;
Chris@16 1415
Chris@16 1416 for(boost::tie(ei,ei_end) = edges(g); ei != ei_end; ++ei)
Chris@16 1417 forbidden_edge[*ei] = outer_face_edge[*ei];
Chris@16 1418
Chris@16 1419 z = kuratowski_walkup
Chris@16 1420 (v, forbidden_edge, goal_edge, is_embedded, z_v_path);
Chris@16 1421
Chris@16 1422 }
Chris@16 1423 else if (w != graph_traits<Graph>::null_vertex())
Chris@16 1424 {
Chris@16 1425 chosen_case = detail::BM_CASE_B;
Chris@16 1426
Chris@16 1427 for(boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
Chris@16 1428 {
Chris@16 1429 edge_t e(*ei);
Chris@16 1430 goal_edge[e] = false;
Chris@16 1431 forbidden_edge[e] = outer_face_edge[e];
Chris@16 1432 }
Chris@16 1433
Chris@16 1434 goal_edge[w_handle.first_edge()] = true;
Chris@16 1435 goal_edge[w_handle.second_edge()] = true;
Chris@16 1436
Chris@16 1437 z = kuratowski_walkup(v,
Chris@16 1438 forbidden_edge,
Chris@16 1439 goal_edge,
Chris@16 1440 is_embedded,
Chris@16 1441 z_v_path
Chris@16 1442 );
Chris@16 1443
Chris@16 1444
Chris@16 1445 for(boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
Chris@16 1446 {
Chris@16 1447 forbidden_edge[*ei] = outer_face_edge[*ei];
Chris@16 1448 }
Chris@16 1449
Chris@16 1450 typename std::vector<edge_t>::iterator pi, pi_end;
Chris@16 1451 pi_end = z_v_path.end();
Chris@16 1452 for(pi = z_v_path.begin(); pi != pi_end; ++pi)
Chris@16 1453 {
Chris@16 1454 goal_edge[*pi] = true;
Chris@16 1455 }
Chris@16 1456
Chris@16 1457 w_ancestor = v;
Chris@16 1458 vertex_t w_endpoint = graph_traits<Graph>::null_vertex();
Chris@16 1459
Chris@16 1460 while(w_endpoint == graph_traits<Graph>::null_vertex())
Chris@16 1461 {
Chris@16 1462 w_ancestor = dfs_parent[w_ancestor];
Chris@16 1463 w_endpoint = kuratowski_walkup(w_ancestor,
Chris@16 1464 forbidden_edge,
Chris@16 1465 goal_edge,
Chris@16 1466 is_embedded,
Chris@16 1467 w_path
Chris@16 1468 );
Chris@16 1469
Chris@16 1470 }
Chris@16 1471
Chris@16 1472 // We really want both the w walkup and the z walkup to finish on
Chris@16 1473 // exactly the same edge, but for convenience (since we don't have
Chris@16 1474 // control over which side of a bicomp a walkup moves up) we've
Chris@16 1475 // defined the walkup to either end at w_handle.first_edge() or
Chris@16 1476 // w_handle.second_edge(). If both walkups ended at different edges,
Chris@16 1477 // we'll do a little surgery on the w walkup path to make it follow
Chris@16 1478 // the other side of the final bicomp.
Chris@16 1479
Chris@16 1480 if ((w_path.back() == w_handle.first_edge() &&
Chris@16 1481 z_v_path.back() == w_handle.second_edge())
Chris@16 1482 ||
Chris@16 1483 (w_path.back() == w_handle.second_edge() &&
Chris@16 1484 z_v_path.back() == w_handle.first_edge())
Chris@16 1485 )
Chris@16 1486 {
Chris@16 1487 walkup_itr_t wi, wi_end;
Chris@16 1488 edge_t final_edge = w_path.back();
Chris@16 1489 vertex_t anchor
Chris@16 1490 = source(final_edge, g) == w_handle.get_anchor() ?
Chris@16 1491 target(final_edge, g) : source(final_edge, g);
Chris@16 1492 if (face_handles[anchor].first_edge() == final_edge)
Chris@16 1493 wi = walkup_itr_t(anchor, face_handles, second_side());
Chris@16 1494 else
Chris@16 1495 wi = walkup_itr_t(anchor, face_handles, first_side());
Chris@16 1496
Chris@16 1497 w_path.pop_back();
Chris@16 1498
Chris@16 1499 for(; wi != wi_end; ++wi)
Chris@16 1500 {
Chris@16 1501 edge_t e(*wi);
Chris@16 1502 if (w_path.back() == e)
Chris@16 1503 w_path.pop_back();
Chris@16 1504 else
Chris@16 1505 w_path.push_back(e);
Chris@16 1506 }
Chris@16 1507 }
Chris@16 1508
Chris@16 1509
Chris@16 1510 }
Chris@16 1511 else
Chris@16 1512 {
Chris@16 1513
Chris@16 1514 //We need to find a valid z, since the x-y path re-defines the lower
Chris@16 1515 //face, and the z we found earlier may now be on the upper face.
Chris@16 1516
Chris@16 1517 chosen_case = detail::BM_CASE_E;
Chris@16 1518
Chris@16 1519
Chris@16 1520 // The z we've used so far is just an externally active vertex on the
Chris@16 1521 // lower face path, but may not be the z we need for a case C, D, or
Chris@16 1522 // E subgraph. the z we need now is any externally active vertex on
Chris@16 1523 // the lower face path with both old_face_handles edges on the outer
Chris@16 1524 // face. Since we know an x-y path exists, such a z must also exist.
Chris@16 1525
Chris@16 1526 //TODO: find this z in the first place.
Chris@16 1527
Chris@16 1528 //find the new z
Chris@16 1529
Chris@16 1530 for(face_itr = x_lower_itr; *face_itr != y; ++face_itr)
Chris@16 1531 {
Chris@16 1532 vertex_t possible_z(*face_itr);
Chris@16 1533 if (pertinent(possible_z,v) &&
Chris@16 1534 outer_face_edge[face_handles[possible_z].old_first_edge()] &&
Chris@16 1535 outer_face_edge[face_handles[possible_z].old_second_edge()]
Chris@16 1536 )
Chris@16 1537 {
Chris@16 1538 z = possible_z;
Chris@16 1539 break;
Chris@16 1540 }
Chris@16 1541 }
Chris@16 1542
Chris@16 1543 //find x-y path, and a w if one exists.
Chris@16 1544
Chris@16 1545 if (externally_active(z,v))
Chris@16 1546 w = z;
Chris@16 1547
Chris@16 1548
Chris@16 1549 typedef typename face_edge_iterator
Chris@16 1550 <single_side, previous_iteration>::type old_face_iterator_t;
Chris@16 1551
Chris@16 1552 old_face_iterator_t
Chris@16 1553 first_old_face_itr(z, face_handles, first_side());
Chris@16 1554 old_face_iterator_t
Chris@16 1555 second_old_face_itr(z, face_handles, second_side());
Chris@16 1556 old_face_iterator_t old_face_itr, old_face_end;
Chris@16 1557
Chris@16 1558 std::vector<old_face_iterator_t> old_face_iterators;
Chris@16 1559 old_face_iterators.push_back(first_old_face_itr);
Chris@16 1560 old_face_iterators.push_back(second_old_face_itr);
Chris@16 1561
Chris@16 1562 std::vector<bool> x_y_path_vertex_vector(num_vertices(g), false);
Chris@16 1563 vertex_to_bool_map_t x_y_path_vertex
Chris@16 1564 (x_y_path_vertex_vector.begin(), vm);
Chris@16 1565
Chris@16 1566 typename std::vector<old_face_iterator_t>::iterator
Chris@16 1567 of_itr, of_itr_end;
Chris@16 1568 of_itr_end = old_face_iterators.end();
Chris@16 1569 for(of_itr = old_face_iterators.begin();
Chris@16 1570 of_itr != of_itr_end; ++of_itr
Chris@16 1571 )
Chris@16 1572 {
Chris@16 1573
Chris@16 1574 old_face_itr = *of_itr;
Chris@16 1575
Chris@16 1576 vertex_t previous_vertex;
Chris@16 1577 bool seen_x_or_y = false;
Chris@16 1578 vertex_t current_vertex = z;
Chris@16 1579 for(; old_face_itr != old_face_end; ++old_face_itr)
Chris@16 1580 {
Chris@16 1581 edge_t e(*old_face_itr);
Chris@16 1582 previous_vertex = current_vertex;
Chris@16 1583 current_vertex = source(e,g) == current_vertex ?
Chris@16 1584 target(e,g) : source(e,g);
Chris@16 1585
Chris@16 1586 if (current_vertex == x || current_vertex == y)
Chris@16 1587 seen_x_or_y = true;
Chris@16 1588
Chris@16 1589 if (w == graph_traits<Graph>::null_vertex() &&
Chris@16 1590 externally_active(current_vertex,v) &&
Chris@16 1591 outer_face_edge[e] &&
Chris@16 1592 outer_face_edge[*boost::next(old_face_itr)] &&
Chris@16 1593 !seen_x_or_y
Chris@16 1594 )
Chris@16 1595 {
Chris@16 1596 w = current_vertex;
Chris@16 1597 }
Chris@16 1598
Chris@16 1599 if (!outer_face_edge[e])
Chris@16 1600 {
Chris@16 1601 if (!upper_face_vertex[current_vertex] &&
Chris@16 1602 !lower_face_vertex[current_vertex]
Chris@16 1603 )
Chris@16 1604 {
Chris@16 1605 x_y_path_vertex[current_vertex] = true;
Chris@16 1606 }
Chris@16 1607
Chris@16 1608 is_in_subgraph[e] = true;
Chris@16 1609 if (upper_face_vertex[source(e,g)] ||
Chris@16 1610 lower_face_vertex[source(e,g)]
Chris@16 1611 )
Chris@16 1612 {
Chris@16 1613 if (first_x_y_path_endpoint ==
Chris@16 1614 graph_traits<Graph>::null_vertex()
Chris@16 1615 )
Chris@16 1616 first_x_y_path_endpoint = source(e,g);
Chris@16 1617 else
Chris@16 1618 second_x_y_path_endpoint = source(e,g);
Chris@16 1619 }
Chris@16 1620 if (upper_face_vertex[target(e,g)] ||
Chris@16 1621 lower_face_vertex[target(e,g)]
Chris@16 1622 )
Chris@16 1623 {
Chris@16 1624 if (first_x_y_path_endpoint ==
Chris@16 1625 graph_traits<Graph>::null_vertex()
Chris@16 1626 )
Chris@16 1627 first_x_y_path_endpoint = target(e,g);
Chris@16 1628 else
Chris@16 1629 second_x_y_path_endpoint = target(e,g);
Chris@16 1630 }
Chris@16 1631
Chris@16 1632
Chris@16 1633 }
Chris@16 1634 else if (previous_vertex == x || previous_vertex == y)
Chris@16 1635 {
Chris@16 1636 chosen_case = detail::BM_CASE_C;
Chris@16 1637 }
Chris@16 1638
Chris@16 1639 }
Chris@16 1640
Chris@16 1641 }
Chris@16 1642
Chris@16 1643 // Look for a case D - one of v's embedded edges will connect to the
Chris@16 1644 // x-y path along an inner face path.
Chris@16 1645
Chris@16 1646 //First, get a list of all of v's embedded child edges
Chris@16 1647
Chris@16 1648 out_edge_iterator_t v_edge_itr, v_edge_end;
Chris@16 1649 for(boost::tie(v_edge_itr,v_edge_end) = out_edges(v,g);
Chris@16 1650 v_edge_itr != v_edge_end; ++v_edge_itr
Chris@16 1651 )
Chris@16 1652 {
Chris@16 1653 edge_t embedded_edge(*v_edge_itr);
Chris@16 1654
Chris@16 1655 if (!is_embedded[embedded_edge] ||
Chris@16 1656 embedded_edge == dfs_parent_edge[v]
Chris@16 1657 )
Chris@16 1658 continue;
Chris@16 1659
Chris@16 1660 case_d_edges.push_back(embedded_edge);
Chris@16 1661
Chris@16 1662 vertex_t current_vertex
Chris@16 1663 = source(embedded_edge,g) == v ?
Chris@16 1664 target(embedded_edge,g) : source(embedded_edge,g);
Chris@16 1665
Chris@16 1666 typename face_edge_iterator<>::type
Chris@16 1667 internal_face_itr, internal_face_end;
Chris@16 1668 if (face_handles[current_vertex].first_vertex() == v)
Chris@16 1669 {
Chris@16 1670 internal_face_itr = typename face_edge_iterator<>::type
Chris@16 1671 (current_vertex, face_handles, second_side());
Chris@16 1672 }
Chris@16 1673 else
Chris@16 1674 {
Chris@16 1675 internal_face_itr = typename face_edge_iterator<>::type
Chris@16 1676 (current_vertex, face_handles, first_side());
Chris@16 1677 }
Chris@16 1678
Chris@16 1679 while(internal_face_itr != internal_face_end &&
Chris@16 1680 !outer_face_edge[*internal_face_itr] &&
Chris@16 1681 !x_y_path_vertex[current_vertex]
Chris@16 1682 )
Chris@16 1683 {
Chris@16 1684 edge_t e(*internal_face_itr);
Chris@16 1685 case_d_edges.push_back(e);
Chris@16 1686 current_vertex =
Chris@16 1687 source(e,g) == current_vertex ? target(e,g) : source(e,g);
Chris@16 1688 ++internal_face_itr;
Chris@16 1689 }
Chris@16 1690
Chris@16 1691 if (x_y_path_vertex[current_vertex])
Chris@16 1692 {
Chris@16 1693 chosen_case = detail::BM_CASE_D;
Chris@16 1694 break;
Chris@16 1695 }
Chris@16 1696 else
Chris@16 1697 {
Chris@16 1698 case_d_edges.clear();
Chris@16 1699 }
Chris@16 1700
Chris@16 1701 }
Chris@16 1702
Chris@16 1703
Chris@16 1704 }
Chris@16 1705
Chris@16 1706
Chris@16 1707
Chris@16 1708
Chris@16 1709 if (chosen_case != detail::BM_CASE_B && chosen_case != detail::BM_CASE_A)
Chris@16 1710 {
Chris@16 1711
Chris@16 1712 //Finding z and w.
Chris@16 1713
Chris@16 1714 for(boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
Chris@16 1715 {
Chris@16 1716 edge_t e(*ei);
Chris@16 1717 goal_edge[e] = !outer_face_edge[e] &&
Chris@16 1718 (source(e,g) == z || target(e,g) == z);
Chris@16 1719 forbidden_edge[e] = outer_face_edge[e];
Chris@16 1720 }
Chris@16 1721
Chris@16 1722 kuratowski_walkup(v,
Chris@16 1723 forbidden_edge,
Chris@16 1724 goal_edge,
Chris@16 1725 is_embedded,
Chris@16 1726 z_v_path
Chris@16 1727 );
Chris@16 1728
Chris@16 1729 if (chosen_case == detail::BM_CASE_E)
Chris@16 1730 {
Chris@16 1731
Chris@16 1732 for(boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
Chris@16 1733 {
Chris@16 1734 forbidden_edge[*ei] = outer_face_edge[*ei];
Chris@16 1735 goal_edge[*ei] = !outer_face_edge[*ei] &&
Chris@16 1736 (source(*ei,g) == w || target(*ei,g) == w);
Chris@16 1737 }
Chris@16 1738
Chris@16 1739 for(boost::tie(oei, oei_end) = out_edges(w,g); oei != oei_end; ++oei)
Chris@16 1740 {
Chris@16 1741 if (!outer_face_edge[*oei])
Chris@16 1742 goal_edge[*oei] = true;
Chris@16 1743 }
Chris@16 1744
Chris@16 1745 typename std::vector<edge_t>::iterator pi, pi_end;
Chris@16 1746 pi_end = z_v_path.end();
Chris@16 1747 for(pi = z_v_path.begin(); pi != pi_end; ++pi)
Chris@16 1748 {
Chris@16 1749 goal_edge[*pi] = true;
Chris@16 1750 }
Chris@16 1751
Chris@16 1752 w_ancestor = v;
Chris@16 1753 vertex_t w_endpoint = graph_traits<Graph>::null_vertex();
Chris@16 1754
Chris@16 1755 while(w_endpoint == graph_traits<Graph>::null_vertex())
Chris@16 1756 {
Chris@16 1757 w_ancestor = dfs_parent[w_ancestor];
Chris@16 1758 w_endpoint = kuratowski_walkup(w_ancestor,
Chris@16 1759 forbidden_edge,
Chris@16 1760 goal_edge,
Chris@16 1761 is_embedded,
Chris@16 1762 w_path
Chris@16 1763 );
Chris@16 1764
Chris@16 1765 }
Chris@16 1766
Chris@16 1767 }
Chris@16 1768
Chris@16 1769
Chris@16 1770 }
Chris@16 1771
Chris@16 1772
Chris@16 1773 //We're done isolating the Kuratowski subgraph at this point -
Chris@16 1774 //but there's still some cleaning up to do.
Chris@16 1775
Chris@16 1776 //Update is_in_subgraph with the paths we just found
Chris@16 1777
Chris@16 1778 xi_end = x_external_path.end();
Chris@16 1779 for(xi = x_external_path.begin(); xi != xi_end; ++xi)
Chris@16 1780 is_in_subgraph[*xi] = true;
Chris@16 1781
Chris@16 1782 xi_end = y_external_path.end();
Chris@16 1783 for(xi = y_external_path.begin(); xi != xi_end; ++xi)
Chris@16 1784 is_in_subgraph[*xi] = true;
Chris@16 1785
Chris@16 1786 xi_end = z_v_path.end();
Chris@16 1787 for(xi = z_v_path.begin(); xi != xi_end; ++xi)
Chris@16 1788 is_in_subgraph[*xi] = true;
Chris@16 1789
Chris@16 1790 xi_end = case_d_edges.end();
Chris@16 1791 for(xi = case_d_edges.begin(); xi != xi_end; ++xi)
Chris@16 1792 is_in_subgraph[*xi] = true;
Chris@16 1793
Chris@16 1794 xi_end = w_path.end();
Chris@16 1795 for(xi = w_path.begin(); xi != xi_end; ++xi)
Chris@16 1796 is_in_subgraph[*xi] = true;
Chris@16 1797
Chris@16 1798 child = bicomp_root;
Chris@16 1799 parent = dfs_parent[child];
Chris@16 1800 while(child != parent)
Chris@16 1801 {
Chris@16 1802 is_in_subgraph[dfs_parent_edge[child]] = true;
Chris@16 1803 boost::tie(parent, child) = std::make_pair( dfs_parent[parent], parent );
Chris@16 1804 }
Chris@16 1805
Chris@16 1806
Chris@16 1807
Chris@16 1808
Chris@16 1809 // At this point, we've already isolated the Kuratowski subgraph and
Chris@16 1810 // collected all of the edges that compose it in the is_in_subgraph
Chris@16 1811 // property map. But we want the verification of such a subgraph to be
Chris@16 1812 // a deterministic process, and we can simplify the function
Chris@16 1813 // is_kuratowski_subgraph by cleaning up some edges here.
Chris@16 1814
Chris@16 1815 if (chosen_case == detail::BM_CASE_B)
Chris@16 1816 {
Chris@16 1817 is_in_subgraph[dfs_parent_edge[v]] = false;
Chris@16 1818 }
Chris@16 1819 else if (chosen_case == detail::BM_CASE_C)
Chris@16 1820 {
Chris@16 1821 // In a case C subgraph, at least one of the x-y path endpoints
Chris@16 1822 // (call it alpha) is above either x or y on the outer face. The
Chris@16 1823 // other endpoint may be attached at x or y OR above OR below. In
Chris@16 1824 // any of these three cases, we can form a K_3_3 by removing the
Chris@16 1825 // edge attached to v on the outer face that is NOT on the path to
Chris@16 1826 // alpha.
Chris@16 1827
Chris@16 1828 typename face_vertex_iterator<single_side, follow_visitor>::type
Chris@16 1829 face_itr, face_end;
Chris@16 1830 if (face_handles[v_dfchild_handle.first_vertex()].first_edge() ==
Chris@16 1831 v_dfchild_handle.first_edge()
Chris@16 1832 )
Chris@16 1833 {
Chris@16 1834 face_itr = typename face_vertex_iterator
Chris@16 1835 <single_side, follow_visitor>::type
Chris@16 1836 (v_dfchild_handle.first_vertex(), face_handles, second_side());
Chris@16 1837 }
Chris@16 1838 else
Chris@16 1839 {
Chris@16 1840 face_itr = typename face_vertex_iterator
Chris@16 1841 <single_side, follow_visitor>::type
Chris@16 1842 (v_dfchild_handle.first_vertex(), face_handles, first_side());
Chris@16 1843 }
Chris@16 1844
Chris@16 1845 for(; true; ++face_itr)
Chris@16 1846 {
Chris@16 1847 vertex_t current_vertex(*face_itr);
Chris@16 1848 if (current_vertex == x || current_vertex == y)
Chris@16 1849 {
Chris@16 1850 is_in_subgraph[v_dfchild_handle.first_edge()] = false;
Chris@16 1851 break;
Chris@16 1852 }
Chris@16 1853 else if (current_vertex == first_x_y_path_endpoint ||
Chris@16 1854 current_vertex == second_x_y_path_endpoint)
Chris@16 1855 {
Chris@16 1856 is_in_subgraph[v_dfchild_handle.second_edge()] = false;
Chris@16 1857 break;
Chris@16 1858 }
Chris@16 1859 }
Chris@16 1860
Chris@16 1861 }
Chris@16 1862 else if (chosen_case == detail::BM_CASE_D)
Chris@16 1863 {
Chris@16 1864 // Need to remove both of the edges adjacent to v on the outer face.
Chris@16 1865 // remove the connecting edges from v to bicomp, then
Chris@16 1866 // is_kuratowski_subgraph will shrink vertices of degree 1
Chris@16 1867 // automatically...
Chris@16 1868
Chris@16 1869 is_in_subgraph[v_dfchild_handle.first_edge()] = false;
Chris@16 1870 is_in_subgraph[v_dfchild_handle.second_edge()] = false;
Chris@16 1871
Chris@16 1872 }
Chris@16 1873 else if (chosen_case == detail::BM_CASE_E)
Chris@16 1874 {
Chris@16 1875 // Similarly to case C, if the endpoints of the x-y path are both
Chris@16 1876 // below x and y, we should remove an edge to allow the subgraph to
Chris@16 1877 // contract to a K_3_3.
Chris@16 1878
Chris@16 1879
Chris@16 1880 if ((first_x_y_path_endpoint != x && first_x_y_path_endpoint != y) ||
Chris@16 1881 (second_x_y_path_endpoint != x && second_x_y_path_endpoint != y)
Chris@16 1882 )
Chris@16 1883 {
Chris@16 1884 is_in_subgraph[dfs_parent_edge[v]] = false;
Chris@16 1885
Chris@16 1886 vertex_t deletion_endpoint, other_endpoint;
Chris@16 1887 if (lower_face_vertex[first_x_y_path_endpoint])
Chris@16 1888 {
Chris@16 1889 deletion_endpoint = second_x_y_path_endpoint;
Chris@16 1890 other_endpoint = first_x_y_path_endpoint;
Chris@16 1891 }
Chris@16 1892 else
Chris@16 1893 {
Chris@16 1894 deletion_endpoint = first_x_y_path_endpoint;
Chris@16 1895 other_endpoint = second_x_y_path_endpoint;
Chris@16 1896 }
Chris@16 1897
Chris@16 1898 typename face_edge_iterator<>::type face_itr, face_end;
Chris@16 1899
Chris@16 1900 bool found_other_endpoint = false;
Chris@16 1901 for(face_itr = typename face_edge_iterator<>::type
Chris@16 1902 (deletion_endpoint, face_handles, first_side());
Chris@16 1903 face_itr != face_end; ++face_itr
Chris@16 1904 )
Chris@16 1905 {
Chris@16 1906 edge_t e(*face_itr);
Chris@16 1907 if (source(e,g) == other_endpoint ||
Chris@16 1908 target(e,g) == other_endpoint
Chris@16 1909 )
Chris@16 1910 {
Chris@16 1911 found_other_endpoint = true;
Chris@16 1912 break;
Chris@16 1913 }
Chris@16 1914 }
Chris@16 1915
Chris@16 1916 if (found_other_endpoint)
Chris@16 1917 {
Chris@16 1918 is_in_subgraph[face_handles[deletion_endpoint].first_edge()]
Chris@16 1919 = false;
Chris@16 1920 }
Chris@16 1921 else
Chris@16 1922 {
Chris@16 1923 is_in_subgraph[face_handles[deletion_endpoint].second_edge()]
Chris@16 1924 = false;
Chris@16 1925 }
Chris@16 1926 }
Chris@16 1927
Chris@16 1928 }
Chris@16 1929
Chris@16 1930
Chris@16 1931 for(boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
Chris@16 1932 if (is_in_subgraph[*ei])
Chris@16 1933 *o_itr = *ei;
Chris@16 1934
Chris@16 1935 }
Chris@16 1936
Chris@16 1937
Chris@16 1938
Chris@16 1939 template<typename EdgePermutation>
Chris@16 1940 void make_edge_permutation(EdgePermutation perm)
Chris@16 1941 {
Chris@16 1942 vertex_iterator_t vi, vi_end;
Chris@16 1943 for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
Chris@16 1944 {
Chris@16 1945 vertex_t v(*vi);
Chris@16 1946 perm[v].clear();
Chris@16 1947 face_handles[v].get_list(std::back_inserter(perm[v]));
Chris@16 1948 }
Chris@16 1949 }
Chris@16 1950
Chris@16 1951
Chris@16 1952 private:
Chris@16 1953
Chris@16 1954 const Graph& g;
Chris@16 1955 VertexIndexMap vm;
Chris@16 1956
Chris@16 1957 vertex_t kuratowski_v;
Chris@16 1958 vertex_t kuratowski_x;
Chris@16 1959 vertex_t kuratowski_y;
Chris@16 1960
Chris@16 1961 vertex_list_t garbage; // we delete items from linked lists by
Chris@16 1962 // splicing them into garbage
Chris@16 1963
Chris@16 1964 //only need these two for kuratowski subgraph isolation
Chris@16 1965 std::vector<vertex_t> current_merge_points;
Chris@16 1966 std::vector<edge_t> embedded_edges;
Chris@16 1967
Chris@16 1968 //property map storage
Chris@16 1969 std::vector<v_size_t> low_point_vector;
Chris@16 1970 std::vector<vertex_t> dfs_parent_vector;
Chris@16 1971 std::vector<v_size_t> dfs_number_vector;
Chris@16 1972 std::vector<v_size_t> least_ancestor_vector;
Chris@16 1973 std::vector<face_handle_list_ptr_t> pertinent_roots_vector;
Chris@16 1974 std::vector<v_size_t> backedge_flag_vector;
Chris@16 1975 std::vector<v_size_t> visited_vector;
Chris@16 1976 std::vector< face_handle_t > face_handles_vector;
Chris@16 1977 std::vector< face_handle_t > dfs_child_handles_vector;
Chris@16 1978 std::vector< vertex_list_ptr_t > separated_dfs_child_list_vector;
Chris@16 1979 std::vector< typename vertex_list_t::iterator >
Chris@16 1980 separated_node_in_parent_list_vector;
Chris@16 1981 std::vector<vertex_t> canonical_dfs_child_vector;
Chris@16 1982 std::vector<bool> flipped_vector;
Chris@16 1983 std::vector<edge_vector_t> backedges_vector;
Chris@16 1984 edge_vector_t self_loops;
Chris@16 1985 std::vector<edge_t> dfs_parent_edge_vector;
Chris@16 1986 vertex_vector_t vertices_by_dfs_num;
Chris@16 1987
Chris@16 1988 //property maps
Chris@16 1989 vertex_to_v_size_map_t low_point;
Chris@16 1990 vertex_to_vertex_map_t dfs_parent;
Chris@16 1991 vertex_to_v_size_map_t dfs_number;
Chris@16 1992 vertex_to_v_size_map_t least_ancestor;
Chris@16 1993 vertex_to_face_handle_list_ptr_map_t pertinent_roots;
Chris@16 1994 vertex_to_v_size_map_t backedge_flag;
Chris@16 1995 vertex_to_v_size_map_t visited;
Chris@16 1996 vertex_to_face_handle_map_t face_handles;
Chris@16 1997 vertex_to_face_handle_map_t dfs_child_handles;
Chris@16 1998 vertex_to_vertex_list_ptr_map_t separated_dfs_child_list;
Chris@16 1999 vertex_to_separated_node_map_t separated_node_in_parent_list;
Chris@16 2000 vertex_to_vertex_map_t canonical_dfs_child;
Chris@16 2001 vertex_to_bool_map_t flipped;
Chris@16 2002 vertex_to_edge_vector_map_t backedges;
Chris@16 2003 vertex_to_edge_map_t dfs_parent_edge; //only need for kuratowski
Chris@16 2004
Chris@16 2005 merge_stack_t merge_stack;
Chris@16 2006
Chris@16 2007 };
Chris@16 2008
Chris@16 2009
Chris@16 2010 } //namespace boost
Chris@16 2011
Chris@16 2012 #endif //__BOYER_MYRVOLD_IMPL_HPP__