123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- //=======================================================================
- // Copyright (c) Aaron Windsor 2007
- //
- // Distributed under the Boost Software License, Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //=======================================================================
- #ifndef __FACE_HANDLES_HPP__
- #define __FACE_HANDLES_HPP__
- #include <list>
- #include <boost/graph/graph_traits.hpp>
- #include <boost/shared_ptr.hpp>
- // A "face handle" is an optimization meant to serve two purposes in
- // the implementation of the Boyer-Myrvold planarity test: (1) it holds
- // the partial planar embedding of a particular vertex as it's being
- // constructed, and (2) it allows for efficient traversal around the
- // outer face of the partial embedding at that particular vertex. A face
- // handle is lightweight, just a shared pointer to the actual implementation,
- // since it is passed around/copied liberally in the algorithm. It consists
- // of an "anchor" (the actual vertex it's associated with) as well as a
- // sequence of edges. The functions first_vertex/second_vertex and
- // first_edge/second_edge allow fast access to the beginning and end of the
- // stored sequence, which allows one to traverse the outer face of the partial
- // planar embedding as it's being created.
- //
- // There are some policies below that define the contents of the face handles:
- // in the case no embedding is needed (for example, if one just wants to use
- // the Boyer-Myrvold algorithm as a true/false test for planarity, the
- // no_embedding class can be passed as the StoreEmbedding policy. Otherwise,
- // either std_list (which uses as std::list) or recursive_lazy_list can be
- // passed as this policy. recursive_lazy_list has the best theoretical
- // performance (O(n) for a sequence of interleaved concatenations and reversals
- // of the underlying list), but I've noticed little difference between std_list
- // and recursive_lazy_list in my tests, even though using std_list changes
- // the worst-case complexity of the planarity test to O(n^2)
- //
- // Another policy is StoreOldHandlesPolicy, which specifies whether or not
- // to keep a record of the previous first/second vertex/edge - this is needed
- // if a Kuratowski subgraph needs to be isolated.
- namespace boost
- {
- namespace graph
- {
- namespace detail
- {
- // face handle policies
- // EmbeddingStorage policy
- struct store_embedding
- {
- };
- struct recursive_lazy_list : public store_embedding
- {
- };
- struct std_list : public store_embedding
- {
- };
- struct no_embedding
- {
- };
- // StoreOldHandlesPolicy
- struct store_old_handles
- {
- };
- struct no_old_handles
- {
- };
- template < typename DataType > struct lazy_list_node
- {
- typedef shared_ptr< lazy_list_node< DataType > > ptr_t;
- lazy_list_node(const DataType& data)
- : m_reversed(false), m_data(data), m_has_data(true)
- {
- }
- lazy_list_node(ptr_t left_child, ptr_t right_child)
- : m_reversed(false)
- , m_has_data(false)
- , m_left_child(left_child)
- , m_right_child(right_child)
- {
- }
- bool m_reversed;
- DataType m_data;
- bool m_has_data;
- shared_ptr< lazy_list_node > m_left_child;
- shared_ptr< lazy_list_node > m_right_child;
- };
- template < typename StoreOldHandlesPolicy, typename Vertex,
- typename Edge >
- struct old_handles_storage;
- template < typename Vertex, typename Edge >
- struct old_handles_storage< store_old_handles, Vertex, Edge >
- {
- Vertex first_vertex;
- Vertex second_vertex;
- Edge first_edge;
- Edge second_edge;
- };
- template < typename Vertex, typename Edge >
- struct old_handles_storage< no_old_handles, Vertex, Edge >
- {
- };
- template < typename StoreEmbeddingPolicy, typename Edge >
- struct edge_list_storage;
- template < typename Edge >
- struct edge_list_storage< no_embedding, Edge >
- {
- typedef void type;
- void push_back(Edge) {}
- void push_front(Edge) {}
- void reverse() {}
- void concat_front(edge_list_storage< no_embedding, Edge >) {}
- void concat_back(edge_list_storage< no_embedding, Edge >) {}
- template < typename OutputIterator > void get_list(OutputIterator)
- {
- }
- };
- template < typename Edge >
- struct edge_list_storage< recursive_lazy_list, Edge >
- {
- typedef lazy_list_node< Edge > node_type;
- typedef shared_ptr< node_type > type;
- type value;
- void push_back(Edge e)
- {
- type new_node(new node_type(e));
- value = type(new node_type(value, new_node));
- }
- void push_front(Edge e)
- {
- type new_node(new node_type(e));
- value = type(new node_type(new_node, value));
- }
- void reverse() { value->m_reversed = !value->m_reversed; }
- void concat_front(
- edge_list_storage< recursive_lazy_list, Edge > other)
- {
- value = type(new node_type(other.value, value));
- }
- void concat_back(
- edge_list_storage< recursive_lazy_list, Edge > other)
- {
- value = type(new node_type(value, other.value));
- }
- template < typename OutputIterator >
- void get_list(OutputIterator out)
- {
- get_list_helper(out, value);
- }
- private:
- template < typename OutputIterator >
- void get_list_helper(
- OutputIterator o_itr, type root, bool flipped = false)
- {
- if (!root)
- return;
- if (root->m_has_data)
- *o_itr = root->m_data;
- if ((flipped && !root->m_reversed)
- || (!flipped && root->m_reversed))
- {
- get_list_helper(o_itr, root->m_right_child, true);
- get_list_helper(o_itr, root->m_left_child, true);
- }
- else
- {
- get_list_helper(o_itr, root->m_left_child, false);
- get_list_helper(o_itr, root->m_right_child, false);
- }
- }
- };
- template < typename Edge > struct edge_list_storage< std_list, Edge >
- {
- typedef std::list< Edge > type;
- type value;
- void push_back(Edge e) { value.push_back(e); }
- void push_front(Edge e) { value.push_front(e); }
- void reverse() { value.reverse(); }
- void concat_front(edge_list_storage< std_list, Edge > other)
- {
- value.splice(value.begin(), other.value);
- }
- void concat_back(edge_list_storage< std_list, Edge > other)
- {
- value.splice(value.end(), other.value);
- }
- template < typename OutputIterator >
- void get_list(OutputIterator out)
- {
- std::copy(value.begin(), value.end(), out);
- }
- };
- template < typename Graph, typename StoreOldHandlesPolicy,
- typename StoreEmbeddingPolicy >
- struct face_handle_impl
- {
- typedef typename graph_traits< Graph >::vertex_descriptor vertex_t;
- typedef typename graph_traits< Graph >::edge_descriptor edge_t;
- typedef
- typename edge_list_storage< StoreEmbeddingPolicy, edge_t >::type
- edge_list_storage_t;
- face_handle_impl()
- : cached_first_vertex(graph_traits< Graph >::null_vertex())
- , cached_second_vertex(graph_traits< Graph >::null_vertex())
- , true_first_vertex(graph_traits< Graph >::null_vertex())
- , true_second_vertex(graph_traits< Graph >::null_vertex())
- , anchor(graph_traits< Graph >::null_vertex())
- {
- initialize_old_vertices_dispatch(StoreOldHandlesPolicy());
- }
- void initialize_old_vertices_dispatch(store_old_handles)
- {
- old_handles.first_vertex = graph_traits< Graph >::null_vertex();
- old_handles.second_vertex
- = graph_traits< Graph >::null_vertex();
- }
- void initialize_old_vertices_dispatch(no_old_handles) {}
- vertex_t cached_first_vertex;
- vertex_t cached_second_vertex;
- vertex_t true_first_vertex;
- vertex_t true_second_vertex;
- vertex_t anchor;
- edge_t cached_first_edge;
- edge_t cached_second_edge;
- edge_list_storage< StoreEmbeddingPolicy, edge_t > edge_list;
- old_handles_storage< StoreOldHandlesPolicy, vertex_t, edge_t >
- old_handles;
- };
- template < typename Graph,
- typename StoreOldHandlesPolicy = store_old_handles,
- typename StoreEmbeddingPolicy = recursive_lazy_list >
- class face_handle
- {
- public:
- typedef typename graph_traits< Graph >::vertex_descriptor vertex_t;
- typedef typename graph_traits< Graph >::edge_descriptor edge_t;
- typedef face_handle_impl< Graph, StoreOldHandlesPolicy,
- StoreEmbeddingPolicy >
- impl_t;
- typedef face_handle< Graph, StoreOldHandlesPolicy,
- StoreEmbeddingPolicy >
- self_t;
- face_handle(vertex_t anchor = graph_traits< Graph >::null_vertex())
- : pimpl(new impl_t())
- {
- pimpl->anchor = anchor;
- }
- face_handle(vertex_t anchor, edge_t initial_edge, const Graph& g)
- : pimpl(new impl_t())
- {
- vertex_t s(source(initial_edge, g));
- vertex_t t(target(initial_edge, g));
- vertex_t other_vertex = s == anchor ? t : s;
- pimpl->anchor = anchor;
- pimpl->cached_first_edge = initial_edge;
- pimpl->cached_second_edge = initial_edge;
- pimpl->cached_first_vertex = other_vertex;
- pimpl->cached_second_vertex = other_vertex;
- pimpl->true_first_vertex = other_vertex;
- pimpl->true_second_vertex = other_vertex;
- pimpl->edge_list.push_back(initial_edge);
- store_old_face_handles_dispatch(StoreOldHandlesPolicy());
- }
- // default copy construction, assignment okay.
- void push_first(edge_t e, const Graph& g)
- {
- pimpl->edge_list.push_front(e);
- pimpl->cached_first_vertex = pimpl->true_first_vertex
- = source(e, g) == pimpl->anchor ? target(e, g)
- : source(e, g);
- pimpl->cached_first_edge = e;
- }
- void push_second(edge_t e, const Graph& g)
- {
- pimpl->edge_list.push_back(e);
- pimpl->cached_second_vertex = pimpl->true_second_vertex
- = source(e, g) == pimpl->anchor ? target(e, g)
- : source(e, g);
- pimpl->cached_second_edge = e;
- }
- inline void store_old_face_handles()
- {
- store_old_face_handles_dispatch(StoreOldHandlesPolicy());
- }
- inline vertex_t first_vertex() const
- {
- return pimpl->cached_first_vertex;
- }
- inline vertex_t second_vertex() const
- {
- return pimpl->cached_second_vertex;
- }
- inline vertex_t true_first_vertex() const
- {
- return pimpl->true_first_vertex;
- }
- inline vertex_t true_second_vertex() const
- {
- return pimpl->true_second_vertex;
- }
- inline vertex_t old_first_vertex() const
- {
- return pimpl->old_handles.first_vertex;
- }
- inline vertex_t old_second_vertex() const
- {
- return pimpl->old_handles.second_vertex;
- }
- inline edge_t old_first_edge() const
- {
- return pimpl->old_handles.first_edge;
- }
- inline edge_t old_second_edge() const
- {
- return pimpl->old_handles.second_edge;
- }
- inline edge_t first_edge() const
- {
- return pimpl->cached_first_edge;
- }
- inline edge_t second_edge() const
- {
- return pimpl->cached_second_edge;
- }
- inline vertex_t get_anchor() const { return pimpl->anchor; }
- void glue_first_to_second(face_handle< Graph, StoreOldHandlesPolicy,
- StoreEmbeddingPolicy >& bottom)
- {
- pimpl->edge_list.concat_front(bottom.pimpl->edge_list);
- pimpl->true_first_vertex = bottom.pimpl->true_first_vertex;
- pimpl->cached_first_vertex = bottom.pimpl->cached_first_vertex;
- pimpl->cached_first_edge = bottom.pimpl->cached_first_edge;
- }
- void glue_second_to_first(face_handle< Graph, StoreOldHandlesPolicy,
- StoreEmbeddingPolicy >& bottom)
- {
- pimpl->edge_list.concat_back(bottom.pimpl->edge_list);
- pimpl->true_second_vertex = bottom.pimpl->true_second_vertex;
- pimpl->cached_second_vertex
- = bottom.pimpl->cached_second_vertex;
- pimpl->cached_second_edge = bottom.pimpl->cached_second_edge;
- }
- void flip()
- {
- pimpl->edge_list.reverse();
- std::swap(pimpl->true_first_vertex, pimpl->true_second_vertex);
- std::swap(
- pimpl->cached_first_vertex, pimpl->cached_second_vertex);
- std::swap(pimpl->cached_first_edge, pimpl->cached_second_edge);
- }
- template < typename OutputIterator >
- void get_list(OutputIterator o_itr)
- {
- pimpl->edge_list.get_list(o_itr);
- }
- void reset_vertex_cache()
- {
- pimpl->cached_first_vertex = pimpl->true_first_vertex;
- pimpl->cached_second_vertex = pimpl->true_second_vertex;
- }
- inline void set_first_vertex(vertex_t v)
- {
- pimpl->cached_first_vertex = v;
- }
- inline void set_second_vertex(vertex_t v)
- {
- pimpl->cached_second_vertex = v;
- }
- private:
- void store_old_face_handles_dispatch(store_old_handles)
- {
- pimpl->old_handles.first_vertex = pimpl->true_first_vertex;
- pimpl->old_handles.second_vertex = pimpl->true_second_vertex;
- pimpl->old_handles.first_edge = pimpl->cached_first_edge;
- pimpl->old_handles.second_edge = pimpl->cached_second_edge;
- }
- void store_old_face_handles_dispatch(no_old_handles) {}
- boost::shared_ptr< impl_t > pimpl;
- };
- } /* namespace detail */
- } /* namespace graph */
- } /* namespace boost */
- #endif //__FACE_HANDLES_HPP__
|