1 //======================================================================= 2 // Copyright (c) Aaron Windsor 2007 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 9 #ifndef __FACE_HANDLES_HPP__ 10 #define __FACE_HANDLES_HPP__ 11 12 13 #include <list> 14 #include <boost/graph/graph_traits.hpp> 15 #include <boost/shared_ptr.hpp> 16 17 18 // A "face handle" is an optimization meant to serve two purposes in 19 // the implementation of the Boyer-Myrvold planarity test: (1) it holds 20 // the partial planar embedding of a particular vertex as it's being 21 // constructed, and (2) it allows for efficient traversal around the 22 // outer face of the partial embedding at that particular vertex. A face 23 // handle is lightweight, just a shared pointer to the actual implementation, 24 // since it is passed around/copied liberally in the algorithm. It consists 25 // of an "anchor" (the actual vertex it's associated with) as well as a 26 // sequence of edges. The functions first_vertex/second_vertex and 27 // first_edge/second_edge allow fast access to the beginning and end of the 28 // stored sequence, which allows one to traverse the outer face of the partial 29 // planar embedding as it's being created. 30 // 31 // There are some policies below that define the contents of the face handles: 32 // in the case no embedding is needed (for example, if one just wants to use 33 // the Boyer-Myrvold algorithm as a true/false test for planarity, the 34 // no_embedding class can be passed as the StoreEmbedding policy. Otherwise, 35 // either std_list (which uses as std::list) or recursive_lazy_list can be 36 // passed as this policy. recursive_lazy_list has the best theoretical 37 // performance (O(n) for a sequence of interleaved concatenations and reversals 38 // of the underlying list), but I've noticed little difference between std_list 39 // and recursive_lazy_list in my tests, even though using std_list changes 40 // the worst-case complexity of the planarity test to O(n^2) 41 // 42 // Another policy is StoreOldHandlesPolicy, which specifies whether or not 43 // to keep a record of the previous first/second vertex/edge - this is needed 44 // if a Kuratowski subgraph needs to be isolated. 45 46 47 namespace boost { namespace graph { namespace detail { 48 49 50 //face handle policies 51 52 //EmbeddingStorage policy 53 struct store_embedding {}; 54 struct recursive_lazy_list : public store_embedding {}; 55 struct std_list : public store_embedding {}; 56 struct no_embedding {}; 57 58 //StoreOldHandlesPolicy 59 struct store_old_handles {}; 60 struct no_old_handles {}; 61 62 63 64 65 template<typename DataType> 66 struct lazy_list_node 67 { 68 typedef shared_ptr< lazy_list_node<DataType> > ptr_t; 69 lazy_list_nodeboost::graph::detail::lazy_list_node70 lazy_list_node(const DataType& data) : 71 m_reversed(false), 72 m_data(data), 73 m_has_data(true) 74 {} 75 lazy_list_nodeboost::graph::detail::lazy_list_node76 lazy_list_node(ptr_t left_child, ptr_t right_child) : 77 m_reversed(false), 78 m_has_data(false), 79 m_left_child(left_child), 80 m_right_child(right_child) 81 {} 82 83 bool m_reversed; 84 DataType m_data; 85 bool m_has_data; 86 shared_ptr<lazy_list_node> m_left_child; 87 shared_ptr<lazy_list_node> m_right_child; 88 }; 89 90 91 92 template <typename StoreOldHandlesPolicy, typename Vertex, typename Edge> 93 struct old_handles_storage; 94 95 template <typename Vertex, typename Edge> 96 struct old_handles_storage<store_old_handles, Vertex, Edge> 97 { 98 Vertex first_vertex; 99 Vertex second_vertex; 100 Edge first_edge; 101 Edge second_edge; 102 }; 103 104 template <typename Vertex, typename Edge> 105 struct old_handles_storage<no_old_handles, Vertex, Edge> 106 {}; 107 108 109 110 111 112 113 template <typename StoreEmbeddingPolicy, typename Edge> 114 struct edge_list_storage; 115 116 117 118 119 120 template <typename Edge> 121 struct edge_list_storage<no_embedding, Edge> 122 { 123 typedef void type; 124 push_backboost::graph::detail::edge_list_storage125 void push_back(Edge) {} push_frontboost::graph::detail::edge_list_storage126 void push_front(Edge) {} reverseboost::graph::detail::edge_list_storage127 void reverse() {} concat_frontboost::graph::detail::edge_list_storage128 void concat_front(edge_list_storage<no_embedding,Edge>) {} concat_backboost::graph::detail::edge_list_storage129 void concat_back(edge_list_storage<no_embedding,Edge>) {} 130 template <typename OutputIterator> get_listboost::graph::detail::edge_list_storage131 void get_list(OutputIterator) {} 132 }; 133 134 135 136 137 138 template <typename Edge> 139 struct edge_list_storage<recursive_lazy_list, Edge> 140 { 141 typedef lazy_list_node<Edge> node_type; 142 typedef shared_ptr< node_type > type; 143 type value; 144 push_backboost::graph::detail::edge_list_storage145 void push_back(Edge e) 146 { 147 type new_node(new node_type(e)); 148 value = type(new node_type(value, new_node)); 149 } 150 push_frontboost::graph::detail::edge_list_storage151 void push_front(Edge e) 152 { 153 type new_node(new node_type(e)); 154 value = type(new node_type(new_node, value)); 155 } 156 reverseboost::graph::detail::edge_list_storage157 void reverse() 158 { 159 value->m_reversed = !value->m_reversed; 160 } 161 concat_frontboost::graph::detail::edge_list_storage162 void concat_front(edge_list_storage<recursive_lazy_list, Edge> other) 163 { 164 value = type(new node_type(other.value, value)); 165 } 166 concat_backboost::graph::detail::edge_list_storage167 void concat_back(edge_list_storage<recursive_lazy_list, Edge> other) 168 { 169 value = type(new node_type(value, other.value)); 170 } 171 172 template <typename OutputIterator> get_listboost::graph::detail::edge_list_storage173 void get_list(OutputIterator out) 174 { 175 get_list_helper(out, value); 176 } 177 178 private: 179 180 template <typename OutputIterator> get_list_helperboost::graph::detail::edge_list_storage181 void get_list_helper(OutputIterator o_itr, 182 type root, 183 bool flipped = false 184 ) 185 { 186 if (!root) 187 return; 188 189 if (root->m_has_data) 190 *o_itr = root->m_data; 191 192 if ((flipped && !root->m_reversed) || 193 (!flipped && root->m_reversed) 194 ) 195 { 196 get_list_helper(o_itr, root->m_right_child, true); 197 get_list_helper(o_itr, root->m_left_child, true); 198 } 199 else 200 { 201 get_list_helper(o_itr, root->m_left_child, false); 202 get_list_helper(o_itr, root->m_right_child, false); 203 } 204 205 } 206 207 }; 208 209 210 211 212 213 template <typename Edge> 214 struct edge_list_storage<std_list, Edge> 215 { 216 typedef std::list<Edge> type; 217 type value; 218 push_backboost::graph::detail::edge_list_storage219 void push_back(Edge e) 220 { 221 value.push_back(e); 222 } 223 push_frontboost::graph::detail::edge_list_storage224 void push_front(Edge e) 225 { 226 value.push_front(e); 227 } 228 reverseboost::graph::detail::edge_list_storage229 void reverse() 230 { 231 value.reverse(); 232 } 233 concat_frontboost::graph::detail::edge_list_storage234 void concat_front(edge_list_storage<std_list,Edge> other) 235 { 236 value.splice(value.begin(), other.value); 237 } 238 concat_backboost::graph::detail::edge_list_storage239 void concat_back(edge_list_storage<std_list, Edge> other) 240 { 241 value.splice(value.end(), other.value); 242 } 243 244 template <typename OutputIterator> get_listboost::graph::detail::edge_list_storage245 void get_list(OutputIterator out) 246 { 247 std::copy(value.begin(), value.end(), out); 248 } 249 250 }; 251 252 253 254 255 256 257 258 template<typename Graph, 259 typename StoreOldHandlesPolicy, 260 typename StoreEmbeddingPolicy 261 > 262 struct face_handle_impl 263 { 264 typedef typename graph_traits<Graph>::vertex_descriptor vertex_t; 265 typedef typename graph_traits<Graph>::edge_descriptor edge_t; 266 typedef typename edge_list_storage<StoreEmbeddingPolicy, edge_t>::type 267 edge_list_storage_t; 268 269 face_handle_implboost::graph::detail::face_handle_impl270 face_handle_impl() : 271 cached_first_vertex(graph_traits<Graph>::null_vertex()), 272 cached_second_vertex(graph_traits<Graph>::null_vertex()), 273 true_first_vertex(graph_traits<Graph>::null_vertex()), 274 true_second_vertex(graph_traits<Graph>::null_vertex()), 275 anchor(graph_traits<Graph>::null_vertex()) 276 { 277 initialize_old_vertices_dispatch(StoreOldHandlesPolicy()); 278 } 279 initialize_old_vertices_dispatchboost::graph::detail::face_handle_impl280 void initialize_old_vertices_dispatch(store_old_handles) 281 { 282 old_handles.first_vertex = graph_traits<Graph>::null_vertex(); 283 old_handles.second_vertex = graph_traits<Graph>::null_vertex(); 284 } 285 initialize_old_vertices_dispatchboost::graph::detail::face_handle_impl286 void initialize_old_vertices_dispatch(no_old_handles) {} 287 288 vertex_t cached_first_vertex; 289 vertex_t cached_second_vertex; 290 vertex_t true_first_vertex; 291 vertex_t true_second_vertex; 292 vertex_t anchor; 293 edge_t cached_first_edge; 294 edge_t cached_second_edge; 295 296 edge_list_storage<StoreEmbeddingPolicy, edge_t> edge_list; 297 old_handles_storage<StoreOldHandlesPolicy, vertex_t, edge_t> old_handles; 298 299 }; 300 301 302 303 304 305 306 307 308 309 310 311 template <typename Graph, 312 typename StoreOldHandlesPolicy = store_old_handles, 313 typename StoreEmbeddingPolicy = recursive_lazy_list 314 > 315 class face_handle 316 { 317 public: 318 typedef typename graph_traits<Graph>::vertex_descriptor vertex_t; 319 typedef typename graph_traits<Graph>::edge_descriptor edge_t; 320 typedef face_handle_impl 321 <Graph, StoreOldHandlesPolicy, StoreEmbeddingPolicy> impl_t; 322 typedef face_handle 323 <Graph, StoreOldHandlesPolicy, StoreEmbeddingPolicy> self_t; 324 face_handle(vertex_t anchor=graph_traits<Graph>::null_vertex ())325 face_handle(vertex_t anchor = graph_traits<Graph>::null_vertex()) : 326 pimpl(new impl_t()) 327 { 328 pimpl->anchor = anchor; 329 } 330 face_handle(vertex_t anchor,edge_t initial_edge,const Graph & g)331 face_handle(vertex_t anchor, edge_t initial_edge, const Graph& g) : 332 pimpl(new impl_t()) 333 { 334 vertex_t s(source(initial_edge,g)); 335 vertex_t t(target(initial_edge,g)); 336 vertex_t other_vertex = s == anchor ? t : s; 337 pimpl->anchor = anchor; 338 pimpl->cached_first_edge = initial_edge; 339 pimpl->cached_second_edge = initial_edge; 340 pimpl->cached_first_vertex = other_vertex; 341 pimpl->cached_second_vertex = other_vertex; 342 pimpl->true_first_vertex = other_vertex; 343 pimpl->true_second_vertex = other_vertex; 344 345 pimpl->edge_list.push_back(initial_edge); 346 store_old_face_handles_dispatch(StoreOldHandlesPolicy()); 347 } 348 349 //default copy construction, assignment okay. 350 push_first(edge_t e,const Graph & g)351 void push_first(edge_t e, const Graph& g) 352 { 353 pimpl->edge_list.push_front(e); 354 pimpl->cached_first_vertex = pimpl->true_first_vertex = 355 source(e, g) == pimpl->anchor ? target(e,g) : source(e,g); 356 pimpl->cached_first_edge = e; 357 } 358 push_second(edge_t e,const Graph & g)359 void push_second(edge_t e, const Graph& g) 360 { 361 pimpl->edge_list.push_back(e); 362 pimpl->cached_second_vertex = pimpl->true_second_vertex = 363 source(e, g) == pimpl->anchor ? target(e,g) : source(e,g); 364 pimpl->cached_second_edge = e; 365 } 366 store_old_face_handles()367 inline void store_old_face_handles() 368 { 369 store_old_face_handles_dispatch(StoreOldHandlesPolicy()); 370 } 371 first_vertex() const372 inline vertex_t first_vertex() const 373 { 374 return pimpl->cached_first_vertex; 375 } 376 second_vertex() const377 inline vertex_t second_vertex() const 378 { 379 return pimpl->cached_second_vertex; 380 } 381 true_first_vertex() const382 inline vertex_t true_first_vertex() const 383 { 384 return pimpl->true_first_vertex; 385 } 386 true_second_vertex() const387 inline vertex_t true_second_vertex() const 388 { 389 return pimpl->true_second_vertex; 390 } 391 old_first_vertex() const392 inline vertex_t old_first_vertex() const 393 { 394 return pimpl->old_handles.first_vertex; 395 } 396 old_second_vertex() const397 inline vertex_t old_second_vertex() const 398 { 399 return pimpl->old_handles.second_vertex; 400 } 401 old_first_edge() const402 inline edge_t old_first_edge() const 403 { 404 return pimpl->old_handles.first_edge; 405 } 406 old_second_edge() const407 inline edge_t old_second_edge() const 408 { 409 return pimpl->old_handles.second_edge; 410 } 411 first_edge() const412 inline edge_t first_edge() const 413 { 414 return pimpl->cached_first_edge; 415 } 416 second_edge() const417 inline edge_t second_edge() const 418 { 419 return pimpl->cached_second_edge; 420 } 421 get_anchor() const422 inline vertex_t get_anchor() const 423 { 424 return pimpl->anchor; 425 } 426 glue_first_to_second(face_handle<Graph,StoreOldHandlesPolicy,StoreEmbeddingPolicy> & bottom)427 void glue_first_to_second 428 (face_handle<Graph,StoreOldHandlesPolicy,StoreEmbeddingPolicy>& bottom) 429 { 430 pimpl->edge_list.concat_front(bottom.pimpl->edge_list); 431 pimpl->true_first_vertex = bottom.pimpl->true_first_vertex; 432 pimpl->cached_first_vertex = bottom.pimpl->cached_first_vertex; 433 pimpl->cached_first_edge = bottom.pimpl->cached_first_edge; 434 } 435 glue_second_to_first(face_handle<Graph,StoreOldHandlesPolicy,StoreEmbeddingPolicy> & bottom)436 void glue_second_to_first 437 (face_handle<Graph,StoreOldHandlesPolicy,StoreEmbeddingPolicy>& bottom) 438 { 439 pimpl->edge_list.concat_back(bottom.pimpl->edge_list); 440 pimpl->true_second_vertex = bottom.pimpl->true_second_vertex; 441 pimpl->cached_second_vertex = bottom.pimpl->cached_second_vertex; 442 pimpl->cached_second_edge = bottom.pimpl->cached_second_edge; 443 } 444 flip()445 void flip() 446 { 447 pimpl->edge_list.reverse(); 448 std::swap(pimpl->true_first_vertex, pimpl->true_second_vertex); 449 std::swap(pimpl->cached_first_vertex, pimpl->cached_second_vertex); 450 std::swap(pimpl->cached_first_edge, pimpl->cached_second_edge); 451 } 452 453 template <typename OutputIterator> get_list(OutputIterator o_itr)454 void get_list(OutputIterator o_itr) 455 { 456 pimpl->edge_list.get_list(o_itr); 457 } 458 reset_vertex_cache()459 void reset_vertex_cache() 460 { 461 pimpl->cached_first_vertex = pimpl->true_first_vertex; 462 pimpl->cached_second_vertex = pimpl->true_second_vertex; 463 } 464 set_first_vertex(vertex_t v)465 inline void set_first_vertex(vertex_t v) 466 { 467 pimpl->cached_first_vertex = v; 468 } 469 set_second_vertex(vertex_t v)470 inline void set_second_vertex(vertex_t v) 471 { 472 pimpl->cached_second_vertex = v; 473 } 474 475 private: 476 store_old_face_handles_dispatch(store_old_handles)477 void store_old_face_handles_dispatch(store_old_handles) 478 { 479 pimpl->old_handles.first_vertex = pimpl->true_first_vertex; 480 pimpl->old_handles.second_vertex = pimpl->true_second_vertex; 481 pimpl->old_handles.first_edge = pimpl->cached_first_edge; 482 pimpl->old_handles.second_edge = pimpl->cached_second_edge; 483 } 484 store_old_face_handles_dispatch(no_old_handles)485 void store_old_face_handles_dispatch(no_old_handles) {} 486 487 488 489 boost::shared_ptr<impl_t> pimpl; 490 491 }; 492 493 494 } /* namespace detail */ } /* namespace graph */ } /* namespace boost */ 495 496 497 #endif //__FACE_HANDLES_HPP__ 498