diff --git a/include/boost/graph/adjacency_list.hpp b/include/boost/graph/adjacency_list.hpp index 197ef54f..a60916a2 100644 --- a/include/boost/graph/adjacency_list.hpp +++ b/include/boost/graph/adjacency_list.hpp @@ -36,7 +36,10 @@ #include #include #include -#include +#include +#include +#include +#include #include #include #include @@ -238,12 +241,12 @@ namespace boost { namespace detail { template struct is_random_access { enum { value = false}; - typedef false_type type; + typedef mpl::false_ type; }; template <> struct is_random_access { enum { value = true }; - typedef true_type type; + typedef mpl::true_ type; }; } // namespace detail @@ -259,7 +262,8 @@ namespace boost { template + class DirectedS = directedS, + class EdgeListS = listS> struct adjacency_list_traits { typedef typename detail::is_random_access::type @@ -267,9 +271,9 @@ namespace boost { typedef typename DirectedS::is_bidir_t is_bidir; typedef typename DirectedS::is_directed_t is_directed; - typedef typename boost::ct_if_t::type >::type directed_category; @@ -278,10 +282,26 @@ namespace boost { edge_parallel_category; typedef void* vertex_ptr; - typedef typename boost::ct_if_t::type vertex_descriptor; typedef detail::edge_desc_impl edge_descriptor; + + typedef std::size_t vertices_size_type; + + private: + // Logic to figure out the edges_size_type + struct dummy {}; + typedef typename container_gen::type EdgeContainer; + typedef typename DirectedS::is_bidir_t BidirectionalT; + typedef typename DirectedS::is_directed_t DirectedT; + typedef typename mpl::and_::type >::type on_edge_storage; + public: + typedef typename mpl::if_::type edges_size_type; + }; } // namespace boost @@ -335,10 +355,10 @@ namespace boost { edge_property_type; // The types that are actually bundled - typedef typename ct_if<(is_same::value), + typedef typename mpl::if_c<(is_same::value), no_vertex_bundle, maybe_vertex_bundled>::type vertex_bundled; - typedef typename ct_if<(is_same::value), + typedef typename mpl::if_c<(is_same::value), no_edge_bundle, maybe_edge_bundled>::type edge_bundled; #else diff --git a/include/boost/graph/adjacency_matrix.hpp b/include/boost/graph/adjacency_matrix.hpp index 5be3829f..9770e51a 100644 --- a/include/boost/graph/adjacency_matrix.hpp +++ b/include/boost/graph/adjacency_matrix.hpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -441,7 +441,7 @@ namespace boost { BOOST_STATIC_ASSERT(type_traits::ice_not<(is_same::value)>::value); #endif - typedef typename boost::ct_if_t::type directed_category; @@ -497,10 +497,10 @@ namespace boost { public: // The types that are actually bundled - typedef typename ct_if<(is_same::value), + typedef typename mpl::if_c<(is_same::value), no_vertex_bundle, maybe_vertex_bundled>::type vertex_bundled; - typedef typename ct_if<(is_same::value), + typedef typename mpl::if_c<(is_same::value), no_edge_bundle, maybe_edge_bundled>::type edge_bundled; #else @@ -511,7 +511,7 @@ namespace boost { #endif public: // should be private - typedef typename ct_if_t::type, + typedef typename mpl::if_::type, std::pair, char>::type StoredEdge; #if (defined(BOOST_MSVC) && BOOST_MSVC <= 1300) || defined(BOOST_NO_STD_ALLOCATOR) typedef std::vector Matrix; @@ -545,7 +545,7 @@ namespace boost { vertex_descriptor, MatrixIter, size_type, edge_descriptor > UnDirOutEdgeIter; - typedef typename ct_if_t< + typedef typename mpl::if_< typename Directed::is_directed_t, DirOutEdgeIter, UnDirOutEdgeIter >::type unfiltered_out_edge_iter; @@ -557,7 +557,7 @@ namespace boost { vertex_descriptor, MatrixIter, size_type, edge_descriptor > UnDirInEdgeIter; - typedef typename ct_if_t< + typedef typename mpl::if_< typename Directed::is_directed_t, DirInEdgeIter, UnDirInEdgeIter >::type unfiltered_in_edge_iter; diff --git a/include/boost/graph/betweenness_centrality.hpp b/include/boost/graph/betweenness_centrality.hpp index 890103f3..0262ad97 100644 --- a/include/boost/graph/betweenness_centrality.hpp +++ b/include/boost/graph/betweenness_centrality.hpp @@ -417,7 +417,6 @@ namespace detail { namespace graph { WeightMap weight_map, VertexIndexMap vertex_index) { - typedef typename graph_traits::degree_size_type degree_size_type; typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename graph_traits::edge_descriptor edge_descriptor; typedef typename mpl::if_c<(is_same > incoming(V); std::vector distance(V); std::vector dependency(V); - std::vector path_count(V); + std::vector path_count(V); brandes_betweenness_centrality( g, centrality, edge_centrality_map, @@ -453,7 +452,6 @@ namespace detail { namespace graph { EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index) { - typedef typename graph_traits::degree_size_type degree_size_type; typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename graph_traits::edge_descriptor edge_descriptor; typedef typename mpl::if_c<(is_same > incoming(V); std::vector distance(V); std::vector dependency(V); - std::vector path_count(V); + std::vector path_count(V); brandes_betweenness_centrality( g, centrality, edge_centrality_map, diff --git a/include/boost/graph/boyer_myrvold_planar_test.hpp b/include/boost/graph/boyer_myrvold_planar_test.hpp new file mode 100644 index 00000000..dc015868 --- /dev/null +++ b/include/boost/graph/boyer_myrvold_planar_test.hpp @@ -0,0 +1,322 @@ +//======================================================================= +// Copyright 2007 Aaron Windsor +// +// 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 __BOYER_MYRVOLD_PLANAR_TEST_HPP__ +#define __BOYER_MYRVOLD_PLANAR_TEST_HPP__ + +#include +#include +#include +#include + + +namespace boost +{ + + struct no_kuratowski_subgraph_isolation {}; + struct no_planar_embedding {}; + + namespace boyer_myrvold_params + { + + BOOST_PARAMETER_KEYWORD(tag, graph) + BOOST_PARAMETER_KEYWORD(tag, embedding) + BOOST_PARAMETER_KEYWORD(tag, kuratowski_subgraph) + BOOST_PARAMETER_KEYWORD(tag, vertex_index_map) + BOOST_PARAMETER_KEYWORD(tag, edge_index_map) + + typedef parameter::parameters< parameter::required, + tag::embedding, + tag::kuratowski_subgraph, + tag::vertex_index_map, + tag::edge_index_map + > boyer_myrvold_params_t; + + namespace core + { + + template + bool dispatched_boyer_myrvold(ArgumentPack const& args, + mpl::true_, + mpl::true_ + ) + { + //Dispatch for no planar embedding, no kuratowski subgraph isolation + + typedef typename remove_const + < + typename remove_reference + < typename parameter::binding + < ArgumentPack, tag::graph>::type + >::type + >::type graph_t; + + typedef typename parameter::binding + < ArgumentPack, + tag::vertex_index_map, + typename property_map + < typename remove_reference::type, + vertex_index_t>::const_type + >::type vertex_index_map_t; + + boyer_myrvold_impl + + planarity_tester(args[graph], + args[vertex_index_map | + get(vertex_index, args[graph]) + ] + ); + + return planarity_tester.is_planar() ? true : false; + } + + + + template + bool dispatched_boyer_myrvold(ArgumentPack const& args, + mpl::true_, + mpl::false_ + ) + { + //Dispatch for no planar embedding, kuratowski subgraph isolation + typedef typename remove_const + < + typename remove_reference + < typename parameter::binding + < ArgumentPack, tag::graph>::type + >::type + >::type graph_t; + + typedef typename parameter::binding + < ArgumentPack, + tag::vertex_index_map, + typename property_map::type + >::type vertex_index_map_t; + + boyer_myrvold_impl + + planarity_tester(args[graph], + args[vertex_index_map | + get(vertex_index, args[graph]) + ] + ); + + if (planarity_tester.is_planar()) + return true; + else + { + planarity_tester.extract_kuratowski_subgraph + (args[kuratowski_subgraph], + args[edge_index_map|get(edge_index, args[graph])] + ); + return false; + } + } + + + + + template + bool dispatched_boyer_myrvold(ArgumentPack const& args, + mpl::false_, + mpl::true_ + ) + { + //Dispatch for planar embedding, no kuratowski subgraph isolation + typedef typename remove_const + < + typename remove_reference + < typename parameter::binding + < ArgumentPack, tag::graph>::type + >::type + >::type graph_t; + + typedef typename parameter::binding + < ArgumentPack, + tag::vertex_index_map, + typename property_map::type + >::type vertex_index_map_t; + + boyer_myrvold_impl + + planarity_tester(args[graph], + args[vertex_index_map | + get(vertex_index, args[graph]) + ] + ); + + if (planarity_tester.is_planar()) + { + planarity_tester.make_edge_permutation(args[embedding]); + return true; + } + else + return false; + } + + + + template + bool dispatched_boyer_myrvold(ArgumentPack const& args, + mpl::false_, + mpl::false_ + ) + { + //Dispatch for planar embedding, kuratowski subgraph isolation + typedef typename remove_const + < + typename remove_reference + < typename parameter::binding + < ArgumentPack, tag::graph>::type + >::type + >::type graph_t; + + typedef typename parameter::binding + < ArgumentPack, + tag::vertex_index_map, + typename property_map::type + >::type vertex_index_map_t; + + boyer_myrvold_impl + + planarity_tester(args[graph], + args[vertex_index_map | + get(vertex_index, args[graph]) + ] + ); + + if (planarity_tester.is_planar()) + { + planarity_tester.make_edge_permutation(args[embedding]); + return true; + } + else + { + planarity_tester.extract_kuratowski_subgraph + (args[kuratowski_subgraph], + args[edge_index_map | get(edge_index, args[graph])] + ); + return false; + } + } + + + + + template + bool boyer_myrvold_planarity_test(ArgumentPack const& args) + { + + typedef typename parameter::binding + < ArgumentPack, + tag::kuratowski_subgraph, + const no_kuratowski_subgraph_isolation& + >::type + kuratowski_arg_t; + + typedef typename parameter::binding + < ArgumentPack, + tag::embedding, + const no_planar_embedding& + >::type + embedding_arg_t; + + return dispatched_boyer_myrvold + (args, + boost::is_same + (), + boost::is_same + () + ); + } + + + + } //namespace core + + } //namespace boyer_myrvold_params + + + template + bool boyer_myrvold_planarity_test(A0 const& arg0) + { + return boyer_myrvold_params::core::boyer_myrvold_planarity_test + (boyer_myrvold_params::boyer_myrvold_params_t()(arg0)); + } + + template + // bool boyer_myrvold_planarity_test(A0 const& arg0, A1 const& arg1) + bool boyer_myrvold_planarity_test(A0 const& arg0, A1 const& arg1) + { + return boyer_myrvold_params::core::boyer_myrvold_planarity_test + (boyer_myrvold_params::boyer_myrvold_params_t()(arg0,arg1)); + } + + template + bool boyer_myrvold_planarity_test(A0 const& arg0, + A1 const& arg1, + A2 const& arg2 + ) + { + return boyer_myrvold_params::core::boyer_myrvold_planarity_test + (boyer_myrvold_params::boyer_myrvold_params_t()(arg0,arg1,arg2)); + } + + template + bool boyer_myrvold_planarity_test(A0 const& arg0, + A1 const& arg1, + A2 const& arg2, + A3 const& arg3 + ) + { + return boyer_myrvold_params::core::boyer_myrvold_planarity_test + (boyer_myrvold_params::boyer_myrvold_params_t()(arg0,arg1,arg2,arg3)); + } + + template + bool boyer_myrvold_planarity_test(A0 const& arg0, + A1 const& arg1, + A2 const& arg2, + A3 const& arg3, + A4 const& arg4 + ) + { + return boyer_myrvold_params::core::boyer_myrvold_planarity_test + (boyer_myrvold_params::boyer_myrvold_params_t() + (arg0,arg1,arg2,arg3,arg4) + ); + } + + +} + +#endif //__BOYER_MYRVOLD_PLANAR_TEST_HPP__ diff --git a/include/boost/graph/chrobak_payne_drawing.hpp b/include/boost/graph/chrobak_payne_drawing.hpp new file mode 100644 index 00000000..6fb7b56d --- /dev/null +++ b/include/boost/graph/chrobak_payne_drawing.hpp @@ -0,0 +1,270 @@ +//======================================================================= +// 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 __CHROBAK_PAYNE_DRAWING_HPP__ +#define __CHROBAK_PAYNE_DRAWING_HPP__ + +#include +#include +#include +#include //for next and prior +#include +#include + + +namespace boost +{ + + namespace graph { namespace detail + { + + template + void accumulate_offsets(typename graph_traits::vertex_descriptor v, + std::size_t offset, + const Graph& g, + VertexTo1DCoordMap x, + VertexTo1DCoordMap delta_x, + VertexToVertexMap left, + VertexToVertexMap right) + { + if (v != graph_traits::null_vertex()) + { + x[v] += delta_x[v] + offset; + accumulate_offsets(left[v], x[v], g, x, delta_x, left, right); + accumulate_offsets(right[v], x[v], g, x, delta_x, left, right); + } + } + + } /*namespace detail*/ } /*namespace graph*/ + + + + + + template + void chrobak_payne_straight_line_drawing(const Graph& g, + PlanarEmbedding embedding, + ForwardIterator ordering_begin, + ForwardIterator ordering_end, + GridPositionMap drawing, + VertexIndexMap vm + ) + { + + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::edge_descriptor edge_t; + typedef typename graph_traits::vertex_iterator vertex_iterator_t; + typedef typename PlanarEmbedding::value_type::const_iterator + edge_permutation_iterator_t; + typedef typename graph_traits::vertices_size_type v_size_t; + typedef std::vector vertex_vector_t; + typedef std::vector vsize_vector_t; + typedef std::vector bool_vector_t; + typedef boost::iterator_property_map + + vertex_to_vertex_map_t; + typedef boost::iterator_property_map + + vertex_to_vsize_map_t; + typedef boost::iterator_property_map + + vertex_to_bool_map_t; + + vertex_vector_t left_vector(num_vertices(g), + graph_traits::null_vertex() + ); + vertex_vector_t right_vector(num_vertices(g), + graph_traits::null_vertex() + ); + vsize_vector_t seen_as_right_vector(num_vertices(g), 0); + vsize_vector_t seen_vector(num_vertices(g), 0); + vsize_vector_t delta_x_vector(num_vertices(g),0); + vsize_vector_t y_vector(num_vertices(g)); + vsize_vector_t x_vector(num_vertices(g),0); + bool_vector_t installed_vector(num_vertices(g),false); + + vertex_to_vertex_map_t left(left_vector.begin(), vm); + vertex_to_vertex_map_t right(right_vector.begin(), vm); + vertex_to_vsize_map_t seen_as_right(seen_as_right_vector.begin(), vm); + vertex_to_vsize_map_t seen(seen_vector.begin(), vm); + vertex_to_vsize_map_t delta_x(delta_x_vector.begin(), vm); + vertex_to_vsize_map_t y(y_vector.begin(), vm); + vertex_to_vsize_map_t x(x_vector.begin(), vm); + vertex_to_bool_map_t installed(installed_vector.begin(), vm); + + v_size_t timestamp = 1; + vertex_vector_t installed_neighbors; + + ForwardIterator itr = ordering_begin; + vertex_t v1 = *itr; ++itr; + vertex_t v2 = *itr; ++itr; + vertex_t v3 = *itr; ++itr; + + delta_x[v2] = 1; + delta_x[v3] = 1; + + y[v1] = 0; + y[v2] = 0; + y[v3] = 1; + + right[v1] = v3; + right[v3] = v2; + + installed[v1] = installed[v2] = installed[v3] = true; + + for(ForwardIterator itr_end = ordering_end; itr != itr_end; ++itr) + { + vertex_t v = *itr; + + // First, find the leftmost and rightmost neighbor of v on the outer + // cycle of the embedding. + // Note: since we're moving clockwise through the edges adjacent to v, + // we're actually moving from right to left among v's neighbors on the + // outer face (since v will be installed above them all) looking for + // the leftmost and rightmost installed neigbhors + + vertex_t leftmost = graph_traits::null_vertex(); + vertex_t rightmost = graph_traits::null_vertex(); + + installed_neighbors.clear(); + + vertex_t prev_vertex = graph_traits::null_vertex(); + edge_permutation_iterator_t pi, pi_end; + pi_end = embedding[v].end(); + for(pi = embedding[v].begin(); pi != pi_end; ++pi) + { + vertex_t curr_vertex = source(*pi,g) == v ? + target(*pi,g) : source(*pi,g); + + // Skip any self-loops or parallel edges + if (curr_vertex == v || curr_vertex == prev_vertex) + continue; + + if (installed[curr_vertex]) + { + seen[curr_vertex] = timestamp; + + if (right[curr_vertex] != graph_traits::null_vertex()) + { + seen_as_right[right[curr_vertex]] = timestamp; + } + installed_neighbors.push_back(curr_vertex); + } + + prev_vertex = curr_vertex; + } + + typename vertex_vector_t::iterator vi, vi_end; + vi_end = installed_neighbors.end(); + for(vi = installed_neighbors.begin(); vi != vi_end; ++vi) + { + if (right[*vi] == graph_traits::null_vertex() || + seen[right[*vi]] != timestamp + ) + rightmost = *vi; + if (seen_as_right[*vi] != timestamp) + leftmost = *vi; + } + + ++timestamp; + + //stretch gaps + ++delta_x[right[leftmost]]; + ++delta_x[rightmost]; + + //adjust offsets + std::size_t delta_p_q = 0; + vertex_t stopping_vertex = right[rightmost]; + for(vertex_t temp = right[leftmost]; temp != stopping_vertex; + temp = right[temp] + ) + { + delta_p_q += delta_x[temp]; + } + + delta_x[v] = (y[rightmost] - y[leftmost] + delta_p_q)/2; + y[v] = (y[rightmost] + y[leftmost] + delta_p_q)/2; + delta_x[rightmost] = delta_p_q - delta_x[v]; + + bool leftmost_and_rightmost_adjacent = right[leftmost] == rightmost; + if (!leftmost_and_rightmost_adjacent) + delta_x[right[leftmost]] -= delta_x[v]; + + //install v + if (!leftmost_and_rightmost_adjacent) + { + left[v] = right[leftmost]; + vertex_t next_to_rightmost; + for(vertex_t temp = leftmost; temp != rightmost; + temp = right[temp] + ) + { + next_to_rightmost = temp; + } + + right[next_to_rightmost] = graph_traits::null_vertex(); + } + else + { + left[v] = graph_traits::null_vertex(); + } + + right[leftmost] = v; + right[v] = rightmost; + installed[v] = true; + + } + + graph::detail::accumulate_offsets + (*ordering_begin,0,g,x,delta_x,left,right); + + vertex_iterator_t vi, vi_end; + for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + { + vertex_t v(*vi); + drawing[v].x = x[v]; + drawing[v].y = y[v]; + } + + } + + + + + template + inline void chrobak_payne_straight_line_drawing(const Graph& g, + PlanarEmbedding embedding, + ForwardIterator ord_begin, + ForwardIterator ord_end, + GridPositionMap drawing + ) + { + chrobak_payne_straight_line_drawing(g, + embedding, + ord_begin, + ord_end, + drawing, + get(vertex_index,g) + ); + } + + + + +} // namespace boost + +#endif //__CHROBAK_PAYNE_DRAWING_HPP__ diff --git a/include/boost/graph/compressed_sparse_row_graph.hpp b/include/boost/graph/compressed_sparse_row_graph.hpp index 161929cd..8615eda3 100644 --- a/include/boost/graph/compressed_sparse_row_graph.hpp +++ b/include/boost/graph/compressed_sparse_row_graph.hpp @@ -739,7 +739,7 @@ private: typedef graph_traits traits; typedef VertexProperty vertex_bundled; typedef EdgeProperty edge_bundled; - typedef typename ct_if<(detail::is_vertex_bundle::value), + typedef typename mpl::if_c<(detail::is_vertex_bundle::value), typename traits::vertex_descriptor, typename traits::edge_descriptor>::type descriptor; diff --git a/include/boost/graph/detail/adjacency_list.hpp b/include/boost/graph/detail/adjacency_list.hpp index 46b4ea81..0839dc0f 100644 --- a/include/boost/graph/detail/adjacency_list.hpp +++ b/include/boost/graph/detail/adjacency_list.hpp @@ -24,7 +24,9 @@ #include -#include +#include +#include +#include #include #include #include @@ -63,6 +65,11 @@ */ +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Stay out of the way of the concept checking class +# define Graph Graph_ +#endif + namespace boost { namespace detail { @@ -2268,7 +2275,7 @@ namespace boost { typedef typename container_gen::type SeqVertexList; typedef boost::integer_range RandVertexList; - typedef typename boost::ct_if_t::type VertexList; typedef typename VertexList::iterator vertex_iterator; @@ -2278,10 +2285,10 @@ namespace boost { typedef typename container_gen >::type EdgeContainer; - typedef typename ct_and::type >::type on_edge_storage; + typedef typename mpl::and_::type >::type on_edge_storage; - typedef typename boost::ct_if_t::type edges_size_type; @@ -2289,9 +2296,9 @@ namespace boost { typedef typename detail::is_random_access::type is_edge_ra; - typedef typename boost::ct_if_t, - typename boost::ct_if_t, stored_edge_iter >::type @@ -2342,7 +2349,7 @@ namespace boost { typedef adj_list_edge_iterator DirectedEdgeIter; - typedef typename boost::ct_if_t::type edge_iterator; // stored_vertex and StoredVertexList @@ -2376,10 +2383,10 @@ namespace boost { InEdgeList m_in_edges; VertexProperty m_property; }; - typedef typename boost::ct_if_t::type, - typename boost::ct_if_t::type >::type StoredVertex; struct stored_vertex : public StoredVertex { @@ -2389,20 +2396,20 @@ namespace boost { typedef typename container_gen::type RandStoredVertexList; - typedef typename boost::ct_if_t< is_rand_access, + typedef typename mpl::if_< is_rand_access, RandStoredVertexList, SeqStoredVertexList>::type StoredVertexList; }; // end of config - typedef typename boost::ct_if_t, - typename boost::ct_if_t, undirected_graph_helper >::type >::type DirectedHelper; - typedef typename boost::ct_if_t, adj_list_impl >::type type; @@ -2807,6 +2814,11 @@ namespace BOOST_STD_EXTENSION_NAMESPACE { #undef stored_edge_property #undef stored_edge_iter +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Stay out of the way of the concept checking class +#undef Graph +#endif + #endif // BOOST_GRAPH_DETAIL_DETAIL_ADJACENCY_LIST_CCT /* diff --git a/include/boost/graph/detail/bitset.hpp b/include/boost/graph/detail/bitset.hpp deleted file mode 100644 index c6ebf223..00000000 --- a/include/boost/graph/detail/bitset.hpp +++ /dev/null @@ -1,910 +0,0 @@ -//======================================================================= -// Copyright 2001 Jeremy G. Siek -// Authors: Jeremy G. Siek -// -// 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) -//======================================================================= - -/* - * Copyright (c) 1998 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -// This provides versions of std::bitset with both static and dynamic size. - -// UNDER CONSTRUCTION - - -// replace this later -#include -#define BOOST_ASSERT_THROW(expr, except) assert(expr) - -namespace boost { - - namespace detail { - // structure to aid in counting bits - template - struct bit_count { - static unsigned char value[256]; - }; - - // Mapping from 8 bit unsigned integers to the index of the first bit - template - struct first_bit_location { - static unsigned char value[256]; - }; - - template // this size is in bits - struct word_traits { - typedef WordType word_type; - static const std::size_t word_size = CHAR_BIT * sizeof(word_type); - }; - - //========================================================================= - template - class bitset_base - : public bitset_adaptor< SizeType, - bitset_base > - { - // private: - public: - typedef SizeType size_type; - typedef typename WordTraits::word_type word_type; - - static size_type s_which_word(size_type pos) { - return pos / WordTraits::word_size; - } - static size_type s_which_byte(size_type pos) { - return (pos % WordTraits::word_size) / CHAR_BIT; - } - static size_type s_which_bit(size_type pos) { - return pos % WordTraits::word_size; - } - static word_type s_mask_bit(size_type pos) { - return (static_cast(1)) << s_which_bit(pos); - } - word_type& m_get_word(size_type pos) { - return data()[s_which_word(pos)]; - } - word_type m_get_word(size_type pos) const { - return data()[s_which_word(pos)]; - } - word_type& m_hi_word() { return data()[num_words() - 1]; } - word_type m_hi_word() const { return data()[num_words() - 1]; } - - void m_sanitize_highest() { - size_type extra_bits = size() % WordTraits::word_size; - if (extra_bits) - m_hi_word() &= ~((~static_cast(0)) << extra_bits); - } - public: - - class reference { - friend class bitset_base; - - word_type *m_word_ptr; - size_type m_bit_pos; - - // left undefined - reference(); - - reference(bitset_base& b, size_type pos ) { - m_word_ptr = &b.m_get_word(pos); - m_bit_pos = s_which_bit(pos); - } - - public: - ~reference() {} - - // for b[i] = x; - reference& operator=(bool x) { - if ( x ) - *m_word_ptr |= s_mask_bit(m_bit_pos); - else - *m_word_ptr &= ~s_mask_bit(m_bit_pos); - - return *this; - } - // for b[i] = b[j]; - reference& operator=(const reference& j) { - if ( (*(j.m_word_ptr) & s_mask_bit(j.m_bit_pos)) ) - *m_word_ptr |= s_mask_bit(m_bit_pos); - else - *m_word_ptr &= ~s_mask_bit(m_bit_pos); - - return *this; - } - // flips the bit - bool operator~() const { - return (*(m_word_ptr) & s_mask_bit(m_bit_pos)) == 0; - } - // for x = b[i]; - operator bool() const { - return (*(m_word_ptr) & s_mask_bit(m_bit_pos)) != 0; - } - // for b[i].flip(); - reference& flip() { - *m_word_ptr ^= s_mask_bit(m_bit_pos); - return *this; - } - }; - - void init_from_ulong(unsigned long val) { - reset(); - const size_type n = (std::min)(sizeof(unsigned long) * CHAR_BIT, - WordTraits::word_size * num_words()); - for(size_type i = 0; i < n; ++i, val >>= 1) - if ( val & 0x1 ) - m_get_word(i) |= s_mask_bit(i); - } - - // intersection: this = this & x - Derived& operator&=(const Derived& x) { - for (size_type i = 0; i < num_words(); ++i) - data()[i] &= x.data()[i]; - return static_cast(*this); - } - // union: this = this | x - Derived& operator|=(const Derived& x) { - for (size_type i = 0; i < num_words(); ++i) - data()[i] |= x.data()[i]; - return static_cast(*this); - } - // exclusive or: this = this ^ x - Derived& operator^=(const Derived& x) { - for (size_type i = 0; i < num_words(); ++i) - data()[i] ^= x.data()[i]; - return static_cast(*this); - } - // left shift - Derived& operator<<=(size_type pos); - - // right shift - Derived& operator>>=(size_type pos); - - Derived& set() { - for (size_type i = 0; i < num_words(); ++i) - data()[i] = ~static_cast(0); - m_sanitize_highest(); - return static_cast(*this); - } - - Derived& set(size_type pos, int val = true) - { - BOOST_ASSERT_THROW(pos < size(), std::out_of_range("boost::bitset::set(pos,value)")); - if (val) - m_get_word(pos) |= s_mask_bit(pos); - else - m_get_word(pos) &= ~s_mask_bit(pos); - return static_cast(*this); - } - - Derived& reset() { - for (size_type i = 0; i < num_words(); ++i) - data()[i] = 0; - return static_cast(*this); - } - - Derived& reset(size_type pos) { - BOOST_ASSERT_THROW(pos < size(), std::out_of_range("boost::bitset::reset(pos)")); - m_get_word(pos) &= ~s_mask_bit(pos); - return static_cast(*this); - } - - // compliment - Derived operator~() const { - return Derived(static_cast(*this)).flip(); - } - - Derived& flip() { - for (size_type i = 0; i < num_words(); ++i) - data()[i] = ~data()[i]; - m_sanitize_highest(); - return static_cast(*this); - } - Derived& flip(size_type pos) { - BOOST_ASSERT_THROW(pos < size(), std::out_of_range("boost::bitset::flip(pos)")); - m_get_word(pos) ^= s_mask_bit(pos); - return static_cast(*this); - } - - // element access - reference operator[](size_type pos) { return reference(*this, pos); } - bool operator[](size_type pos) const { return test(pos); } - - unsigned long to_ulong() const; - - // to_string - - - size_type count() const { - size_type result = 0; - const unsigned char* byte_ptr = (const unsigned char*)data(); - const unsigned char* end_ptr = - (const unsigned char*)(data() + num_words()); - while ( byte_ptr < end_ptr ) { - result += bit_count<>::value[*byte_ptr]; - byte_ptr++; - } - return result; - } - - // size() must be provided by Derived class - - bool operator==(const Derived& x) const { - return std::equal(data(), data() + num_words(), x.data()); - } - - bool operator!=(const Derived& x) const { - return ! this->operator==(x); - } - - bool test(size_type pos) const { - BOOST_ASSERT_THROW(pos < size(), std::out_of_range("boost::bitset::test(pos)")); - return (m_get_word(pos) & s_mask_bit(pos)) - != static_cast(0); - } - - bool any() const { - for (size_type i = 0; i < num_words(); ++i) { - if ( data()[i] != static_cast(0) ) - return true; - } - return false; - } - bool none() const { - return !any(); - } - - Derived operator<<(size_type pos) const - { return Derived(static_cast(*this)) <<= pos; } - - Derived operator>>(size_type pos) const - { return Derived(static_cast(*this)) >>= pos; } - - template - void m_copy_from_string(const basic_string& s, - size_type pos, size_type n) - { - reset(); - const size_type nbits = (std::min)(size(), (std::min)(n, s.size() - pos)); - for (size_type i = 0; i < nbits; ++i) { - switch(s[pos + nbits - i - 1]) { - case '0': - break; - case '1': - this->set(i); - break; - default: - throw std::invalid_argument - ("boost::bitset_base::m_copy_from_string(s, pos, n)"); - } - } - } - - template - void m_copy_to_string(basic_string& s) const - { - s.assign(size(), '0'); - - for (size_type i = 0; i < size(); ++i) - if (test(i)) - s[size() - 1 - i] = '1'; - } - - //----------------------------------------------------------------------- - // Stuff not in std::bitset - - // difference: this = this - x - Derived& operator-=(const Derived& x) { - for (size_type i = 0; i < num_words(); ++i) - data()[i] &= ~x.data()[i]; - return static_cast(*this); - } - - // this wasn't working, why? - int compare_3way(const Derived& x) const { - return std::lexicographical_compare_3way - (data(), data() + num_words(), x.data(), x.data() + x.num_words()); - } - - // less-than compare - bool operator<(const Derived& x) const { - return std::lexicographical_compare - (data(), data() + num_words(), x.data(), x.data() + x.num_words()); - } - - // find the index of the first "on" bit - size_type find_first() const; - - // find the index of the next "on" bit after prev - size_type find_next(size_type prev) const; - - - size_type _Find_first() const { return find_first(); } - - // find the index of the next "on" bit after prev - size_type _Find_next(size_type prev) const { return find_next(prev); } - - // private: - word_type* data() - { return static_cast(this)->data(); } - - const word_type* data() const - { return static_cast(this)->data(); } - - size_type num_words() const - { return static_cast(this)->num_words(); } - - size_type size() const - { return static_cast(this)->size(); } - }; - - // 23.3.5.3 bitset operations: - template - inline D operator&(const bitset_base& x, - const bitset_base& y) { - D result(static_cast(x)); - result &= static_cast(y); - return result; - } - - template - inline D operator|(const bitset_base& x, - const bitset_base& y) { - D result(static_cast(x)); - result |= static_cast(y); - return result; - } - - template - inline D operator^(const bitset_base& x, - const bitset_base& y) { - D result(static_cast(x)); - result ^= static_cast(y); - return result; - } - - // this one is an extension - template - inline D operator-(const bitset_base& x, - const bitset_base& y) { - D result(static_cast(x)); - result -= static_cast(y); - return result; - } - - template - inline int compare_3way(const bitset_base& x, - const bitset_base& y) { - return std::lexicographical_compare_3way - (x.data(), x.data() + x.num_words(), - y.data(), y.data() + y.num_words()); - } - - - template - std::istream& - operator>>(std::istream& is, bitset_base& x) { - std::string tmp; - tmp.reserve(x.size()); - - // In new templatized iostreams, use istream::sentry - if (is.flags() & ios::skipws) { - char c; - do - is.get(c); - while (is && isspace(c)); - if (is) - is.putback(c); - } - - for (S i = 0; i < x.size(); ++i) { - char c; - is.get(c); - - if (!is) - break; - else if (c != '0' && c != '1') { - is.putback(c); - break; - } - else - // tmp.push_back(c); - tmp += c; - } - - if (tmp.empty()) - is.clear(is.rdstate() | ios::failbit); - else - x.m_copy_from_string(tmp, static_cast(0), x.size()); - - return is; - } - - template - std::ostream& operator<<(std::ostream& os, - const bitset_base& x) { - std::string tmp; - x.m_copy_to_string(tmp); - return os << tmp; - } - - //========================================================================= - template - > - class dyn_size_bitset - : public bitset_base, SizeType, - dyn_size_bitset > - { - typedef dyn_size_bitset self; - public: - typedef SizeType size_type; - private: - typedef word_traits WordTraits; - static const size_type word_size = WordTraits::word_size; - - public: - dyn_size_bitset(unsigned long val, - size_type n, - const Allocator& alloc = Allocator()) - : m_data(alloc.allocate((n + word_size - 1) / word_size)), - m_size(n), - m_num_words((n + word_size - 1) / word_size), - m_alloc(alloc) - { - init_from_ulong(val); - } - - dyn_size_bitset(size_type n, // size of the set's "universe" - const Allocator& alloc = Allocator()) - : m_data(alloc.allocate((n + word_size - 1) / word_size)), - m_size(n), m_num_words((n + word_size - 1) / word_size), - m_alloc(alloc) - { } - - template - explicit dyn_size_bitset - (const basic_string& s, - std::size_t pos = 0, - std::size_t n = std::size_t(basic_string::npos), - const Allocator& alloc = Allocator()) - : m_data(alloc.allocate((n + word_size - 1) / word_size)), - m_size(n), m_num_words((n + word_size - 1) / word_size), - m_alloc(alloc) - { - BOOST_ASSERT_THROW(pos < s.size(), std::out_of_range("dyn_size_bitset::dyn_size_bitset(s,pos,n,alloc)")); - m_copy_from_string(s, pos, n); - } - - template - explicit dyn_size_bitset - (InputIterator first, InputIterator last, - size_type n, // size of the set's "universe" - const Allocator& alloc = Allocator()) - : m_data(alloc.allocate((n + word_size - 1) / word_size)), - m_size(N), m_num_words((n + word_size - 1) / word_size), - m_alloc(alloc) - { - while (first != last) - this->set(*first++); - } - - ~dyn_size_bitset() { - m_alloc.deallocate(m_data, m_num_words); - } - - size_type size() const { return m_size; } - - // protected: - size_type num_words() const { return m_num_words; } - - word_type* data() { return m_data; } - const word_type* data() const { return m_data; } - - protected: - word_type* m_data; - SizeType m_size; - SizeType m_num_words; - Allocator m_alloc; - }; - - //========================================================================= - template - class bitset - : public bitset_base, SizeType, - bitset > - { - typedef bitset self; - static const std::size_t word_size = word_traits::word_size; - public: - // 23.3.5.1 constructors: - bitset() { -#if defined(__GNUC__) - for (size_type i = 0; i < num_words(); ++i) - m_data[i] = static_cast(0); -#endif - } - - bitset(unsigned long val) { - init_from_ulong(val); - } - - template - explicit bitset - (const basic_string& s, - std::size_t pos = 0, - std::size_t n = std::size_t(basic_string::npos)) - { - BOOST_ASSERT_THROW - (pos < s.size(), std::out_of_range("bitset::bitset(s,pos,n)")); - m_copy_from_string(s, pos, n); - } - - size_type size() const { return N; } - - // protected: - size_type num_words() const { return (N + word_size - 1) / word_size; } - - word_type* data() { return m_data; } - const word_type* data() const { return m_data; } - protected: - word_type m_data[(N + word_size - 1) / word_size]; - }; - - //========================================================================= - struct select_static_bitset { - template - struct bind_ { - typedef bitset type; - }; - }; - struct select_dyn_size_bitset { - template - struct bind_ { - typedef dyn_size_bitset type; - }; - }; - - template - > - class bitset_generator { - typedef typename ct_if::type selector; - public: - typedef typename selector - ::template bind_::type type; - }; - - - //========================================================================= - // bitset_base non-inline member function implementations - - template - Derived& - bitset_base:: - operator<<=(size_type shift) - { - typedef typename WordTraits::word_type word_type; - typedef SizeType size_type; - if (shift != 0) { - const size_type wshift = shift / WordTraits::word_size; - const size_type offset = shift % WordTraits::word_size; - const size_type sub_offset = WordTraits::word_size - offset; - size_type n = num_words() - 1; - for ( ; n > wshift; --n) - data()[n] = (data()[n - wshift] << offset) | - (data()[n - wshift - 1] >> sub_offset); - if (n == wshift) - data()[n] = data()[0] << offset; - for (size_type n1 = 0; n1 < n; ++n1) - data()[n1] = static_cast(0); - } - m_sanitize_highest(); - return static_cast(*this); - } // end operator<<= - - - template - Derived& - bitset_base:: - operator>>=(size_type shift) - { - typedef typename WordTraits::word_type word_type; - typedef SizeType size_type; - if (shift != 0) { - const size_type wshift = shift / WordTraits::word_size; - const size_type offset = shift % WordTraits::word_size; - const size_type sub_offset = WordTraits::word_size - offset; - const size_type limit = num_words() - wshift - 1; - size_type n = 0; - for ( ; n < limit; ++n) - data()[n] = (data()[n + wshift] >> offset) | - (data()[n + wshift + 1] << sub_offset); - data()[limit] = data()[num_words()-1] >> offset; - for (size_type n1 = limit + 1; n1 < num_words(); ++n1) - data()[n1] = static_cast(0); - } - m_sanitize_highest(); - return static_cast(*this); - } // end operator>>= - - - template - unsigned long bitset_base:: - to_ulong() const - { - typedef typename WordTraits::word_type word_type; - typedef SizeType size_type; - const std::overflow_error - overflow("boost::bit_set::operator unsigned long()"); - - if (sizeof(word_type) >= sizeof(unsigned long)) { - for (size_type i = 1; i < num_words(); ++i) - BOOST_ASSERT_THROW(! data()[i], overflow); - - const word_type mask - = static_cast(static_cast(-1)); - BOOST_ASSERT_THROW(! (data()[0] & ~mask), overflow); - - return static_cast(data()[0] & mask); - } - else { // sizeof(word_type) < sizeof(unsigned long). - const size_type nwords = - (sizeof(unsigned long) + sizeof(word_type) - 1) / sizeof(word_type); - - size_type min_nwords = nwords; - if (num_words() > nwords) { - for (size_type i = nwords; i < num_words(); ++i) - BOOST_ASSERT_THROW(!data()[i], overflow); - } - else - min_nwords = num_words(); - - // If unsigned long is 8 bytes and word_type is 6 bytes, then - // an unsigned long consists of all of one word plus 2 bytes - // from another word. - const size_type part = sizeof(unsigned long) % sizeof(word_type); - -#if 0 - // bug in here? - // >> to far? - BOOST_ASSERT_THROW((part != 0 - && nwords <= num_words() - && (data()[min_nwords - 1] >> - ((sizeof(word_type) - part) * CHAR_BIT)) != 0), - overflow); -#endif - - unsigned long result = 0; - for (size_type i = 0; i < min_nwords; ++i) { - result |= static_cast( - data()[i]) << (i * sizeof(word_type) * CHAR_BIT); - } - return result; - } - }// end operator unsigned long() - - - template - SizeType bitset_base:: - find_first() const - { - SizeType not_found = size(); - for (size_type i = 0; i < num_words(); i++ ) { - word_type thisword = data()[i]; - if ( thisword != static_cast(0) ) { - // find byte within word - for ( std::size_t j = 0; j < sizeof(word_type); j++ ) { - unsigned char this_byte - = static_cast(thisword & (~(unsigned char)0)); - if ( this_byte ) - return i * WordTraits::word_size + j * CHAR_BIT + - first_bit_location<>::value[this_byte]; - - thisword >>= CHAR_BIT; - } - } - } - // not found, so return an indication of failure. - return not_found; - } - - template - SizeType bitset_base:: - bitset_base:: - find_next(size_type prev) const - { - SizeType not_found = size(); - // make bound inclusive - ++prev; - - // check out of bounds - if ( prev >= num_words() * WordTraits::word_size ) - return not_found; - - // search first word - size_type i = s_which_word(prev); - word_type thisword = data()[i]; - - // mask off bits below bound - thisword &= (~static_cast(0)) << s_which_bit(prev); - - if ( thisword != static_cast(0) ) { - // find byte within word - // get first byte into place - thisword >>= s_which_byte(prev) * CHAR_BIT; - for ( size_type j = s_which_byte(prev); j < sizeof(word_type); j++ ) { - unsigned char this_byte - = static_cast(thisword & (~(unsigned char)0)); - if ( this_byte ) - return i * WordTraits::word_size + j * CHAR_BIT + - first_bit_location<>::value[this_byte]; - - thisword >>= CHAR_BIT; - } - } - - // check subsequent words - i++; - for ( ; i < num_words(); i++ ) { - word_type thisword = data()[i]; - if ( thisword != static_cast(0) ) { - // find byte within word - for ( size_type j = 0; j < sizeof(word_type); j++ ) { - unsigned char this_byte - = static_cast(thisword & (~(unsigned char)0)); - if ( this_byte ) - return i * WordTraits::word_size + j * CHAR_BIT + - first_bit_location<>::value[this_byte]; - - thisword >>= CHAR_BIT; - } - } - } - - // not found, so return an indication of failure. - return not_found; - } // end find_next - - - template - unsigned char bit_count::value[] = { - 0, /* 0 */ 1, /* 1 */ 1, /* 2 */ 2, /* 3 */ 1, /* 4 */ - 2, /* 5 */ 2, /* 6 */ 3, /* 7 */ 1, /* 8 */ 2, /* 9 */ - 2, /* 10 */ 3, /* 11 */ 2, /* 12 */ 3, /* 13 */ 3, /* 14 */ - 4, /* 15 */ 1, /* 16 */ 2, /* 17 */ 2, /* 18 */ 3, /* 19 */ - 2, /* 20 */ 3, /* 21 */ 3, /* 22 */ 4, /* 23 */ 2, /* 24 */ - 3, /* 25 */ 3, /* 26 */ 4, /* 27 */ 3, /* 28 */ 4, /* 29 */ - 4, /* 30 */ 5, /* 31 */ 1, /* 32 */ 2, /* 33 */ 2, /* 34 */ - 3, /* 35 */ 2, /* 36 */ 3, /* 37 */ 3, /* 38 */ 4, /* 39 */ - 2, /* 40 */ 3, /* 41 */ 3, /* 42 */ 4, /* 43 */ 3, /* 44 */ - 4, /* 45 */ 4, /* 46 */ 5, /* 47 */ 2, /* 48 */ 3, /* 49 */ - 3, /* 50 */ 4, /* 51 */ 3, /* 52 */ 4, /* 53 */ 4, /* 54 */ - 5, /* 55 */ 3, /* 56 */ 4, /* 57 */ 4, /* 58 */ 5, /* 59 */ - 4, /* 60 */ 5, /* 61 */ 5, /* 62 */ 6, /* 63 */ 1, /* 64 */ - 2, /* 65 */ 2, /* 66 */ 3, /* 67 */ 2, /* 68 */ 3, /* 69 */ - 3, /* 70 */ 4, /* 71 */ 2, /* 72 */ 3, /* 73 */ 3, /* 74 */ - 4, /* 75 */ 3, /* 76 */ 4, /* 77 */ 4, /* 78 */ 5, /* 79 */ - 2, /* 80 */ 3, /* 81 */ 3, /* 82 */ 4, /* 83 */ 3, /* 84 */ - 4, /* 85 */ 4, /* 86 */ 5, /* 87 */ 3, /* 88 */ 4, /* 89 */ - 4, /* 90 */ 5, /* 91 */ 4, /* 92 */ 5, /* 93 */ 5, /* 94 */ - 6, /* 95 */ 2, /* 96 */ 3, /* 97 */ 3, /* 98 */ 4, /* 99 */ - 3, /* 100 */ 4, /* 101 */ 4, /* 102 */ 5, /* 103 */ 3, /* 104 */ - 4, /* 105 */ 4, /* 106 */ 5, /* 107 */ 4, /* 108 */ 5, /* 109 */ - 5, /* 110 */ 6, /* 111 */ 3, /* 112 */ 4, /* 113 */ 4, /* 114 */ - 5, /* 115 */ 4, /* 116 */ 5, /* 117 */ 5, /* 118 */ 6, /* 119 */ - 4, /* 120 */ 5, /* 121 */ 5, /* 122 */ 6, /* 123 */ 5, /* 124 */ - 6, /* 125 */ 6, /* 126 */ 7, /* 127 */ 1, /* 128 */ 2, /* 129 */ - 2, /* 130 */ 3, /* 131 */ 2, /* 132 */ 3, /* 133 */ 3, /* 134 */ - 4, /* 135 */ 2, /* 136 */ 3, /* 137 */ 3, /* 138 */ 4, /* 139 */ - 3, /* 140 */ 4, /* 141 */ 4, /* 142 */ 5, /* 143 */ 2, /* 144 */ - 3, /* 145 */ 3, /* 146 */ 4, /* 147 */ 3, /* 148 */ 4, /* 149 */ - 4, /* 150 */ 5, /* 151 */ 3, /* 152 */ 4, /* 153 */ 4, /* 154 */ - 5, /* 155 */ 4, /* 156 */ 5, /* 157 */ 5, /* 158 */ 6, /* 159 */ - 2, /* 160 */ 3, /* 161 */ 3, /* 162 */ 4, /* 163 */ 3, /* 164 */ - 4, /* 165 */ 4, /* 166 */ 5, /* 167 */ 3, /* 168 */ 4, /* 169 */ - 4, /* 170 */ 5, /* 171 */ 4, /* 172 */ 5, /* 173 */ 5, /* 174 */ - 6, /* 175 */ 3, /* 176 */ 4, /* 177 */ 4, /* 178 */ 5, /* 179 */ - 4, /* 180 */ 5, /* 181 */ 5, /* 182 */ 6, /* 183 */ 4, /* 184 */ - 5, /* 185 */ 5, /* 186 */ 6, /* 187 */ 5, /* 188 */ 6, /* 189 */ - 6, /* 190 */ 7, /* 191 */ 2, /* 192 */ 3, /* 193 */ 3, /* 194 */ - 4, /* 195 */ 3, /* 196 */ 4, /* 197 */ 4, /* 198 */ 5, /* 199 */ - 3, /* 200 */ 4, /* 201 */ 4, /* 202 */ 5, /* 203 */ 4, /* 204 */ - 5, /* 205 */ 5, /* 206 */ 6, /* 207 */ 3, /* 208 */ 4, /* 209 */ - 4, /* 210 */ 5, /* 211 */ 4, /* 212 */ 5, /* 213 */ 5, /* 214 */ - 6, /* 215 */ 4, /* 216 */ 5, /* 217 */ 5, /* 218 */ 6, /* 219 */ - 5, /* 220 */ 6, /* 221 */ 6, /* 222 */ 7, /* 223 */ 3, /* 224 */ - 4, /* 225 */ 4, /* 226 */ 5, /* 227 */ 4, /* 228 */ 5, /* 229 */ - 5, /* 230 */ 6, /* 231 */ 4, /* 232 */ 5, /* 233 */ 5, /* 234 */ - 6, /* 235 */ 5, /* 236 */ 6, /* 237 */ 6, /* 238 */ 7, /* 239 */ - 4, /* 240 */ 5, /* 241 */ 5, /* 242 */ 6, /* 243 */ 5, /* 244 */ - 6, /* 245 */ 6, /* 246 */ 7, /* 247 */ 5, /* 248 */ 6, /* 249 */ - 6, /* 250 */ 7, /* 251 */ 6, /* 252 */ 7, /* 253 */ 7, /* 254 */ - 8 /* 255 */ - }; // end _Bit_count - - template - unsigned char first_bit_location::value[] = { - 0, /* 0 */ 0, /* 1 */ 1, /* 2 */ 0, /* 3 */ 2, /* 4 */ - 0, /* 5 */ 1, /* 6 */ 0, /* 7 */ 3, /* 8 */ 0, /* 9 */ - 1, /* 10 */ 0, /* 11 */ 2, /* 12 */ 0, /* 13 */ 1, /* 14 */ - 0, /* 15 */ 4, /* 16 */ 0, /* 17 */ 1, /* 18 */ 0, /* 19 */ - 2, /* 20 */ 0, /* 21 */ 1, /* 22 */ 0, /* 23 */ 3, /* 24 */ - 0, /* 25 */ 1, /* 26 */ 0, /* 27 */ 2, /* 28 */ 0, /* 29 */ - 1, /* 30 */ 0, /* 31 */ 5, /* 32 */ 0, /* 33 */ 1, /* 34 */ - 0, /* 35 */ 2, /* 36 */ 0, /* 37 */ 1, /* 38 */ 0, /* 39 */ - 3, /* 40 */ 0, /* 41 */ 1, /* 42 */ 0, /* 43 */ 2, /* 44 */ - 0, /* 45 */ 1, /* 46 */ 0, /* 47 */ 4, /* 48 */ 0, /* 49 */ - 1, /* 50 */ 0, /* 51 */ 2, /* 52 */ 0, /* 53 */ 1, /* 54 */ - 0, /* 55 */ 3, /* 56 */ 0, /* 57 */ 1, /* 58 */ 0, /* 59 */ - 2, /* 60 */ 0, /* 61 */ 1, /* 62 */ 0, /* 63 */ 6, /* 64 */ - 0, /* 65 */ 1, /* 66 */ 0, /* 67 */ 2, /* 68 */ 0, /* 69 */ - 1, /* 70 */ 0, /* 71 */ 3, /* 72 */ 0, /* 73 */ 1, /* 74 */ - 0, /* 75 */ 2, /* 76 */ 0, /* 77 */ 1, /* 78 */ 0, /* 79 */ - 4, /* 80 */ 0, /* 81 */ 1, /* 82 */ 0, /* 83 */ 2, /* 84 */ - 0, /* 85 */ 1, /* 86 */ 0, /* 87 */ 3, /* 88 */ 0, /* 89 */ - 1, /* 90 */ 0, /* 91 */ 2, /* 92 */ 0, /* 93 */ 1, /* 94 */ - 0, /* 95 */ 5, /* 96 */ 0, /* 97 */ 1, /* 98 */ 0, /* 99 */ - 2, /* 100 */ 0, /* 101 */ 1, /* 102 */ 0, /* 103 */ 3, /* 104 */ - 0, /* 105 */ 1, /* 106 */ 0, /* 107 */ 2, /* 108 */ 0, /* 109 */ - 1, /* 110 */ 0, /* 111 */ 4, /* 112 */ 0, /* 113 */ 1, /* 114 */ - 0, /* 115 */ 2, /* 116 */ 0, /* 117 */ 1, /* 118 */ 0, /* 119 */ - 3, /* 120 */ 0, /* 121 */ 1, /* 122 */ 0, /* 123 */ 2, /* 124 */ - 0, /* 125 */ 1, /* 126 */ 0, /* 127 */ 7, /* 128 */ 0, /* 129 */ - 1, /* 130 */ 0, /* 131 */ 2, /* 132 */ 0, /* 133 */ 1, /* 134 */ - 0, /* 135 */ 3, /* 136 */ 0, /* 137 */ 1, /* 138 */ 0, /* 139 */ - 2, /* 140 */ 0, /* 141 */ 1, /* 142 */ 0, /* 143 */ 4, /* 144 */ - 0, /* 145 */ 1, /* 146 */ 0, /* 147 */ 2, /* 148 */ 0, /* 149 */ - 1, /* 150 */ 0, /* 151 */ 3, /* 152 */ 0, /* 153 */ 1, /* 154 */ - 0, /* 155 */ 2, /* 156 */ 0, /* 157 */ 1, /* 158 */ 0, /* 159 */ - 5, /* 160 */ 0, /* 161 */ 1, /* 162 */ 0, /* 163 */ 2, /* 164 */ - 0, /* 165 */ 1, /* 166 */ 0, /* 167 */ 3, /* 168 */ 0, /* 169 */ - 1, /* 170 */ 0, /* 171 */ 2, /* 172 */ 0, /* 173 */ 1, /* 174 */ - 0, /* 175 */ 4, /* 176 */ 0, /* 177 */ 1, /* 178 */ 0, /* 179 */ - 2, /* 180 */ 0, /* 181 */ 1, /* 182 */ 0, /* 183 */ 3, /* 184 */ - 0, /* 185 */ 1, /* 186 */ 0, /* 187 */ 2, /* 188 */ 0, /* 189 */ - 1, /* 190 */ 0, /* 191 */ 6, /* 192 */ 0, /* 193 */ 1, /* 194 */ - 0, /* 195 */ 2, /* 196 */ 0, /* 197 */ 1, /* 198 */ 0, /* 199 */ - 3, /* 200 */ 0, /* 201 */ 1, /* 202 */ 0, /* 203 */ 2, /* 204 */ - 0, /* 205 */ 1, /* 206 */ 0, /* 207 */ 4, /* 208 */ 0, /* 209 */ - 1, /* 210 */ 0, /* 211 */ 2, /* 212 */ 0, /* 213 */ 1, /* 214 */ - 0, /* 215 */ 3, /* 216 */ 0, /* 217 */ 1, /* 218 */ 0, /* 219 */ - 2, /* 220 */ 0, /* 221 */ 1, /* 222 */ 0, /* 223 */ 5, /* 224 */ - 0, /* 225 */ 1, /* 226 */ 0, /* 227 */ 2, /* 228 */ 0, /* 229 */ - 1, /* 230 */ 0, /* 231 */ 3, /* 232 */ 0, /* 233 */ 1, /* 234 */ - 0, /* 235 */ 2, /* 236 */ 0, /* 237 */ 1, /* 238 */ 0, /* 239 */ - 4, /* 240 */ 0, /* 241 */ 1, /* 242 */ 0, /* 243 */ 2, /* 244 */ - 0, /* 245 */ 1, /* 246 */ 0, /* 247 */ 3, /* 248 */ 0, /* 249 */ - 1, /* 250 */ 0, /* 251 */ 2, /* 252 */ 0, /* 253 */ 1, /* 254 */ - 0, /* 255 */ - }; // end _First_one - - } // namespace detail - -} // namespace boost diff --git a/include/boost/graph/detail/bitset_adaptor.hpp b/include/boost/graph/detail/bitset_adaptor.hpp deleted file mode 100644 index d301b7d6..00000000 --- a/include/boost/graph/detail/bitset_adaptor.hpp +++ /dev/null @@ -1,90 +0,0 @@ -//======================================================================= -// Copyright 2002 Indiana University. -// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek -// -// 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 BOOST_BITSET_ADAPTOR_HPP -#define BOOST_BITSET_ADAPTOR_HPP - - template - struct bitset_adaptor { - Derived& derived() { return static_cast(*this); } - const Derived& derived() const { - return static_cast(*this); - } - }; - - template - bool set_contains(const bitset_adaptor& s, const V& x) { - return s.derived().test(x); - } - - template - bool set_equal(const bitset_adaptor& x, - const bitset_adaptor& y) { - return x.derived() == y.derived(); - } - - template - int set_lex_order(const bitset_adaptor& x, - const bitset_adaptor& y) { - return compare_3way(x.derived(), y.derived()); - } - - template - void set_clear(bitset_adaptor& x) { - x.derived().reset(); - } - - template - bool set_empty(const bitset_adaptor& x) { - return x.derived().none(); - } - - template - void set_insert(bitset_adaptor& x, const V& a) { - x.derived().set(a); - } - - template - void set_remove(bitset_adaptor& x, const V& a) { - x.derived().set(a, false); - } - - template - void set_intersect(const bitset_adaptor& x, - const bitset_adaptor& y, - bitset_adaptor& z) - { - z.derived() = x.derived() & y.derived(); - } - - template - void set_union(const bitset_adaptor& x, - const bitset_adaptor& y, - bitset_adaptor& z) - { - z.derived() = x.derived() | y.derived(); - } - - template - void set_difference(const bitset_adaptor& x, - const bitset_adaptor& y, - bitset_adaptor& z) - { - z.derived() = x.derived() - y.derived(); - } - - template - void set_compliment(const bitset_adaptor& x, - bitset_adaptor& z) - { - z.derived() = x.derived(); - z.derived().flip(); - } - -#endif // BOOST_BITSET_ADAPTOR_HPP diff --git a/include/boost/graph/detail/edge.hpp b/include/boost/graph/detail/edge.hpp index 8ab375f0..da085973 100644 --- a/include/boost/graph/detail/edge.hpp +++ b/include/boost/graph/detail/edge.hpp @@ -49,7 +49,7 @@ namespace boost { // protected: property_type* m_eproperty; }; - + template inline bool operator==(const detail::edge_desc_impl& a, @@ -65,6 +65,36 @@ namespace boost { return ! (a.get_property() == b.get_property()); } + // Order edges according to the address of their property object + template + inline bool + operator<(const detail::edge_desc_impl& a, + const detail::edge_desc_impl& b) + { + return a.get_property() < b.get_property(); + } + template + inline bool + operator<=(const detail::edge_desc_impl& a, + const detail::edge_desc_impl& b) + { + return a.get_property() <= b.get_property(); + } + template + inline bool + operator>(const detail::edge_desc_impl& a, + const detail::edge_desc_impl& b) + { + return a.get_property() > b.get_property(); + } + template + inline bool + operator>=(const detail::edge_desc_impl& a, + const detail::edge_desc_impl& b) + { + return a.get_property() >= b.get_property(); + } + } //namespace detail } // namespace boost diff --git a/include/boost/graph/detail/is_same.hpp b/include/boost/graph/detail/is_same.hpp index cda8d561..8027a47a 100644 --- a/include/boost/graph/detail/is_same.hpp +++ b/include/boost/graph/detail/is_same.hpp @@ -9,7 +9,7 @@ #ifndef BOOST_GRAPH_DETAIL_IS_SAME_HPP #define BOOST_GRAPH_DETAIL_IS_SAME_HPP -#include +#include namespace boost { struct false_tag; @@ -30,7 +30,7 @@ namespace boost { template struct is_same { enum { Unum = U::num, Vnum = V::num }; - typedef typename boost::ct_if< (Unum == Vnum), + typedef typename mpl::if_c< (Unum == Vnum), boost::true_tag, boost::false_tag>::type is_same_tag; }; #endif diff --git a/include/boost/graph/detail/read_graphviz_spirit.hpp b/include/boost/graph/detail/read_graphviz_spirit.hpp index 56bd4f8c..0c483349 100644 --- a/include/boost/graph/detail/read_graphviz_spirit.hpp +++ b/include/boost/graph/detail/read_graphviz_spirit.hpp @@ -149,7 +149,7 @@ struct dot_grammar : public boost::spirit::grammar { ID = ( lexeme_d[((alpha_p | ch_p('_')) >> *(alnum_p | ch_p('_')))] | real_p - | confix_p('"', *c_escape_ch_p, '"') + | lexeme_d[confix_p('"', *c_escape_ch_p, '"')] | comment_nest_p('<', '>') )[ID.name = construct_(arg1,arg2)] ; @@ -161,7 +161,7 @@ struct dot_grammar : public boost::spirit::grammar { >> !( ch_p('=') >> ID[a_list.value = arg1]) [phoenix::bind(&definition::call_prop_actor) - (var(*this),a_list.key,a_list.value)],ch_p(',')); + (var(*this),a_list.key,a_list.value)],!ch_p(',')); attr_list = +(ch_p('[') >> !a_list >> ch_p(']')); @@ -182,6 +182,14 @@ struct dot_grammar : public boost::spirit::grammar { = ( ID[node_id.name = arg1] >> (!port) ) [phoenix::bind(&definition::memoize_node)(var(*this))]; + graph_stmt + = (ID[graph_stmt.key = arg1] >> + ch_p('=') >> + ID[graph_stmt.value = arg1]) + [phoenix::bind(&definition::call_graph_prop) + (var(*this),graph_stmt.key,graph_stmt.value)] + ; // Graph property. + attr_stmt = (as_lower_d[keyword_p("graph")] >> attr_list(actor_t(phoenix::bind(&definition::default_graph_prop) @@ -236,7 +244,7 @@ struct dot_grammar : public boost::spirit::grammar { stmt - = (ID >> ch_p('=') >> ID) // Graph property -- ignore. + = graph_stmt | attr_stmt | data_stmt ; @@ -331,7 +339,7 @@ struct dot_grammar : public boost::spirit::grammar { edge_stack_t& edge_stack = data_stmt.edge_stack(); for(nodes_t::iterator i = sources.begin(); i != sources.end(); ++i) { for(nodes_t::iterator j = dests.begin(); j != dests.end(); ++j) { - // Create the edge and and push onto the edge stack. + // Create the edge and push onto the edge stack. #ifdef BOOST_GRAPH_DEBUG std::cout << "Edge " << *i << " to " << *j << std::endl; #endif // BOOST_GRAPH_DEBUG @@ -376,8 +384,13 @@ struct dot_grammar : public boost::spirit::grammar { } } - // default_graph_prop - Just ignore graph properties. - void default_graph_prop(id_t const&, id_t const&) { } + // default_graph_prop - Store as a graph property. + void default_graph_prop(id_t const& key, id_t const& value) { +#ifdef BOOST_GRAPH_DEBUG + std::cout << key << " = " << value << std::endl; +#endif // BOOST_GRAPH_DEBUG + self.graph_.set_graph_property(key, value); + } // default_node_prop - declare default properties for any future new nodes void default_node_prop(id_t const& key, id_t const& value) { @@ -432,6 +445,15 @@ struct dot_grammar : public boost::spirit::grammar { actor(lhs,rhs); } + void call_graph_prop(std::string const& lhs, std::string const& rhs) { + // If first and last characters of the rhs are double-quotes, + // remove them. + if (!rhs.empty() && rhs[0] == '"' && rhs[rhs.size() - 1] == '"') + this->default_graph_prop(lhs, rhs.substr(1, rhs.size()-2)); + else + this->default_graph_prop(lhs,rhs); + } + void set_node_property(node_t const& node, id_t const& key, id_t const& value) { @@ -454,7 +476,11 @@ struct dot_grammar : public boost::spirit::grammar { self.graph_.set_edge_property(key, edge, value); #ifdef BOOST_GRAPH_DEBUG // Tell the world - std::cout << "(" << edge.first << "," << edge.second << "): " +#if 0 // RG - edge representation changed, + std::cout << "(" << edge.first << "," << edge.second << "): " +#else + std::cout << "an edge: " +#endif // 0 << key << " = " << value << std::endl; #endif // BOOST_GRAPH_DEBUG } @@ -476,6 +502,7 @@ struct dot_grammar : public boost::spirit::grammar { rule_t port_angle; rule_t port; boost::spirit::rule node_id; + boost::spirit::rule graph_stmt; rule_t attr_stmt; boost::spirit::rule data_stmt; boost::spirit::rule subgraph; @@ -527,9 +554,9 @@ struct dot_skipper : public boost::spirit::grammar using namespace boost::spirit; using namespace phoenix; // comment forms - skip = space_p + skip = eol_p >> comment_p("#") + | space_p | comment_p("//") - | comment_p("#") #if BOOST_WORKAROUND(BOOST_MSVC, <= 1400) | confix_p(str_p("/*") ,*anychar_p, str_p("*/")) #else diff --git a/include/boost/graph/edge_list.hpp b/include/boost/graph/edge_list.hpp index 46fdde69..32c5c259 100644 --- a/include/boost/graph/edge_list.hpp +++ b/include/boost/graph/edge_list.hpp @@ -13,7 +13,8 @@ #include #include -#include +#include +#include #include #include #include @@ -241,11 +242,11 @@ namespace boost { template struct is_random { enum { RET = false }; - typedef false_type type; + typedef mpl::false_ type; }; template <> struct is_random { - enum { RET = true }; typedef true_type type; + enum { RET = true }; typedef mpl::true_ type; }; // The edge_list class conditionally inherits from one of the @@ -262,7 +263,7 @@ namespace boost { class Cat> #endif class edge_list - : public ct_if_t< typename is_random::type, + : public mpl::if_< typename is_random::type, edge_list_impl_ra< edge_list, EdgeIter,T,D>, edge_list_impl< edge_list, EdgeIter,T,D> >::type diff --git a/include/boost/graph/graph_concepts.hpp b/include/boost/graph/graph_concepts.hpp index a4572650..c6a3fe6c 100644 --- a/include/boost/graph/graph_concepts.hpp +++ b/include/boost/graph/graph_concepts.hpp @@ -18,125 +18,10 @@ #include #include -namespace boost { - - template - struct MultiPassInputIteratorConcept { - void constraints() { - function_requires< InputIteratorConcept >(); - } - }; - - template - struct GraphConcept - { - typedef typename graph_traits::vertex_descriptor vertex_descriptor; - typedef typename graph_traits::directed_category directed_category; - typedef typename graph_traits::edge_parallel_category - edge_parallel_category; - typedef typename graph_traits::traversal_category - traversal_category; - void constraints() { - function_requires< DefaultConstructibleConcept >(); - function_requires< EqualityComparableConcept >(); - function_requires< AssignableConcept >(); - } - G g; - }; - - template - struct IncidenceGraphConcept - { - typedef typename graph_traits::edge_descriptor edge_descriptor; - typedef typename graph_traits::out_edge_iterator - out_edge_iterator; - typedef typename graph_traits::traversal_category - traversal_category; - void constraints() { - function_requires< GraphConcept >(); - function_requires< MultiPassInputIteratorConcept >(); - function_requires< DefaultConstructibleConcept >(); - function_requires< EqualityComparableConcept >(); - function_requires< AssignableConcept >(); - function_requires< ConvertibleConcept >(); - - p = out_edges(u, g); - n = out_degree(u, g); - e = *p.first; - u = source(e, g); - v = target(e, g); - const_constraints(g); - } - void const_constraints(const G& cg) { - p = out_edges(u, cg); - n = out_degree(u, cg); - e = *p.first; - u = source(e, cg); - v = target(e, cg); - } - std::pair p; - typename graph_traits::vertex_descriptor u, v; - typename graph_traits::edge_descriptor e; - typename graph_traits::degree_size_type n; - G g; - }; - - template - struct BidirectionalGraphConcept - { - typedef typename graph_traits::in_edge_iterator - in_edge_iterator; - typedef typename graph_traits::traversal_category - traversal_category; - void constraints() { - function_requires< IncidenceGraphConcept >(); - function_requires< MultiPassInputIteratorConcept >(); - function_requires< ConvertibleConcept >(); - - p = in_edges(v, g); - n = in_degree(v, g); - e = *p.first; - const_constraints(g); - } - void const_constraints(const G& cg) { - p = in_edges(v, cg); - n = in_degree(v, cg); - e = *p.first; - } - std::pair p; - typename graph_traits::vertex_descriptor v; - typename graph_traits::edge_descriptor e; - typename graph_traits::degree_size_type n; - G g; - }; - - template - struct AdjacencyGraphConcept - { - typedef typename graph_traits::adjacency_iterator - adjacency_iterator; - typedef typename graph_traits::traversal_category - traversal_category; - void constraints() { - function_requires< GraphConcept >(); - function_requires< MultiPassInputIteratorConcept >(); - function_requires< ConvertibleConcept >(); - - p = adjacent_vertices(v, g); - v = *p.first; - const_constraints(g); - } - void const_constraints(const G& cg) { - p = adjacent_vertices(v, cg); - } - std::pair p; - typename graph_traits::vertex_descriptor v; - G g; - }; +#include +namespace boost +{ // dwa 2003/7/11 -- This clearly shouldn't be necessary, but if // you want to use vector_as_graph, it is! I'm sure the graph // library leaves these out all over the place. Probably a @@ -156,18 +41,138 @@ template typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); #endif - template - struct VertexListGraphConcept + namespace concepts { + BOOST_concept(MultiPassInputIterator,(T)) { + BOOST_CONCEPT_USAGE(MultiPassInputIterator) { + BOOST_CONCEPT_ASSERT((InputIterator)); + } + }; + + BOOST_concept(Graph,(G)) + { + typedef typename graph_traits::vertex_descriptor vertex_descriptor; + typedef typename graph_traits::directed_category directed_category; + typedef typename graph_traits::edge_parallel_category + edge_parallel_category; + + typedef typename graph_traits::traversal_category + traversal_category; + + BOOST_CONCEPT_USAGE(Graph) + { + BOOST_CONCEPT_ASSERT((DefaultConstructible)); + BOOST_CONCEPT_ASSERT((EqualityComparable)); + BOOST_CONCEPT_ASSERT((Assignable)); + } + G g; + }; + + BOOST_concept(IncidenceGraph,(G)) + : Graph + { + typedef typename graph_traits::edge_descriptor edge_descriptor; + typedef typename graph_traits::out_edge_iterator + out_edge_iterator; + + typedef typename graph_traits::traversal_category + traversal_category; + + BOOST_CONCEPT_USAGE(IncidenceGraph) { + BOOST_CONCEPT_ASSERT((MultiPassInputIterator)); + BOOST_CONCEPT_ASSERT((DefaultConstructible)); + BOOST_CONCEPT_ASSERT((EqualityComparable)); + BOOST_CONCEPT_ASSERT((Assignable)); + BOOST_CONCEPT_ASSERT((Convertible)); + + p = out_edges(u, g); + n = out_degree(u, g); + e = *p.first; + u = source(e, g); + v = target(e, g); + const_constraints(g); + } + void const_constraints(const G& cg) { + p = out_edges(u, cg); + n = out_degree(u, cg); + e = *p.first; + u = source(e, cg); + v = target(e, cg); + } + std::pair p; + typename graph_traits::vertex_descriptor u, v; + typename graph_traits::edge_descriptor e; + typename graph_traits::degree_size_type n; + G g; + }; + + BOOST_concept(BidirectionalGraph,(G)) + : IncidenceGraph + { + typedef typename graph_traits::in_edge_iterator + in_edge_iterator; + typedef typename graph_traits::traversal_category + traversal_category; + + BOOST_CONCEPT_USAGE(BidirectionalGraph) { + BOOST_CONCEPT_ASSERT((MultiPassInputIterator)); + BOOST_CONCEPT_ASSERT((Convertible)); + + p = in_edges(v, g); + n = in_degree(v, g); + e = *p.first; + const_constraints(g); + } + void const_constraints(const G& cg) { + p = in_edges(v, cg); + n = in_degree(v, cg); + e = *p.first; + } + std::pair p; + typename graph_traits::vertex_descriptor v; + typename graph_traits::edge_descriptor e; + typename graph_traits::degree_size_type n; + G g; + }; + + BOOST_concept(AdjacencyGraph,(G)) + : Graph + { + typedef typename graph_traits::adjacency_iterator + adjacency_iterator; + typedef typename graph_traits::traversal_category + traversal_category; + + BOOST_CONCEPT_USAGE(AdjacencyGraph) { + BOOST_CONCEPT_ASSERT((MultiPassInputIterator)); + BOOST_CONCEPT_ASSERT((Convertible)); + + p = adjacent_vertices(v, g); + v = *p.first; + const_constraints(g); + } + void const_constraints(const G& cg) { + p = adjacent_vertices(v, cg); + } + std::pair p; + typename graph_traits::vertex_descriptor v; + G g; + }; + + BOOST_concept(VertexListGraph,(G)) + : Graph { typedef typename graph_traits::vertex_iterator vertex_iterator; typedef typename graph_traits::vertices_size_type vertices_size_type; typedef typename graph_traits::traversal_category traversal_category; - void constraints() { - function_requires< GraphConcept >(); - function_requires< MultiPassInputIteratorConcept >(); - function_requires< ConvertibleConcept >(); + + BOOST_CONCEPT_USAGE(VertexListGraph) { + BOOST_CONCEPT_ASSERT((MultiPassInputIterator)); + BOOST_CONCEPT_ASSERT((Convertible)); #ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK // dwa 2003/7/11 -- This clearly shouldn't be necessary, but if @@ -201,22 +206,22 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); vertices_size_type V; }; - template - struct EdgeListGraphConcept + BOOST_concept(EdgeListGraph,(G)) + : Graph { typedef typename graph_traits::edge_descriptor edge_descriptor; typedef typename graph_traits::edge_iterator edge_iterator; typedef typename graph_traits::edges_size_type edges_size_type; typedef typename graph_traits::traversal_category traversal_category; - void constraints() { - function_requires< GraphConcept >(); - function_requires< MultiPassInputIteratorConcept >(); - function_requires< DefaultConstructibleConcept >(); - function_requires< EqualityComparableConcept >(); - function_requires< AssignableConcept >(); - function_requires< ConvertibleConcept >(); + + BOOST_CONCEPT_USAGE(EdgeListGraph) { + BOOST_CONCEPT_ASSERT((MultiPassInputIterator)); + BOOST_CONCEPT_ASSERT((DefaultConstructible)); + BOOST_CONCEPT_ASSERT((EqualityComparable)); + BOOST_CONCEPT_ASSERT((Assignable)); + BOOST_CONCEPT_ASSERT((Convertible)); p = edges(g); e = *p.first; @@ -238,13 +243,10 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); G g; }; - template - struct VertexAndEdgeListGraphConcept + BOOST_concept(VertexAndEdgeListGraph,(G)) + : VertexListGraph + , EdgeListGraph { - void constraints() { - function_requires< VertexListGraphConcept >(); - function_requires< EdgeListGraphConcept >(); - } }; // Where to put the requirement for this constructor? @@ -252,11 +254,11 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); // Not in mutable graph, then LEDA graph's can't be models of // MutableGraph. - template - struct EdgeMutableGraphConcept + BOOST_concept(EdgeMutableGraph,(G)) { typedef typename graph_traits::edge_descriptor edge_descriptor; - void constraints() { + + BOOST_CONCEPT_USAGE(EdgeMutableGraph) { p = add_edge(u, v, g); remove_edge(u, v, g); remove_edge(e, g); @@ -268,10 +270,10 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); typename graph_traits::vertex_descriptor u, v; }; - template - struct VertexMutableGraphConcept + BOOST_concept(VertexMutableGraph,(G)) { - void constraints() { + + BOOST_CONCEPT_USAGE(VertexMutableGraph) { v = add_vertex(g); remove_vertex(v, g); } @@ -279,13 +281,10 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); typename graph_traits::vertex_descriptor u, v; }; - template - struct MutableGraphConcept + BOOST_concept(MutableGraph,(G)) + : EdgeMutableGraph + , VertexMutableGraph { - void constraints() { - function_requires< EdgeMutableGraphConcept >(); - function_requires< VertexMutableGraphConcept >(); - } }; template @@ -295,11 +294,10 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); } }; - template - struct MutableIncidenceGraphConcept + BOOST_concept(MutableIncidenceGraph,(G)) + : MutableGraph { - void constraints() { - function_requires< MutableGraphConcept >(); + BOOST_CONCEPT_USAGE(MutableIncidenceGraph) { remove_edge(iter, g); remove_out_edge_if(u, p, g); } @@ -310,24 +308,23 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); typename boost::graph_traits::out_edge_iterator iter; }; - template - struct MutableBidirectionalGraphConcept + BOOST_concept(MutableBidirectionalGraph,(G)) + : MutableIncidenceGraph { - void constraints() { - function_requires< MutableIncidenceGraphConcept >(); - remove_in_edge_if(u, p, g); - } - G g; - typedef typename graph_traits::edge_descriptor edge_descriptor; - dummy_edge_predicate p; - typename boost::graph_traits::vertex_descriptor u; + BOOST_CONCEPT_USAGE(MutableBidirectionalGraph) + { + remove_in_edge_if(u, p, g); + } + G g; + typedef typename graph_traits::edge_descriptor edge_descriptor; + dummy_edge_predicate p; + typename boost::graph_traits::vertex_descriptor u; }; - template - struct MutableEdgeListGraphConcept + BOOST_concept(MutableEdgeListGraph,(G)) + : EdgeMutableGraph { - void constraints() { - function_requires< EdgeMutableGraphConcept >(); + BOOST_CONCEPT_USAGE(MutableEdgeListGraph) { remove_edge_if(p, g); } G g; @@ -335,11 +332,10 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); dummy_edge_predicate p; }; - template - struct VertexMutablePropertyGraphConcept + BOOST_concept(VertexMutablePropertyGraph,(G)) + : VertexMutableGraph { - void constraints() { - function_requires< VertexMutableGraphConcept >(); + BOOST_CONCEPT_USAGE(VertexMutablePropertyGraph) { v = add_vertex(vp, g); } G g; @@ -347,12 +343,12 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); typename vertex_property::type vp; }; - template - struct EdgeMutablePropertyGraphConcept + BOOST_concept(EdgeMutablePropertyGraph,(G)) + : EdgeMutableGraph { typedef typename graph_traits::edge_descriptor edge_descriptor; - void constraints() { - function_requires< EdgeMutableGraphConcept >(); + + BOOST_CONCEPT_USAGE(EdgeMutablePropertyGraph) { p = add_edge(u, v, ep, g); } G g; @@ -361,13 +357,12 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); typename edge_property::type ep; }; - template - struct AdjacencyMatrixConcept + BOOST_concept(AdjacencyMatrix,(G)) + : Graph { typedef typename graph_traits::edge_descriptor edge_descriptor; - void constraints() { - function_requires< GraphConcept >(); - + + BOOST_CONCEPT_USAGE(AdjacencyMatrix) { p = edge(u, v, g); const_constraints(g); } @@ -379,13 +374,14 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); G g; }; - template - struct ReadablePropertyGraphConcept + BOOST_concept(ReadablePropertyGraph,(G)(X)(Property)) + : Graph { typedef typename property_map::const_type const_Map; - void constraints() { - function_requires< GraphConcept >(); - function_requires< ReadablePropertyMapConcept >(); + + BOOST_CONCEPT_USAGE(ReadablePropertyGraph) + { + BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept)); const_constraints(g); } @@ -399,13 +395,12 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); typename property_traits::value_type pval; }; - template - struct PropertyGraphConcept + BOOST_concept(PropertyGraph,(G)(X)(Property)) + : ReadablePropertyGraph { typedef typename property_map::type Map; - void constraints() { - function_requires< ReadablePropertyGraphConcept >(); - function_requires< ReadWritePropertyMapConcept >(); + BOOST_CONCEPT_USAGE(PropertyGraph) { + BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept)); Map pmap = get(Property(), g); pval = get(Property(), g, x); @@ -417,14 +412,14 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); typename property_traits::value_type pval; }; - template - struct LvaluePropertyGraphConcept + BOOST_concept(LvaluePropertyGraph,(G)(X)(Property)) + : ReadablePropertyGraph { typedef typename property_map::type Map; typedef typename property_map::const_type const_Map; - void constraints() { - function_requires< ReadablePropertyGraphConcept >(); - function_requires< LvaluePropertyMapConcept >(); + + BOOST_CONCEPT_USAGE(LvaluePropertyGraph) { + BOOST_CONCEPT_ASSERT((LvaluePropertyMapConcept)); pval = get(Property(), g, x); put(Property(), g, x, pval); @@ -435,10 +430,9 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); }; // This needs to move out of the graph library - template - struct BufferConcept + BOOST_concept(Buffer,(B)) { - void constraints() { + BOOST_CONCEPT_USAGE(Buffer) { b.push(t); b.pop(); typename B::value_type& v = b.top(); @@ -457,13 +451,11 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); B b; }; - template - struct ColorValueConcept + BOOST_concept(ColorValue,(C)) + : EqualityComparable + , DefaultConstructible { - void constraints() { - function_requires< EqualityComparableConcept >(); - function_requires< DefaultConstructibleConcept >(); - + BOOST_CONCEPT_USAGE(ColorValue) { c = color_traits::white(); c = color_traits::gray(); c = color_traits::black(); @@ -471,10 +463,9 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); C c; }; - template - struct BasicMatrixConcept + BOOST_concept(BasicMatrix,(M)(I)(V)) { - void constraints() { + BOOST_CONCEPT_USAGE(BasicMatrix) { V& elt = A[i][j]; const_constraints(A); ignore_unused_variable_warning(elt); @@ -487,6 +478,33 @@ typename T::ThereReallyIsNoMemberByThisNameInT vertices(T const&); I i, j; }; + } // end namespace concepts + + using boost::concepts::MultiPassInputIteratorConcept; + using boost::concepts::GraphConcept; + using boost::concepts::IncidenceGraphConcept; + using boost::concepts::BidirectionalGraphConcept; + using boost::concepts::AdjacencyGraphConcept; + using boost::concepts::VertexListGraphConcept; + using boost::concepts::EdgeListGraphConcept; + using boost::concepts::VertexAndEdgeListGraphConcept; + using boost::concepts::EdgeMutableGraphConcept; + using boost::concepts::VertexMutableGraphConcept; + using boost::concepts::MutableGraphConcept; + using boost::concepts::MutableIncidenceGraphConcept; + using boost::concepts::MutableBidirectionalGraphConcept; + using boost::concepts::MutableEdgeListGraphConcept; + using boost::concepts::VertexMutablePropertyGraphConcept; + using boost::concepts::EdgeMutablePropertyGraphConcept; + using boost::concepts::AdjacencyMatrixConcept; + using boost::concepts::ReadablePropertyGraphConcept; + using boost::concepts::PropertyGraphConcept; + using boost::concepts::LvaluePropertyGraphConcept; + using boost::concepts::BufferConcept; + using boost::concepts::ColorValueConcept; + using boost::concepts::BasicMatrixConcept; } // namespace boost +#include + #endif /* BOOST_GRAPH_CONCEPTS_H */ diff --git a/include/boost/graph/graph_selectors.hpp b/include/boost/graph/graph_selectors.hpp index a3223c9b..777ebefc 100644 --- a/include/boost/graph/graph_selectors.hpp +++ b/include/boost/graph/graph_selectors.hpp @@ -10,6 +10,8 @@ #ifndef BOOST_GRAPH_SELECTORS_HPP #define BOOST_GRAPH_SELECTORS_HPP +#include + namespace boost { //=========================================================================== @@ -17,18 +19,18 @@ namespace boost { // and adjacency_matrix. struct directedS { enum { is_directed = true, is_bidir = false }; - typedef true_type is_directed_t; - typedef false_type is_bidir_t; + typedef mpl::true_ is_directed_t; + typedef mpl::false_ is_bidir_t; }; struct undirectedS { enum { is_directed = false, is_bidir = false }; - typedef false_type is_directed_t; - typedef false_type is_bidir_t; + typedef mpl::false_ is_directed_t; + typedef mpl::false_ is_bidir_t; }; struct bidirectionalS { enum { is_directed = true, is_bidir = true }; - typedef true_type is_directed_t; - typedef true_type is_bidir_t; + typedef mpl::true_ is_directed_t; + typedef mpl::true_ is_bidir_t; }; } // namespace boost diff --git a/include/boost/graph/graph_test.hpp b/include/boost/graph/graph_test.hpp index 37ded0c7..554ddbad 100644 --- a/include/boost/graph/graph_test.hpp +++ b/include/boost/graph/graph_test.hpp @@ -85,7 +85,7 @@ namespace boost { for (; p.first != p.second; ++p.first) { edge_t e = *p.first; BOOST_CHECK(source(e, g) == u); - BOOST_CHECK(contains(adj, target(e, g)) == true); + BOOST_CHECK(container_contains(adj, target(e, g)) == true); } } } @@ -114,7 +114,7 @@ namespace boost { for (; p.first != p.second; ++p.first) { edge_t e = *p.first; BOOST_CHECK(target(e, g) == v); - BOOST_CHECK(contains(inv_adj, source(e, g)) == true); + BOOST_CHECK(container_contains(inv_adj, source(e, g)) == true); } } } @@ -140,7 +140,7 @@ namespace boost { BOOST_CHECK(deg_size_t(std::distance(p.first, p.second)) == adj.size()); for (; p.first != p.second; ++p.first) { vertex_t v = *p.first; - BOOST_CHECK(contains(adj, v) == true); + BOOST_CHECK(container_contains(adj, v) == true); } } } @@ -155,7 +155,7 @@ namespace boost { BOOST_CHECK(n == num_vertices(g)); for (; p.first != p.second; ++p.first) { vertex_t v = *p.first; - BOOST_CHECK(contains(vertex_set, v) == true); + BOOST_CHECK(container_contains(vertex_set, v) == true); } } @@ -172,8 +172,8 @@ namespace boost { for (; p.first != p.second; ++p.first) { edge_t e = *p.first; BOOST_CHECK(any_if(edge_set, connects(source(e, g), target(e, g), g))); - BOOST_CHECK(contains(vertex_set, source(e, g)) == true); - BOOST_CHECK(contains(vertex_set, target(e, g)) == true); + BOOST_CHECK(container_contains(vertex_set, source(e, g)) == true); + BOOST_CHECK(container_contains(vertex_set, target(e, g)) == true); } } @@ -232,7 +232,7 @@ namespace boost { IsoMap iso_map(iso_vec.begin(), get(vertex_index, g)); copy_graph(g, cpy, orig_to_copy(iso_map)); - bool parallel_edge_exists = contains(adjacent_vertices(u, g), v); + bool parallel_edge_exists = container_contains(adjacent_vertices(u, g), v); std::pair p = add_edge(u, v, g); edge_t e = p.first; @@ -249,7 +249,7 @@ namespace boost { if (p.second == true) { // edge added BOOST_CHECK(num_edges(g) == num_edges(cpy) + 1); - BOOST_CHECK(contains(out_edges(u, g), e) == true); + BOOST_CHECK(container_contains(out_edges(u, g), e) == true); BOOST_CHECK((verify_isomorphism (make_filtered_graph(g, ignore_edge(e)), cpy, iso_map))); diff --git a/include/boost/graph/graphml.hpp b/include/boost/graph/graphml.hpp new file mode 100644 index 00000000..be7a804e --- /dev/null +++ b/include/boost/graph/graphml.hpp @@ -0,0 +1,332 @@ +// Copyright (C) 2006 Tiago de Paula Peixoto +// Copyright (C) 2004 The Trustees of Indiana University. +// +// Use, modification and distribution is subject to 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) +// +// Authors: Douglas Gregor +// Andrew Lumsdaine +// Tiago de Paula Peixoto + +#ifndef BOOST_GRAPH_GRAPHML_HPP +#define BOOST_GRAPH_GRAPHML_HPP + +#include +#include +#include +#include +#include // for exceptions +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + +///////////////////////////////////////////////////////////////////////////// +// Graph reader exceptions +///////////////////////////////////////////////////////////////////////////// +struct parse_error: public graph_exception +{ + parse_error(const std::string& error) {statement = "parse error: " + error;} + virtual ~parse_error() throw() {} + virtual const char* what() const throw() {return statement.c_str();} + std::string statement; +}; + + +class mutate_graph +{ +public: + virtual ~mutate_graph() {} + virtual bool is_directed() const = 0; + + virtual boost::any do_add_vertex() = 0; + virtual std::pair do_add_edge(boost::any source, boost::any target) = 0; + + virtual void + set_graph_property(const std::string& name, const std::string& value, const std::string& value_type) = 0; + + virtual void + set_vertex_property(const std::string& name, boost::any vertex, const std::string& value, const std::string& value_type) = 0; + + virtual void + set_edge_property(const std::string& name, boost::any edge, const std::string& value, const std::string& value_type) = 0; +}; + +template +class mutate_graph_impl : public mutate_graph +{ + typedef typename graph_traits::vertex_descriptor vertex_descriptor; + typedef typename graph_traits::edge_descriptor edge_descriptor; + + public: + mutate_graph_impl(MutableGraph& g, dynamic_properties& dp) + : m_g(g), m_dp(dp) { } + + bool is_directed() const + { + return is_convertible::directed_category, + directed_tag>::value; + } + + virtual any do_add_vertex() + { + return any(add_vertex(m_g)); + } + + virtual std::pair do_add_edge(any source, any target) + { + std::pair retval = add_edge(any_cast(source), + any_cast(target), m_g); + return std::make_pair(any(retval.first), retval.second); + } + + virtual void + set_graph_property(const std::string& name, const std::string& value, const std::string& value_type) + { + bool type_found = false; + try + { + mpl::for_each(put_property + (name, m_dp, m_g, value, value_type, m_type_names, type_found)); + } + catch (bad_lexical_cast) + { + throw parse_error("invalid value \"" + value + "\" for key " + + name + " of type " + value_type); + } + if (!type_found) + throw parse_error("unrecognized type \"" + value_type + + "\" for key " + name); + + } + + virtual void + set_vertex_property(const std::string& name, any vertex, const std::string& value, const std::string& value_type) + { + bool type_found = false; + try + { + mpl::for_each(put_property + (name, m_dp, any_cast(vertex), + value, value_type, m_type_names, type_found)); + } + catch (bad_lexical_cast) + { + throw parse_error("invalid value \"" + value + "\" for key " + + name + " of type " + value_type); + } + if (!type_found) + throw parse_error("unrecognized type \"" + value_type + + "\" for key " + name); + + } + + virtual void + set_edge_property(const std::string& name, any edge, const std::string& value, const std::string& value_type) + { + bool type_found = false; + try + { + mpl::for_each(put_property + (name, m_dp, any_cast(edge), + value, value_type, m_type_names, type_found)); + } + catch (bad_lexical_cast) + { + throw parse_error("invalid value \"" + value + "\" for key " + + name + " of type " + value_type); + } + if (!type_found) + throw parse_error("unrecognized type \"" + value_type + + "\" for key " + name); + } + + template + class put_property + { + public: + put_property(const std::string& name, dynamic_properties& dp, const Key& key, + const std::string& value, const std::string& value_type, + char** type_names, bool& type_found) + : m_name(name), m_dp(dp), m_key(key), m_value(value), + m_value_type(value_type), m_type_names(type_names), + m_type_found(type_found) {} + template + void operator()(Value) + { + if (m_value_type == m_type_names[mpl::find::type::pos::value]) + { + put(m_name, m_dp, m_key, lexical_cast(m_value)); + m_type_found = true; + } + } + private: + const std::string& m_name; + dynamic_properties& m_dp; + const Key& m_key; + const std::string& m_value; + const std::string& m_value_type; + char** m_type_names; + bool& m_type_found; + }; + +protected: + MutableGraph& m_g; + dynamic_properties& m_dp; + typedef mpl::vector value_types; + static char* m_type_names[]; +}; + +template +char* mutate_graph_impl::m_type_names[] = {"boolean", "int", "long", "float", "double", "string"}; + +void +read_graphml(std::istream& in, mutate_graph& g); + +template +void +read_graphml(std::istream& in, MutableGraph& g, dynamic_properties& dp) +{ + mutate_graph_impl mg(g,dp); + read_graphml(in, mg); +} + +template +class get_type_name +{ +public: + get_type_name(const std::type_info& type, char** type_names, std::string& type_name) + : m_type(type), m_type_names(type_names), m_type_name(type_name) {} + template + void operator()(Type) + { + if (typeid(Type) == m_type) + m_type_name = m_type_names[mpl::find::type::pos::value]; + } +private: + const std::type_info &m_type; + char** m_type_names; + std::string &m_type_name; +}; + + +template +void +write_graphml(std::ostream& out, const Graph& g, VertexIndexMap vertex_index, + const dynamic_properties& dp, bool ordered_vertices=false) +{ + typedef typename graph_traits::directed_category directed_category; + typedef typename graph_traits::edge_descriptor edge_descriptor; + typedef typename graph_traits::vertex_descriptor vertex_descriptor; + + BOOST_STATIC_CONSTANT(bool, + graph_is_directed = + (is_convertible::value)); + + out << "\n" + << "\n"; + + typedef mpl::vector value_types; + char* type_names[] = {"boolean", "int", "int", "int", "int", "long", "long", "long", "long", "float", "double", "double", "string"}; + std::map graph_key_ids; + std::map vertex_key_ids; + std::map edge_key_ids; + int key_count = 0; + + // Output keys + for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i) + { + std::string key_id = "key" + lexical_cast(key_count++); + if (i->second->key() == typeid(Graph)) + vertex_key_ids[i->first] = key_id; + else if (i->second->key() == typeid(vertex_descriptor)) + vertex_key_ids[i->first] = key_id; + else if (i->second->key() == typeid(edge_descriptor)) + edge_key_ids[i->first] = key_id; + else + continue; + std::string type_name = "string"; + mpl::for_each(get_type_name(i->second->value(), type_names, type_name)); + out << " second->key() == typeid(Graph) ? "graph" : (i->second->key() == typeid(vertex_descriptor) ? "node" : "edge")) << "\"" + << " attr.name=\"" << i->first << "\"" + << " attr.type=\"" << type_name << "\"" + << " />\n"; + } + + out << " \n"; + + // Output graph data + for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i) + { + if (i->second->key() == typeid(Graph)) + { + out << " first] << "\">" + << i->second->get_string(g) << "\n"; + } + } + + typedef typename graph_traits::vertex_iterator vertex_iterator; + vertex_iterator v, v_end; + for (tie(v, v_end) = vertices(g); v != v_end; ++v) + { + out << " \n"; + // Output data + for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i) + { + if (i->second->key() == typeid(vertex_descriptor)) + { + out << " first] << "\">" + << i->second->get_string(*v) << "\n"; + } + } + out << " \n"; + } + + typedef typename graph_traits::edge_iterator edge_iterator; + edge_iterator e, e_end; + typename graph_traits::edges_size_type edge_count = 0; + for (tie(e, e_end) = edges(g); e != e_end; ++e) + { + out << " \n"; + + // Output data + for (dynamic_properties::const_iterator i = dp.begin(); i != dp.end(); ++i) + { + if (i->second->key() == typeid(edge_descriptor)) + { + out << " first] << "\">" + << i->second->get_string(*e) << "\n"; + } + } + out << " \n"; + } + + out << " \n" + << "\n"; +} + + +template +void +write_graphml(std::ostream& out, const Graph& g, const dynamic_properties& dp, + bool ordered_vertices=false) +{ + write_graphml(out, g, get(vertex_index, g), dp, ordered_vertices); +} + +} // boost namespace + +#endif // BOOST_GRAPH_GRAPHML_HPP diff --git a/include/boost/graph/graphviz.hpp b/include/boost/graph/graphviz.hpp index 840c0d79..b010dd84 100644 --- a/include/boost/graph/graphviz.hpp +++ b/include/boost/graph/graphviz.hpp @@ -679,6 +679,9 @@ class mutate_graph virtual void set_edge_property(const id_t& key, const edge_t& edge, const id_t& value) = 0; + + virtual void // RG: need new second parameter to support BGL subgraphs + set_graph_property(const id_t& key, const id_t& value) = 0; }; template @@ -740,6 +743,14 @@ class mutate_graph_impl : public mutate_graph put(key, dp_, bgl_edges[edge], value); } + void + set_graph_property(const id_t& key, const id_t& value) + { + /* RG: pointer to graph prevents copying */ + put(key, dp_, &graph_, value); + } + + protected: MutableGraph& graph_; dynamic_properties& dp_; diff --git a/include/boost/graph/howard_cycle_ratio.hpp b/include/boost/graph/howard_cycle_ratio.hpp new file mode 100644 index 00000000..ec248713 --- /dev/null +++ b/include/boost/graph/howard_cycle_ratio.hpp @@ -0,0 +1,611 @@ +/*! +* Copyright 2007 Technical University of Catalonia +* +* Use, modification and distribution is subject to 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) +* +* Authors: Dmitry Bufistov +* Andrey Parfenov +*/ + +#ifndef BOOST_GRAPH_HOWARD_CYCLE_RATIO_HOWARD_HPP +#define BOOST_GRAPH_HOWARD_CYCLE_RATIO_HOWARD_HPP + +/*! +* \file Maximum cycle ratio algorithm (Jean Cochet-Terrasson, Guy +* Cochen and others) +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { + namespace detail { + /// To avoid round error. + static const double mcr_howard_ltolerance = 0.00001; + + /*! + * Calculate maximum cycle ratio of "good" directed multigraph + * g. Use Howard's iteration policy algorithm ("Numerical + * Computation of Spectral Elements in MAX-PLUS algebra" by Jean + * Cochet-Terrasson, Guy Cochen and others). + * + * \param g = (V, E) - a "good" directed multigraph (out_degree of + * each vertex is greater then 0). If graph is strongly connected + * then it is "good". + * + * \param vim - Vertex Index, read property Map: V -> [0, + * num_vertices(g)). + * + * \param ewm - edge weight read property map: E -> R + * + * \param ewm2 - edge weight2 read property map: E -> R+ + * + * \return maximum_{for all cycles C}CR(C), or + * -(std::numeric_limits)::max() if g is not "good". + */ + template + class Cmcr_Howard + { + public: + Cmcr_Howard(const TGraph& g, TVertexIndexMap vim, TWeight1EdgeMap ewm, + TWeight2EdgeMap ew2m) + : m_g(g), m_vim(vim), m_ew1m(ewm), m_ew2m(ew2m), + m_g2pi_g_vm(std::vector().end(), m_vim), /// Stupid dummy initialization + m_minus_infinity(-(std::numeric_limits::max)()) + { + typedef typename boost::graph_traits::directed_category DirCat; + BOOST_STATIC_ASSERT((boost::is_convertible::value == true)); + m_cr = m_minus_infinity; + } + + double operator()() + { + return maximum_cycle_ratio_Howard(); + } + + virtual ~Cmcr_Howard() { } + + protected: + typedef typename boost::graph_traits::vertex_descriptor + mcr_vertex_t; + typedef typename boost::graph_traits::edge_descriptor + mcr_edge_t; + + const TGraph& m_g; + typedef std::vector eigenmode_t; + eigenmode_t m_eigen_value; + eigenmode_t m_eigen_vector; + TVertexIndexMap m_vim; + TWeight1EdgeMap m_ew1m; + TWeight2EdgeMap m_ew2m; + + typedef typename boost::remove_const::value_type>::type mcr_edge_weight1_t; + typedef typename boost::remove_const::value_type>::type mcr_edge_weight2_t; + typedef typename boost::adjacency_list< + boost::listS, boost::vecS, boost::bidirectionalS, + boost::no_property, + boost::property > > + pi_graph_t; + typedef typename boost::property_map::type TPiGraphVertexIndexMap; + typedef typename boost::property_map::type TPiGraphEdgeWeight1Map; + typedef typename boost::property_map::type TPiGraphEdgeWeight2Map; + + typedef typename boost::property_traits::value_type pigraph_vertex_index_t; + + pi_graph_t m_pi_g; + typedef typename boost::graph_traits::vertex_descriptor pi_vertex_t; + typedef typename boost::graph_traits::edge_descriptor pi_edge_t; + typedef typename boost::iterator_property_map::iterator, TVertexIndexMap> g2pi_g_vm_t; + g2pi_g_vm_t m_g2pi_g_vm; ///Graph to Pi graph vertex map + std::vector m_g2pig; + int m_step_number; + const double m_minus_infinity; + typedef typename std::vector critical_cycle_t; + double m_cr; ///Cycle ratio that already has been found + + class bad_graph + { + public: + typedef typename boost::property_traits::value_type + v_index_t; + + bad_graph(v_index_t bvi) : bad_vertex_index(bvi) {} + v_index_t what() const throw() + { + return bad_vertex_index; + } + + private: + v_index_t bad_vertex_index; + }; + + double maximum_cycle_ratio_Howard() + { + try + { + construct_pi_graph(); + } + catch (const bad_graph& a) + { + return m_minus_infinity; + } + std::vector max_eigen_val(boost::num_vertices(m_g)); + m_eigen_value.resize(boost::num_vertices(m_g)); + m_eigen_vector.resize(boost::num_vertices(m_g)); + m_step_number = 0; + do + { + pi_eingen_value(get(vertex_index, m_pi_g), get(boost::edge_weight, m_pi_g), get(boost::edge_weight2, m_pi_g)); + ++m_step_number; + } + while (improve_policy_try1(max_eigen_val) || improve_policy_try2(max_eigen_val)); + return *(std::max_element(m_eigen_value.begin(), m_eigen_value.end())); + } + + /*! + * Construct an arbitrary policy m_pi_g. + */ + void construct_pi_graph() + { + m_g2pig.resize(boost::num_vertices(m_g)); + m_g2pi_g_vm = boost::make_iterator_property_map(m_g2pig.begin(), m_vim); + BGL_FORALL_VERTICES_T(vd, m_g, TGraph) + { + m_g2pi_g_vm[vd] = boost::add_vertex(m_pi_g); + store_pivertex(m_g2pi_g_vm[vd], vd); + } + BGL_FORALL_VERTICES_T(vd1, m_g, TGraph) + { + if (boost::out_edges(vd1, m_g).first == boost::out_edges(vd1, m_g).second) throw bad_graph(m_vim[vd1]); + mcr_edge_t ed = *boost::out_edges(vd1, m_g).first; + pi_edge_t pied = boost::add_edge(m_g2pi_g_vm[source(ed, m_g)], m_g2pi_g_vm[target(ed, m_g)], m_pi_g).first; + boost::put(boost::edge_weight, m_pi_g, pied, m_ew1m[ed]); + boost::put(boost::edge_weight2, m_pi_g, pied, m_ew2m[ed]); + } + } + + class bfs_eingmode_visitor : public boost::default_bfs_visitor + { + public: + bfs_eingmode_visitor(TPiGraphVertexIndexMap vi_m, TPiGraphEdgeWeight1Map w_m, TPiGraphEdgeWeight2Map& d_m, + eigenmode_t& e_val, eigenmode_t& e_vec, double ev) : m_index_map(vi_m), m_weight_map(w_m), m_delay_map(d_m), + m_eig_value(&e_val), m_eig_vec(&e_vec), m_eigen_value(ev) { } + + template < typename Edge, typename g_t> + void examine_edge(Edge e, const g_t & g) const + { + typedef typename boost::graph_traits::vertex_descriptor Vertex; + Vertex u = boost::target(e, g), v = boost::source(e, g); + pigraph_vertex_index_t ind = m_index_map[u]; + (*m_eig_value)[ind] = m_eigen_value; + (*m_eig_vec)[ind] = m_weight_map[e] - m_eigen_value * m_delay_map[e] + (*m_eig_vec)[m_index_map[v]]; + } + private: + TPiGraphVertexIndexMap m_index_map; + TPiGraphEdgeWeight1Map m_weight_map; + TPiGraphEdgeWeight2Map m_delay_map; + eigenmode_t* m_eig_value; + eigenmode_t* m_eig_vec; + double m_eigen_value; + }; + + /*! + * Find a vertex in the Pi Graph which belongs to cycle, just a DFV until back edge found + */ + pi_vertex_t find_good_source(const pi_vertex_t start_vertex) + { + pi_vertex_t good_vertex = start_vertex; + typename std::set s; + s.insert(start_vertex); + do + { + good_vertex = boost::target(*boost::out_edges(good_vertex, m_pi_g).first, m_pi_g); + } + while (s.insert(good_vertex).second); + return good_vertex; + } + virtual void store_pivertex(pi_vertex_t pivd, mcr_vertex_t vd) {} + virtual void store_critical_edge(pi_edge_t ed, critical_cycle_t& cc) {} + virtual void store_critical_cycle(critical_cycle_t& cc) {} + + /*! + * \param startV - vertex that belongs to a cycle in policy graph m_pi_g + */ + double calculate_eigen_value(pi_vertex_t startV) + { + std::pair accum_sums(0., 0.); + pi_vertex_t vd = startV; + critical_cycle_t cc; + do + { + pi_edge_t tmp_ed = *(boost::out_edges(vd, m_pi_g).first); + store_critical_edge(tmp_ed, cc); + accum_sums.first += boost::get(boost::edge_weight, m_pi_g, tmp_ed); + accum_sums.second += boost::get(boost::edge_weight2, m_pi_g, tmp_ed); + vd = boost::target(tmp_ed, m_pi_g); + } + while (vd != startV); + //assert((std::abs(accum_sums.first) <= 0.00000001) && "Division by zerro!"); + double cr = accum_sums.first / accum_sums.second; + if (cr > m_cr) + { + m_cr = cr; + store_critical_cycle(cc); + } + else + { + + } + return cr; + } + + /*! + * Value determination. Find a generalized eigenmode (n^{k+1}, x^{k+1}) of A^{Ï_{k+1}} of the pi graph (Algorithm IV.1). + */ + void pi_eingen_value( + TPiGraphVertexIndexMap index_map, + TPiGraphEdgeWeight1Map weight_map, + TPiGraphEdgeWeight2Map weigh2_map) + { + using namespace boost; + typedef std::vector color_map_t; + color_map_t vcm(num_vertices(m_pi_g), white_color);//Vertex color map + color_map_t::iterator uv_itr = vcm.begin(); //Undiscovered vertex + reverse_graph rev_g(m_pi_g); //For backward breadth visit + + while ((uv_itr = std::find_if(uv_itr, vcm.end(), + boost::bind(std::equal_to(), boost::white_color, _1))) != vcm.end()) + ///While there are undiscovered vertices + { + pi_vertex_t gv = find_good_source(pi_vertex_t(uv_itr - vcm.begin())); + pigraph_vertex_index_t gv_ind = index_map[gv]; + m_eigen_value[gv_ind] = calculate_eigen_value(gv) ; + bfs_eingmode_visitor bfs_vis(index_map, weight_map, weigh2_map, m_eigen_value, m_eigen_vector, m_eigen_value[gv_ind]); + typename boost::queue Q; + breadth_first_visit(rev_g, gv, Q, bfs_vis, make_iterator_property_map(vcm.begin(), index_map)); + } + } + + void improve_policy(mcr_vertex_t vd, mcr_edge_t new_edge) + { + remove_edge(*(out_edges(m_g2pi_g_vm[vd], m_pi_g).first), m_pi_g); + pi_edge_t ned = add_edge(m_g2pi_g_vm[vd], m_g2pi_g_vm[target(new_edge, m_g)], m_pi_g).first; + put(edge_weight, m_pi_g, ned, m_ew1m[new_edge]); + put(edge_weight2, m_pi_g, ned, m_ew2m[new_edge]); + } + /*! + * Policy Improvement. Improve the policy graph. The new policy graph has greater cycle ratio. + * \return false if nothing can be improved. + */ + bool improve_policy_try1(std::vector& max_eing_vals) + { + bool improved = false; + BGL_FORALL_VERTICES_T(vd, m_g, TGraph) + { + double max_ev = m_minus_infinity;/// Maximum eigen value for vertex + mcr_edge_t cr_ed;///Critical edge + + BGL_FORALL_OUTEDGES_T(vd, outed, m_g, TGraph) + { + if (m_eigen_value[m_vim[target(outed, m_g)]] > max_ev) + { + max_ev = m_eigen_value[m_vim[boost::target(outed, m_g)]]; + cr_ed = outed; + } + } + if (max_ev > m_eigen_value[get(m_vim,vd)]) + { + improve_policy(vd, cr_ed); + improved = true; + } + max_eing_vals[get(m_vim,vd)] = max_ev; + } + return improved; + } + + /*! + * \param max_eigen_values[u] = max_(for all adjacent vertices (u,v)) m_eigen_value[v] + */ + bool improve_policy_try2(const std::vector& max_eigen_values) + { + bool improved = false; + BGL_FORALL_VERTICES_T(vd, m_g, TGraph) + { + mcr_edge_t impr_edge; + double max_val = m_minus_infinity; + BGL_FORALL_OUTEDGES_T(vd, outed, m_g, TGraph) + { + ///If vertex vd is in the K(vd) set + if (max_eigen_values[get(m_vim, vd)] <= m_eigen_value[get(m_vim, target(outed, m_g))]) + { + double c_val = m_ew1m[outed] - m_ew2m[outed] * m_eigen_value[m_vim[boost::target(outed, m_g)]] + + m_eigen_vector[m_vim[boost::target(outed, m_g)]]; + if (c_val > max_val) + { + max_val = c_val; + impr_edge = outed; + } + } + } + if ((max_val - m_eigen_vector[get(m_vim, vd)]) > mcr_howard_ltolerance) + ///If m_eigen_vector[vd] == max_val + { + improve_policy(vd, impr_edge); + improved = true; + } + } + return improved; + } + };///Cmcr_Howard + + /*! + * \return maximum cycle ratio and one critical cycle. + */ + template + class Cmcr_Howard1 : public Cmcr_Howard + { + public: + typedef Cmcr_Howard inhr_t; + Cmcr_Howard1(const TGraph& g, TVertexIndexMap vim, TWeight1EdgeMap ewm, TWeight2EdgeMap ew2m) : inhr_t(g, vim, ewm, ew2m) + { + m_pi_g2g.resize(boost::num_vertices(g)); + m_pi_g2g_vm = boost::make_iterator_property_map(m_pi_g2g.begin(), boost::get(boost::vertex_index, this->m_pi_g)); + } + + void get_critical_cycle(typename inhr_t::critical_cycle_t& cc) { return cc.swap(m_critical_cycle); } + protected: + void store_pivertex(typename inhr_t::pi_vertex_t pivd, typename inhr_t::mcr_vertex_t vd) + { + m_pi_g2g_vm[pivd] = vd; + } + void store_critical_edge(typename inhr_t::pi_edge_t ed, typename inhr_t::critical_cycle_t& cc) + { + typename inhr_t::pi_vertex_t s = boost::source(ed, this->m_pi_g); + typename inhr_t::pi_vertex_t t = boost::target(ed, this->m_pi_g); + assert(boost::edge(m_pi_g2g_vm[s], m_pi_g2g_vm[t], this->m_g).second); + cc.push_back(boost::edge(m_pi_g2g_vm[s], m_pi_g2g_vm[t], this->m_g).first); ///Store corresponding edge of the m_g + } + void store_critical_cycle(typename inhr_t::critical_cycle_t& cc) + { + m_critical_cycle.swap(cc); + } + private: + typename inhr_t::critical_cycle_t m_critical_cycle; + typedef typename boost::iterator_property_map::iterator, typename inhr_t::TPiGraphVertexIndexMap> pi_g2g_vm_t; + pi_g2g_vm_t m_pi_g2g_vm; ///Maps policy graph vertices to input graph vertices + typename std::vector m_pi_g2g; + }; + + /*! + * Add sink vertex - this will make any graph good, the selfloop will have ratio equal to infinity + * Properties must be "self increasing" + */ + template + typename boost::graph_traits::vertex_descriptor + make_graph_good(TGraph& g, TWeight1EdgeMap ewm, TWeight2EdgeMap ew2m, + typename boost::property_traits::value_type infinity) + { + typedef typename boost::graph_traits::edge_descriptor Edge; + typename boost::graph_traits::vertex_descriptor sink = boost::add_vertex(g); + + BGL_FORALL_VERTICES_T(vd, g, TGraph) + { + Edge newed = boost::add_edge(vd, sink, g).first; + boost::put(ewm, newed, 0); + boost::put(ew2m, newed, 1); + } + Edge selfed = boost::edge(sink, sink, g).first; + boost::put(ewm, selfed, infinity); + return sink; + } + + /*! + * Construct from input graph g "safe" (suitable for maximum_cycle_ratio1() call) version - safeg + */ + template + void construct_safe_graph(const TG& g, TIndVertexMap vim, TW1EdgeMap ew1m, TW2EdgeMap ew2m, TSafeG& safeg, SafeG2GEdgeMap& sg2gm) + { + assert(num_vertices(g) == num_vertices(safeg)); + typedef typename graph_traits::edge_descriptor tmp_edge_t; + typedef typename graph_traits::edge_descriptor edge_t; + typename graph_traits::edge_iterator ei, ei_end; + + for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) + { + tmp_edge_t tmped = add_edge(vim[source(*ei, g)], vim[target(*ei, g)], safeg).first; + sg2gm[tmped] = *ei; + put(edge_weight, safeg, tmped, get(ew1m, *ei)); + put(edge_weight2, safeg, tmped, get(ew2m, *ei)); + } + } + + template + double maximum_cycle_ratio_good_graph(const TGraph& g, TVertexIndexMap vim, TWeight1EdgeMap ewm, TWeight2EdgeMap ew2m, + typename std::vector::edge_descriptor>* pcc = 0) + { + if (pcc == 0) + { + return detail::Cmcr_Howard(g, vim, ewm, ew2m)(); + } + else + { + detail::Cmcr_Howard1 obj(g, vim, ewm, ew2m); + double maxcr = obj(); + obj.get_critical_cycle(*pcc); + return maxcr; + } + } + + template + double minimum_cycle_ratio_good_graph(const TGraph& g, TVertexIndexMap vim, TWeight1EdgeMap ewm, + TWeight2EdgeMap ew2m, TEdgeIndexMap eim, + typename std::vector::edge_descriptor>* pcc = 0) + { + typedef typename boost::remove_const::value_type>::type weight_value_t; + BOOST_STATIC_ASSERT(!is_integral::value || is_signed::value); + typename std::vector ne_w(boost::num_edges(g)); + BGL_FORALL_EDGES_T(ed, g, TGraph) ne_w[boost::get(eim, ed)] = -ewm[ed]; + return -maximum_cycle_ratio_good_graph(g, vim, boost::make_iterator_property_map(ne_w.begin(), eim), ew2m, pcc); + } + + /*! + * \param g directed multigraph. + * \param pcc - pointer to the critical edges list. + * \param minus_infinity must be small enough to garanty that g has at least one cycle with greater ratio. + * \return minus_infinity if there're no cycles in the graph + */ + template + double maximum_cycle_ratio1(const TGraph& g, TWeight1EdgeMap ewm, TWeight2EdgeMap ew2m, + typename std::vector::edge_descriptor>* pcc = 0, + typename boost::property_traits::value_type minus_infinity = -(std::numeric_limits::max)()) + { + typedef typename boost::graph_traits::vertex_descriptor Vertex; + typedef typename boost::graph_traits::edge_descriptor Edge; + boost::function_requires< boost::ReadWritePropertyMapConcept >(); + boost::function_requires< boost::ReadWritePropertyMapConcept >(); + + TGraph& ncg = const_cast(g); + Vertex sink = detail::make_graph_good(ncg, ewm, ew2m, minus_infinity ); + + double res = maximum_cycle_ratio_good_graph(ncg, boost::get(boost::vertex_index, g), ewm, ew2m, pcc); + boost::clear_vertex(sink, ncg); boost::remove_vertex(sink, ncg); + return res; + } + + /*! + * Edge index MUST be in diapazon [0,..., num_edges(g)-1] + * \return plus_infinity if g has no cycles. + */ + template + double minimum_cycle_ratio1(const TGraph& g, TWeight1EdgeMap ewm, TWeight2EdgeMap ew2m, TEdgeIndexMap eim, + typename std::vector::edge_descriptor>* pcc = 0, + typename boost::property_traits::value_type plus_infinity = (std::numeric_limits::max)() + ) + { + typedef typename boost::property_traits::value_type ei_t; + typedef typename boost::graph_traits::vertex_descriptor Vertex; + typedef typename boost::graph_traits::edge_descriptor Edge; + + boost::function_requires< boost::ReadWritePropertyMapConcept >(); + boost::function_requires< boost::ReadWritePropertyMapConcept >(); + boost::function_requires< boost::ReadWritePropertyMapConcept >(); + + TGraph& ncg = const_cast(g); + + ei_t nei = ei_t(boost::num_edges(g)); + Vertex sink = detail::make_graph_good(ncg, ewm, ew2m, plus_infinity ); + ///Maintain edge index invariant + BGL_FORALL_VERTICES_T(vd, ncg, TGraph) + { + typename boost::graph_traits::edge_descriptor ed = boost::edge(vd, sink, ncg).first; + boost::put(eim, ed, nei++); + } + double res = minimum_cycle_ratio_good_graph(ncg, boost::get(boost::vertex_index, ncg), ewm, ew2m, eim, pcc); + boost::clear_vertex(sink, ncg); boost::remove_vertex(sink, ncg); + return res; + } + struct edge_less_than + { + template bool operator()(const TEdgeDescriptor& x, const TEdgeDescriptor& y) const + { + return x.get_property() < y.get_property(); + } + }; + }///namespace detail + namespace + { + template struct safe_graph + { + typedef typename boost::adjacency_list > > type; + }; + } + + /*! + * Calculate the maximum cycle ratio (mcr) of the directed multigraph g. + * \param g directed multigraph + * \param pcc - If provided then a critical cycle will be written to corresponding vector. + * \param minus_infinity small enough value to garanty that g has at least one cycle with greater ratio. + * \return mcr or minus_infinity if g has no cycles. + */ + template + double maximum_cycle_ratio(const TGraph& g, TVertexIndexMap vim, TW1EdgeMap ew1m, TW2EdgeMap ew2m, + typename std::vector::edge_descriptor>* pcc = 0, + typename boost::property_traits::value_type minus_infinity = + -(std::numeric_limits::max)()) + { + typedef typename remove_const::value_type>::type w1_t; + typedef typename remove_const::value_type>::type w2_t; + typedef typename safe_graph::type safe_graph_t; + typedef typename graph_traits::edge_descriptor tmp_edge_t; + typedef typename graph_traits::edge_descriptor edge_t; + typename std::map tmpg2g; + std::vector cc; + safe_graph_t sg(num_vertices(g)); + detail::construct_safe_graph(g, vim, ew1m, ew2m, sg, tmpg2g); + double mcr = maximum_cycle_ratio1(sg, get(edge_weight, sg), get(edge_weight2, sg), pcc ? &cc : 0, minus_infinity); + if (pcc && (mcr > minus_infinity)) + { + pcc->clear(); + for (typename std::vector::iterator it = cc.begin(); it != cc.end(); ++it) pcc->push_back(tmpg2g[*it]); + } + return mcr; + } + + template + double minimum_cycle_ratio(const TGraph& g, TVertexIndexMap vim, TW1EdgeMap ew1m, TW2EdgeMap ew2m, TIndEdgeMap eim, + typename std::vector::edge_descriptor>* pcc = 0, + typename boost::property_traits::value_type plus_infinity = + (std::numeric_limits::max)()) + { + typedef typename boost::remove_const::value_type>::type weight_value_t; + BOOST_STATIC_ASSERT(!is_integral::value || is_signed::value); + typename std::vector ne_w(boost::num_edges(g)); + BGL_FORALL_EDGES_T(ed, g, TGraph) ne_w[boost::get(eim, ed)] = -ew1m[ed]; + return -maximum_cycle_ratio(g, vim, boost::make_iterator_property_map(ne_w.begin(), eim), ew2m, pcc, -plus_infinity); + } + /*! + * Calculate maximum mean cycle of directed weighted multigraph. + * \param g directed multigraph + * \return maximum mean cycle of g or minus_infinity if g has no cycles. + */ + template + double maximum_mean_cycle(const TGraph& g, TVertexIndexMap vim, TWeightEdgeMap ewm, TIndEdgeMap eim, + typename std::vector::edge_descriptor>* pcc = 0, + typename boost::property_traits::value_type minus_infinity = + -(std::numeric_limits::max)()) + { + typedef typename boost::remove_const::value_type>::type weight_value_t; + typedef typename boost::graph_traits::edge_descriptor Edge; + typename std::vector ed_w2(boost::num_edges(g), 1); + return maximum_cycle_ratio(g, vim, ewm, boost::make_iterator_property_map(ed_w2.begin(), eim), pcc, minus_infinity); + } + + template + double minimum_mean_cycle(const TGraph& g, TVertexIndexMap vim, TWeightEdgeMap ewm, TIndEdgeMap eim, + typename std::vector::edge_descriptor>* pcc = 0, + typename boost::property_traits::value_type plus_infinity = + (std::numeric_limits::max)()) + { + typedef typename boost::remove_const::value_type>::type weight_value_t; + typedef typename boost::graph_traits::edge_descriptor Edge; + typename std::vector ed_w2(boost::num_edges(g), 1); + return minimum_cycle_ratio(g, vim, ewm, boost::make_iterator_property_map(ed_w2.begin(), eim), eim, pcc, plus_infinity); + } +} //namespace boost +#endif diff --git a/include/boost/graph/is_kuratowski_subgraph.hpp b/include/boost/graph/is_kuratowski_subgraph.hpp new file mode 100644 index 00000000..c510c3ab --- /dev/null +++ b/include/boost/graph/is_kuratowski_subgraph.hpp @@ -0,0 +1,332 @@ +//======================================================================= +// Copyright 2007 Aaron Windsor +// +// 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 __IS_KURATOWSKI_SUBGRAPH_HPP__ +#define __IS_KURATOWSKI_SUBGRAPH_HPP__ + +#include +#include //for next/prior +#include //for tie +#include +#include +#include +#include + +#include +#include +#include + + + +namespace boost +{ + + namespace detail + { + + template + Graph make_K_5() + { + typename graph_traits::vertex_iterator vi, vi_end, inner_vi; + Graph K_5(5); + for(tie(vi,vi_end) = vertices(K_5); vi != vi_end; ++vi) + for(inner_vi = next(vi); inner_vi != vi_end; ++inner_vi) + add_edge(*vi, *inner_vi, K_5); + return K_5; + } + + + template + Graph make_K_3_3() + { + typename graph_traits::vertex_iterator + vi, vi_end, bipartition_start, inner_vi; + Graph K_3_3(6); + bipartition_start = next(next(next(vertices(K_3_3).first))); + for(tie(vi, vi_end) = vertices(K_3_3); vi != bipartition_start; ++vi) + for(inner_vi= bipartition_start; inner_vi != vi_end; ++inner_vi) + add_edge(*vi, *inner_vi, K_3_3); + return K_3_3; + } + + + template + void contract_edge(AdjacencyList& neighbors, Vertex u, Vertex v) + { + // Remove u from v's neighbor list + neighbors[v].erase(std::remove(neighbors[v].begin(), + neighbors[v].end(), u + ), + neighbors[v].end() + ); + + // Replace any references to u with references to v + typedef typename AdjacencyList::value_type::iterator + adjacency_iterator_t; + + adjacency_iterator_t u_neighbor_end = neighbors[u].end(); + for(adjacency_iterator_t u_neighbor_itr = neighbors[u].begin(); + u_neighbor_itr != u_neighbor_end; ++u_neighbor_itr + ) + { + Vertex u_neighbor(*u_neighbor_itr); + std::replace(neighbors[u_neighbor].begin(), + neighbors[u_neighbor].end(), u, v + ); + } + + // Remove v from u's neighbor list + neighbors[u].erase(std::remove(neighbors[u].begin(), + neighbors[u].end(), v + ), + neighbors[u].end() + ); + + // Add everything in u's neighbor list to v's neighbor list + std::copy(neighbors[u].begin(), + neighbors[u].end(), + std::back_inserter(neighbors[v]) + ); + + // Clear u's neighbor list + neighbors[u].clear(); + + } + + } // namespace detail + + + + + template + bool is_kuratowski_subgraph(const Graph& g, + ForwardIterator begin, + ForwardIterator end, + VertexIndexMap vm + ) + { + + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::vertex_iterator vertex_iterator_t; + typedef typename graph_traits::edge_descriptor edge_t; + typedef typename graph_traits::edges_size_type e_size_t; + typedef typename graph_traits::vertices_size_type v_size_t; + typedef typename std::vector v_list_t; + typedef typename v_list_t::iterator v_list_iterator_t; + typedef iterator_property_map + ::iterator, VertexIndexMap> + vertex_to_v_list_map_t; + + typedef adjacency_list small_graph_t; + + enum target_graph_t { k_3_3, k_5}; + + target_graph_t target_graph = k_3_3; //unless we decide otherwise later + + static small_graph_t K_5(detail::make_K_5()); + + static small_graph_t K_3_3(detail::make_K_3_3()); + + v_size_t n_vertices(num_vertices(g)); + v_size_t max_num_edges(3*n_vertices - 5); + + std::vector neighbors_vector(n_vertices); + vertex_to_v_list_map_t neighbors(neighbors_vector.begin(), vm); + + e_size_t count = 0; + for(ForwardIterator itr = begin; itr != end; ++itr) + { + + if (count++ > max_num_edges) + return false; + + edge_t e(*itr); + vertex_t u(source(e,g)); + vertex_t v(target(e,g)); + + neighbors[u].push_back(v); + neighbors[v].push_back(u); + + } + + + for(v_size_t max_size = 2; max_size < 5; ++max_size) + { + + vertex_iterator_t vi, vi_end; + for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + { + vertex_t v(*vi); + + //a hack to make sure we don't contract the middle edge of a path + //of four degree-3 vertices + if (max_size == 4 && neighbors[v].size() == 3) + { + if (neighbors[neighbors[v][0]].size() + + neighbors[neighbors[v][1]].size() + + neighbors[neighbors[v][2]].size() + < 11 // so, it has two degree-3 neighbors + ) + continue; + } + + while (neighbors[v].size() > 0 && neighbors[v].size() < max_size) + { + // Find one of v's neighbors u such that that v and u + // have no neighbors in common. We'll look for such a + // neighbor with a naive cubic-time algorithm since the + // max size of any of the neighbor sets we'll consider + // merging is 3 + + bool neighbor_sets_intersect = false; + + vertex_t min_u = graph_traits::null_vertex(); + vertex_t u; + v_list_iterator_t v_neighbor_end = neighbors[v].end(); + for(v_list_iterator_t v_neighbor_itr = neighbors[v].begin(); + v_neighbor_itr != v_neighbor_end; + ++v_neighbor_itr + ) + { + neighbor_sets_intersect = false; + u = *v_neighbor_itr; + v_list_iterator_t u_neighbor_end = neighbors[u].end(); + for(v_list_iterator_t u_neighbor_itr = + neighbors[u].begin(); + u_neighbor_itr != u_neighbor_end && + !neighbor_sets_intersect; + ++u_neighbor_itr + ) + { + for(v_list_iterator_t inner_v_neighbor_itr = + neighbors[v].begin(); + inner_v_neighbor_itr != v_neighbor_end; + ++inner_v_neighbor_itr + ) + { + if (*u_neighbor_itr == *inner_v_neighbor_itr) + { + neighbor_sets_intersect = true; + break; + } + } + + } + if (!neighbor_sets_intersect && + (min_u == graph_traits::null_vertex() || + neighbors[u].size() < neighbors[min_u].size()) + ) + { + min_u = u; + } + + } + + if (min_u == graph_traits::null_vertex()) + // Exited the loop without finding an appropriate neighbor of + // v, so v must be a lost cause. Move on to other vertices. + break; + else + u = min_u; + + detail::contract_edge(neighbors, u, v); + + }//end iteration over v's neighbors + + }//end iteration through vertices v + + if (max_size == 3) + { + // check to see whether we should go on to find a K_5 + for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + if (neighbors[*vi].size() == 4) + { + target_graph = k_5; + break; + } + + if (target_graph == k_3_3) + break; + } + + }//end iteration through max degree 2,3, and 4 + + + //Now, there should only be 5 or 6 vertices with any neighbors. Find them. + + v_list_t main_vertices; + vertex_iterator_t vi, vi_end; + + for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + { + if (!neighbors[*vi].empty()) + main_vertices.push_back(*vi); + } + + // create a graph isomorphic to the contracted graph to test + // against K_5 and K_3_3 + small_graph_t contracted_graph(main_vertices.size()); + std::map::vertex_descriptor> + contracted_vertex_map; + + typename v_list_t::iterator itr, itr_end; + itr_end = main_vertices.end(); + typename graph_traits::vertex_iterator + si = vertices(contracted_graph).first; + + for(itr = main_vertices.begin(); itr != itr_end; ++itr, ++si) + { + contracted_vertex_map[*itr] = *si; + } + + typename v_list_t::iterator jtr, jtr_end; + for(itr = main_vertices.begin(); itr != itr_end; ++itr) + { + jtr_end = neighbors[*itr].end(); + for(jtr = neighbors[*itr].begin(); jtr != jtr_end; ++jtr) + { + if (get(vm,*itr) < get(vm,*jtr)) + { + add_edge(contracted_vertex_map[*itr], + contracted_vertex_map[*jtr], + contracted_graph + ); + } + } + } + + if (target_graph == k_5) + { + return isomorphism(K_5,contracted_graph); + } + else //target_graph == k_3_3 + { + return isomorphism(K_3_3,contracted_graph); + } + + + } + + + + + + template + bool is_kuratowski_subgraph(const Graph& g, + ForwardIterator begin, + ForwardIterator end + ) + { + return is_kuratowski_subgraph(g, begin, end, get(vertex_index,g)); + } + + + + +} + +#endif //__IS_KURATOWSKI_SUBGRAPH_HPP__ diff --git a/include/boost/graph/is_straight_line_drawing.hpp b/include/boost/graph/is_straight_line_drawing.hpp new file mode 100644 index 00000000..f533bce2 --- /dev/null +++ b/include/boost/graph/is_straight_line_drawing.hpp @@ -0,0 +1,232 @@ +//======================================================================= +// Copyright 2007 Aaron Windsor +// +// 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 __IS_STRAIGHT_LINE_DRAWING_HPP__ +#define __IS_STRAIGHT_LINE_DRAWING_HPP__ + +#include +#include //for next and prior +#include +#include +#include +#include +#include + +#include +#include +#include + + + +namespace boost +{ + + // Return true exactly when the line segments s1 = ((x1,y1), (x2,y2)) and + // s2 = ((a1,b1), (a2,b2)) intersect in a point other than the endpoints of + // the line segments. The one exception to this rule is when s1 = s2, in + // which case false is returned - this is to accomodate multiple edges + // between the same pair of vertices, which shouldn't invalidate the straight + // line embedding. A tolerance variable epsilon can also be used, which + // defines how far away from the endpoints of s1 and s2 we want to consider + // an intersection. + + bool intersects(double x1, double y1, + double x2, double y2, + double a1, double b1, + double a2, double b2, + double epsilon = 0.000001 + ) + { + + if (x1 - x2 == 0) + { + std::swap(x1,a1); + std::swap(y1,b1); + std::swap(x2,a2); + std::swap(y2,b2); + } + + if (x1 - x2 == 0) + { + BOOST_USING_STD_MAX(); + BOOST_USING_STD_MIN(); + + //two vertical line segments + double min_y = min BOOST_PREVENT_MACRO_SUBSTITUTION(y1,y2); + double max_y = max BOOST_PREVENT_MACRO_SUBSTITUTION(y1,y2); + double min_b = min BOOST_PREVENT_MACRO_SUBSTITUTION(b1,b2); + double max_b = max BOOST_PREVENT_MACRO_SUBSTITUTION(b1,b2); + if ((max_y > max_b && max_b > min_y) || + (max_b > max_y && max_y > min_b) + ) + return true; + else + return false; + } + + double x_diff = x1 - x2; + double y_diff = y1 - y2; + double a_diff = a2 - a1; + double b_diff = b2 - b1; + + double beta_denominator = b_diff - (y_diff/((double)x_diff)) * a_diff; + + if (beta_denominator == 0) + { + //parallel lines + return false; + } + + double beta = (b2 - y2 - (y_diff/((double)x_diff)) * (a2 - x2)) / + beta_denominator; + double alpha = (a2 - x2 - beta*(a_diff))/x_diff; + + double upper_bound = 1 - epsilon; + double lower_bound = 0 + epsilon; + + return (beta < upper_bound && beta > lower_bound && + alpha < upper_bound && alpha > lower_bound); + + } + + + template + bool is_straight_line_drawing(const Graph& g, + GridPositionMap drawing, + VertexIndexMap vm + ) + { + + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::vertex_iterator vertex_iterator_t; + typedef typename graph_traits::edge_descriptor edge_t; + typedef typename graph_traits::edge_iterator edge_iterator_t; + typedef typename graph_traits::edges_size_type e_size_t; + typedef typename graph_traits::vertices_size_type v_size_t; + + typedef std::size_t x_coord_t; + typedef std::size_t y_coord_t; + typedef boost::tuple edge_event_t; + typedef typename std::vector< edge_event_t > edge_event_queue_t; + + typedef tuple active_map_key_t; + typedef edge_t active_map_value_t; + typedef std::map< active_map_key_t, active_map_value_t > active_map_t; + typedef typename active_map_t::iterator active_map_iterator_t; + + + edge_event_queue_t edge_event_queue; + active_map_t active_edges; + + edge_iterator_t ei, ei_end; + for(tie(ei,ei_end) = edges(g); ei != ei_end; ++ei) + { + edge_t e(*ei); + vertex_t s(source(e,g)); + vertex_t t(target(e,g)); + edge_event_queue.push_back + (make_tuple(e, + static_cast(drawing[s].x), + static_cast(drawing[s].y) + ) + ); + edge_event_queue.push_back + (make_tuple(e, + static_cast(drawing[t].x), + static_cast(drawing[t].y) + ) + ); + } + + // Order by edge_event_queue by first, then second coordinate + // (bucket_sort is a stable sort.) + bucket_sort(edge_event_queue.begin(), edge_event_queue.end(), + property_map_tuple_adaptor() + ); + + bucket_sort(edge_event_queue.begin(), edge_event_queue.end(), + property_map_tuple_adaptor() + ); + + typedef typename edge_event_queue_t::iterator event_queue_iterator_t; + event_queue_iterator_t itr_end = edge_event_queue.end(); + for(event_queue_iterator_t itr = edge_event_queue.begin(); + itr != itr_end; ++itr + ) + { + edge_t e(get<0>(*itr)); + vertex_t source_v(source(e,g)); + vertex_t target_v(target(e,g)); + if (drawing[source_v].x > drawing[target_v].x) + std::swap(source_v, target_v); + + active_map_key_t key(get(drawing, source_v).y, + get(drawing, target_v).y, + get(drawing, source_v).x, + get(drawing, target_v).x + ); + + active_map_iterator_t a_itr = active_edges.find(key); + if (a_itr == active_edges.end()) + { + active_edges[key] = e; + } + else + { + active_map_iterator_t before, after; + if (a_itr == active_edges.begin()) + before = active_edges.end(); + else + before = prior(a_itr); + after = next(a_itr); + + if (after != active_edges.end() || before != active_edges.end()) + { + + edge_t f = after != active_edges.end() ? + after->second : before->second; + + vertex_t e_source(source(e,g)); + vertex_t e_target(target(e,g)); + vertex_t f_source(source(f,g)); + vertex_t f_target(target(f,g)); + + if (intersects(drawing[e_source].x, + drawing[e_source].y, + drawing[e_target].x, + drawing[e_target].y, + drawing[f_source].x, + drawing[f_source].y, + drawing[f_target].x, + drawing[f_target].y + ) + ) + return false; + } + + active_edges.erase(a_itr); + + } + } + + return true; + + } + + + template + bool is_straight_line_drawing(const Graph& g, GridPositionMap drawing) + { + return is_straight_line_drawing(g, drawing, get(vertex_index,g)); + } + +} + +#endif // __IS_STRAIGHT_LINE_DRAWING_HPP__ diff --git a/include/boost/graph/isomorphism.hpp b/include/boost/graph/isomorphism.hpp index 1b8fe790..842f9143 100644 --- a/include/boost/graph/isomorphism.hpp +++ b/include/boost/graph/isomorphism.hpp @@ -245,7 +245,7 @@ namespace boost { } else { - if (contains(adjacent_vertices(f[i], G2), f[j])) { + if (container_contains(adjacent_vertices(f[i], G2), f[j])) { ++num_edges_on_k; if (match(next(iter), dfs_num_k)) return true; diff --git a/include/boost/graph/johnson_all_pairs_shortest.hpp b/include/boost/graph/johnson_all_pairs_shortest.hpp index 5a89e033..45a8cf2c 100644 --- a/include/boost/graph/johnson_all_pairs_shortest.hpp +++ b/include/boost/graph/johnson_all_pairs_shortest.hpp @@ -27,7 +27,6 @@ #include #include #include -#include #include namespace boost { diff --git a/include/boost/graph/kolmogorov_max_flow.hpp b/include/boost/graph/kolmogorov_max_flow.hpp new file mode 100644 index 00000000..e74796d3 --- /dev/null +++ b/include/boost/graph/kolmogorov_max_flow.hpp @@ -0,0 +1,807 @@ +// Copyright (c) 2006, Stephan Diederich +// +// This code may be used under either of the following two licences: +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE. +// +// Or: +// +// 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 BOOST_KOLMOGOROV_MAX_FLOW_HPP +#define BOOST_KOLMOGOROV_MAX_FLOW_HPP + +#include +#include +#include +#include +#include +#include +#include // for std::min and std::max + +#include +#include +#include +#include +#include +#include + +namespace boost { + namespace detail { + + template + class kolmogorov{ + typedef typename property_traits::value_type tEdgeVal; + typedef graph_traits tGraphTraits; + typedef typename tGraphTraits::vertex_iterator vertex_iterator; + typedef typename tGraphTraits::vertex_descriptor vertex_descriptor; + typedef typename tGraphTraits::edge_descriptor edge_descriptor; + typedef typename tGraphTraits::edge_iterator edge_iterator; + typedef typename tGraphTraits::out_edge_iterator out_edge_iterator; + typedef boost::queue tQueue; //queue of vertices, used in adoption-stage + typedef typename property_traits::value_type tColorValue; + typedef color_traits tColorTraits; + typedef typename property_traits::value_type tDistanceVal; + + public: + kolmogorov(Graph& g, + EdgeCapacityMap cap, + ResidualCapacityEdgeMap res, + ReverseEdgeMap rev, + PredecessorMap pre, + ColorMap color, + DistanceMap dist, + IndexMap idx, + vertex_descriptor src, + vertex_descriptor sink): + m_g(g), + m_index_map(idx), + m_cap_map(cap), + m_res_cap_map(res), + m_rev_edge_map(rev), + m_pre_map(pre), + m_tree_map(color), + m_dist_map(dist), + m_source(src), + m_sink(sink), + m_active_nodes(), + m_in_active_list_vec(num_vertices(g), false), + m_in_active_list_map(make_iterator_property_map(m_in_active_list_vec.begin(), m_index_map)), + m_has_parent_vec(num_vertices(g), false), + m_has_parent_map(make_iterator_property_map(m_has_parent_vec.begin(), m_index_map)), + m_time_vec(num_vertices(g), 0), + m_time_map(make_iterator_property_map(m_time_vec.begin(), m_index_map)), + m_flow(0), + m_time(1), + m_last_grow_vertex(graph_traits::null_vertex()){ + // initialize the color-map with gray-values + vertex_iterator vi, v_end; + for(tie(vi, v_end) = vertices(m_g); vi != v_end; ++vi){ + set_tree(*vi, tColorTraits::gray()); + } + // Initialize flow to zero which means initializing + // the residual capacity equal to the capacity + edge_iterator ei, e_end; + for(tie(ei, e_end) = edges(m_g); ei != e_end; ++ei) { + m_res_cap_map[*ei] = m_cap_map[*ei]; + assert(m_rev_edge_map[m_rev_edge_map[*ei]] == *ei); //check if the reverse edge map is build up properly + } + //init the search trees with the two terminals + set_tree(m_source, tColorTraits::black()); + set_tree(m_sink, tColorTraits::white()); + m_time_map[m_source] = 1; + m_time_map[m_sink] = 1; + } + + ~kolmogorov(){} + + tEdgeVal max_flow(){ + //augment direct paths from SOURCE->SINK and SOURCE->VERTEX->SINK + augment_direct_paths(); + //start the main-loop + while(true){ + bool path_found; + edge_descriptor connecting_edge; + tie(connecting_edge, path_found) = grow(); //find a path from source to sink + if(!path_found){ + //we're finished, no more paths were found + break; + } + ++m_time; + augment(connecting_edge); //augment that path + adopt(); //rebuild search tree structure + } + return m_flow; + } + + //the complete class is protected, as we want access to members in derived test-class (see $(BOOST_ROOT)/libs/graph/test/kolmogorov_max_flow_test.cpp) + protected: + void augment_direct_paths(){ + //in a first step, we augment all direct paths from source->NODE->sink + //and additionally paths from source->sink + //this improves especially graphcuts for segmentation, as most of the nodes have source/sink connects + //but shouldn't have an impact on other maxflow problems (this is done in grow() anyway) + out_edge_iterator ei, e_end; + for(tie(ei, e_end) = out_edges(m_source, m_g); ei != e_end; ++ei){ + edge_descriptor from_source = *ei; + vertex_descriptor current_node = target(from_source, m_g); + if(current_node == m_sink){ + tEdgeVal cap = m_res_cap_map[from_source]; + m_res_cap_map[from_source] = 0; + m_flow += cap; + continue; + } + edge_descriptor to_sink; + bool is_there; + tie(to_sink, is_there) = edge(current_node, m_sink, m_g); + if(is_there){ + tEdgeVal cap_from_source = m_res_cap_map[from_source]; + tEdgeVal cap_to_sink = m_res_cap_map[to_sink]; + if(cap_from_source > cap_to_sink){ + set_tree(current_node, tColorTraits::black()); + add_active_node(current_node); + set_edge_to_parent(current_node, from_source); + m_dist_map[current_node] = 1; + m_time_map[current_node] = 1; + //add stuff to flow and update residuals + //we dont need to update reverse_edges, as incoming/outgoing edges to/from source/sink don't count for max-flow + m_res_cap_map[from_source] -= cap_to_sink; + m_res_cap_map[to_sink] = 0; + m_flow += cap_to_sink; + } else if(cap_to_sink > 0){ + set_tree(current_node, tColorTraits::white()); + add_active_node(current_node); + set_edge_to_parent(current_node, to_sink); + m_dist_map[current_node] = 1; + m_time_map[current_node] = 1; + //add stuff to flow and update residuals + //we dont need to update reverse_edges, as incoming/outgoing edges to/from source/sink don't count for max-flow + m_res_cap_map[to_sink] -= cap_from_source; + m_res_cap_map[from_source] = 0; + m_flow += cap_from_source; + } + } else if(m_res_cap_map[from_source]){ + //there is no sink connect, so we can't augment this path + //but to avoid adding m_source to the active nodes, we just activate this node and set the approciate things + set_tree(current_node, tColorTraits::black()); + set_edge_to_parent(current_node, from_source); + m_dist_map[current_node] = 1; + m_time_map[current_node] = 1; + add_active_node(current_node); + } + } + for(tie(ei, e_end) = out_edges(m_sink, m_g); ei != e_end; ++ei){ + edge_descriptor to_sink = m_rev_edge_map[*ei]; + vertex_descriptor current_node = source(to_sink, m_g); + if(m_res_cap_map[to_sink]){ + set_tree(current_node, tColorTraits::white()); + set_edge_to_parent(current_node, to_sink); + m_dist_map[current_node] = 1; + m_time_map[current_node] = 1; + add_active_node(current_node); + } + } + } + + /** + * returns a pair of an edge and a boolean. if the bool is true, the edge is a connection of a found path from s->t , read "the link" and + * source(returnVal, m_g) is the end of the path found in the source-tree + * target(returnVal, m_g) is the beginning of the path found in the sink-tree + */ + std::pair grow(){ + assert(m_orphans.empty()); + vertex_descriptor current_node; + while((current_node = get_next_active_node()) != graph_traits::null_vertex()){ //if there is one + assert(get_tree(current_node) != tColorTraits::gray() && (has_parent(current_node) || current_node==m_source || current_node==m_sink)); + if(get_tree(current_node) == tColorTraits::black()){ + //source tree growing + out_edge_iterator ei, e_end; + if(current_node != m_last_grow_vertex){ + m_last_grow_vertex = current_node; + tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g); + } + for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it){ + edge_descriptor out_edge = *m_last_grow_edge_it; + if(m_res_cap_map[out_edge] > 0){ //check if we have capacity left on this edge + vertex_descriptor other_node = target(out_edge, m_g); + if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node + set_tree(other_node, tColorTraits::black()); //aquire other node to our search tree + set_edge_to_parent(other_node, out_edge); //set us as parent + m_dist_map[other_node] = m_dist_map[current_node] + 1; //and update the distance-heuristic + m_time_map[other_node] = m_time_map[current_node]; + add_active_node(other_node); + } else if(get_tree(other_node) == tColorTraits::black()){ + if(is_closer_to_terminal(current_node, other_node)){ //we do this to get shorter paths. check if we are nearer to the source as its parent is + set_edge_to_parent(other_node, out_edge); + m_dist_map[other_node] = m_dist_map[current_node] + 1; + m_time_map[other_node] = m_time_map[current_node]; + } + } else{ + assert(get_tree(other_node)==tColorTraits::white()); + //kewl, found a path from one to the other search tree, return the connecting edge in src->sink dir + return std::make_pair(out_edge, true); + } + } + } //for all out-edges + } //source-tree-growing + else{ + assert(get_tree(current_node) == tColorTraits::white()); + out_edge_iterator ei, e_end; + if(current_node != m_last_grow_vertex){ + m_last_grow_vertex = current_node; + tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g); + } + for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it){ + edge_descriptor in_edge = m_rev_edge_map[*m_last_grow_edge_it]; + if(m_res_cap_map[in_edge] > 0){ //check if there is capacity left + vertex_descriptor other_node = source(in_edge, m_g); + if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node + set_tree(other_node, tColorTraits::white()); //aquire that node to our search tree + set_edge_to_parent(other_node, in_edge); //set us as parent + add_active_node(other_node); //activate that node + m_dist_map[other_node] = m_dist_map[current_node] + 1; //set its distance + m_time_map[other_node] = m_time_map[current_node]; //and time + } else if(get_tree(other_node) == tColorTraits::white()){ + if(is_closer_to_terminal(current_node, other_node)){ + //we are closer to the sink than its parent is, so we "adopt" him + set_edge_to_parent(other_node, in_edge); + m_dist_map[other_node] = m_dist_map[current_node] + 1; + m_time_map[other_node] = m_time_map[current_node]; + } + } else{ + assert(get_tree(other_node)==tColorTraits::black()); + //kewl, found a path from one to the other search tree, return the connecting edge in src->sink dir + return std::make_pair(in_edge, true); + } + } + } //for all out-edges + } //sink-tree growing + //all edges of that node are processed, and no more paths were found. so remove if from the front of the active queue + finish_node(current_node); + } //while active_nodes not empty + return std::make_pair(edge_descriptor(), false); //no active nodes anymore and no path found, we're done + } + + /** + * augments path from s->t and updates residual graph + * source(e, m_g) is the end of the path found in the source-tree + * target(e, m_g) is the beginning of the path found in the sink-tree + * this phase generates orphans on satured edges, if the attached verts are from different search-trees + * orphans are ordered in distance to sink/source. first the farest from the source are front_inserted into the orphans list, + * and after that the sink-tree-orphans are front_inserted. when going to adoption stage the orphans are popped_front, and so we process the nearest + * verts to the terminals first + */ + void augment(edge_descriptor e){ + assert(get_tree(target(e, m_g)) == tColorTraits::white()); + assert(get_tree(source(e, m_g)) == tColorTraits::black()); + assert(m_orphans.empty()); + + const tEdgeVal bottleneck = find_bottleneck(e); + //now we push the found flow through the path + //for each edge we saturate we have to look for the verts that belong to that edge, one of them becomes an orphans + //now process the connecting edge + m_res_cap_map[e] -= bottleneck; + assert(m_res_cap_map[e] >= 0); + m_res_cap_map[m_rev_edge_map[e]] += bottleneck; + + //now we follow the path back to the source + vertex_descriptor current_node = source(e, m_g); + while(current_node != m_source){ + edge_descriptor pred = get_edge_to_parent(current_node); + m_res_cap_map[pred] -= bottleneck; + assert(m_res_cap_map[pred] >= 0); + m_res_cap_map[m_rev_edge_map[pred]] += bottleneck; + if(m_res_cap_map[pred] == 0){ + set_no_parent(current_node); + m_orphans.push_front(current_node); + } + current_node = source(pred, m_g); + } + //then go forward in the sink-tree + current_node = target(e, m_g); + while(current_node != m_sink){ + edge_descriptor pred = get_edge_to_parent(current_node); + m_res_cap_map[pred] -= bottleneck; + assert(m_res_cap_map[pred] >= 0); + m_res_cap_map[m_rev_edge_map[pred]] += bottleneck; + if(m_res_cap_map[pred] == 0){ + set_no_parent(current_node); + m_orphans.push_front(current_node); + } + current_node = target(pred, m_g); + } + //and add it to the max-flow + m_flow += bottleneck; + } + + /** + * returns the bottleneck of a s->t path (end_of_path is last vertex in source-tree, begin_of_path is first vertex in sink-tree) + */ + inline tEdgeVal find_bottleneck(edge_descriptor e){ + BOOST_USING_STD_MIN(); + tEdgeVal minimum_cap = m_res_cap_map[e]; + vertex_descriptor current_node = source(e, m_g); + //first go back in the source tree + while(current_node != m_source){ + edge_descriptor pred = get_edge_to_parent(current_node); + minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, m_res_cap_map[pred]); + current_node = source(pred, m_g); + } + //then go forward in the sink-tree + current_node = target(e, m_g); + while(current_node != m_sink){ + edge_descriptor pred = get_edge_to_parent(current_node); + minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, m_res_cap_map[pred]); + current_node = target(pred, m_g); + } + return minimum_cap; + } + + /** + * rebuild search trees + * empty the queue of orphans, and find new parents for them or just drop them from the search trees + */ + void adopt(){ + while(!m_orphans.empty() || !m_child_orphans.empty()){ + vertex_descriptor current_node; + if(m_child_orphans.empty()){ + //get the next orphan from the main-queue and remove it + current_node = m_orphans.front(); + m_orphans.pop_front(); + } else{ + current_node = m_child_orphans.front(); + m_child_orphans.pop(); + } + if(get_tree(current_node) == tColorTraits::black()){ + //we're in the source-tree + tDistanceVal min_distance = (std::numeric_limits::max)(); + edge_descriptor new_parent_edge; + out_edge_iterator ei, e_end; + for(tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ + const edge_descriptor in_edge = m_rev_edge_map[*ei]; + assert(target(in_edge, m_g) == current_node); //we should be the target of this edge + if(m_res_cap_map[in_edge] > 0){ + vertex_descriptor other_node = source(in_edge, m_g); + if(get_tree(other_node) == tColorTraits::black() && has_source_connect(other_node)){ + if(m_dist_map[other_node] < min_distance){ + min_distance = m_dist_map[other_node]; + new_parent_edge = in_edge; + } + } + } + } + if(min_distance != (std::numeric_limits::max)()){ + set_edge_to_parent(current_node, new_parent_edge); + m_dist_map[current_node] = min_distance + 1; + m_time_map[current_node] = m_time; + } else{ + m_time_map[current_node] = 0; + for(tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ + edge_descriptor in_edge = m_rev_edge_map[*ei]; + vertex_descriptor other_node = source(in_edge, m_g); + if(get_tree(other_node) == tColorTraits::black() && has_parent(other_node)){ + if(m_res_cap_map[in_edge] > 0){ + add_active_node(other_node); + } + if(source(get_edge_to_parent(other_node), m_g) == current_node){ + //we are the parent of that node + //it has to find a new parent, too + set_no_parent(other_node); + m_child_orphans.push(other_node); + } + } + } + set_tree(current_node, tColorTraits::gray()); + } //no parent found + } //source-tree-adoption + else{ + //now we should be in the sink-tree, check that... + assert(get_tree(current_node) == tColorTraits::white()); + out_edge_iterator ei, e_end; + edge_descriptor new_parent_edge; + tDistanceVal min_distance = (std::numeric_limits::max)(); + for(tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ + const edge_descriptor out_edge = *ei; + if(m_res_cap_map[out_edge] > 0){ + const vertex_descriptor other_node = target(out_edge, m_g); + if(get_tree(other_node) == tColorTraits::white() && has_sink_connect(other_node)) + if(m_dist_map[other_node] < min_distance){ + min_distance = m_dist_map[other_node]; + new_parent_edge = out_edge; + } + } + } + if(min_distance != (std::numeric_limits::max)()){ + set_edge_to_parent(current_node, new_parent_edge); + m_dist_map[current_node] = min_distance + 1; + m_time_map[current_node] = m_time; + } else{ + m_time_map[current_node] = 0; + for(tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){ + const edge_descriptor out_edge = *ei; + const vertex_descriptor other_node = target(out_edge, m_g); + if(get_tree(other_node) == tColorTraits::white() && has_parent(other_node)){ + if(m_res_cap_map[out_edge] > 0){ + add_active_node(other_node); + } + if(target(get_edge_to_parent(other_node), m_g) == current_node){ + //we were it's parent, so it has to find a new one, too + set_no_parent(other_node); + m_child_orphans.push(other_node); + } + } + } + set_tree(current_node, tColorTraits::gray()); + } //no parent found + } //sink-tree adoption + } //while !orphans.empty() + } //adopt + + /** + * return next active vertex if there is one, otherwise a null_vertex + */ + inline vertex_descriptor get_next_active_node(){ + while(true){ + if(m_active_nodes.empty()) + return graph_traits::null_vertex(); + vertex_descriptor v = m_active_nodes.front(); + + if(!has_parent(v) && v != m_source && v != m_sink){ //if it has no parent, this node can't be active(if its not source or sink) + m_active_nodes.pop(); + m_in_active_list_map[v] = false; + } else{ + assert(get_tree(v) == tColorTraits::black() || get_tree(v) == tColorTraits::white()); + return v; + } + } + } + + /** + * adds v as an active vertex, but only if its not in the list already + */ + inline void add_active_node(vertex_descriptor v){ + assert(get_tree(v) != tColorTraits::gray()); + if(m_in_active_list_map[v]){ + return; + } else{ + m_in_active_list_map[v] = true; + m_active_nodes.push(v); + } + } + + /** + * finish_node removes a node from the front of the active queue (its called in grow phase, if no more paths can be found using this node) + */ + inline void finish_node(vertex_descriptor v){ + assert(m_active_nodes.front() == v); + m_active_nodes.pop(); + m_in_active_list_map[v] = false; + m_last_grow_vertex = graph_traits::null_vertex(); + } + + /** + * removes a vertex from the queue of active nodes (actually this does nothing, + * but checks if this node has no parent edge, as this is the criteria for beeing no more active) + */ + inline void remove_active_node(vertex_descriptor v){ + assert(!has_parent(v)); + } + + /** + * returns the search tree of v; tColorValue::black() for source tree, white() for sink tree, gray() for no tree + */ + inline tColorValue get_tree(vertex_descriptor v) const { + return m_tree_map[v]; + } + + /** + * sets search tree of v; tColorValue::black() for source tree, white() for sink tree, gray() for no tree + */ + inline void set_tree(vertex_descriptor v, tColorValue t){ + m_tree_map[v] = t; + } + + /** + * returns edge to parent vertex of v; + */ + inline edge_descriptor get_edge_to_parent(vertex_descriptor v) const{ + return m_pre_map[v]; + } + + /** + * returns true if the edge stored in m_pre_map[v] is a valid entry + */ + inline bool has_parent(vertex_descriptor v) const{ + return m_has_parent_map[v]; + } + + /** + * sets edge to parent vertex of v; + */ + inline void set_edge_to_parent(vertex_descriptor v, edge_descriptor f_edge_to_parent){ + assert(m_res_cap_map[f_edge_to_parent] > 0); + m_pre_map[v] = f_edge_to_parent; + m_has_parent_map[v] = true; + } + + /** + * removes the edge to parent of v (this is done by invalidating the entry an additional map) + */ + inline void set_no_parent(vertex_descriptor v){ + m_has_parent_map[v] = false; + } + + /** + * checks if vertex v has a connect to the sink-vertex (@var m_sink) + * @param v the vertex which is checked + * @return true if a path to the sink was found, false if not + */ + inline bool has_sink_connect(vertex_descriptor v){ + tDistanceVal current_distance = 0; + vertex_descriptor current_vertex = v; + while(true){ + if(m_time_map[current_vertex] == m_time){ + //we found a node which was already checked this round. use it for distance calculations + current_distance += m_dist_map[current_vertex]; + break; + } + if(current_vertex == m_sink){ + m_time_map[m_sink] = m_time; + break; + } + if(has_parent(current_vertex)){ + //it has a parent, so get it + current_vertex = target(get_edge_to_parent(current_vertex), m_g); + ++current_distance; + } else{ + //no path found + return false; + } + } + current_vertex=v; + while(m_time_map[current_vertex] != m_time){ + m_dist_map[current_vertex] = current_distance--; + m_time_map[current_vertex] = m_time; + current_vertex = target(get_edge_to_parent(current_vertex), m_g); + } + return true; + } + + /** + * checks if vertex v has a connect to the source-vertex (@var m_source) + * @param v the vertex which is checked + * @return true if a path to the source was found, false if not + */ + inline bool has_source_connect(vertex_descriptor v){ + tDistanceVal current_distance = 0; + vertex_descriptor current_vertex = v; + while(true){ + if(m_time_map[current_vertex] == m_time){ + //we found a node which was already checked this round. use it for distance calculations + current_distance += m_dist_map[current_vertex]; + break; + } + if(current_vertex == m_source){ + m_time_map[m_source] = m_time; + break; + } + if(has_parent(current_vertex)){ + //it has a parent, so get it + current_vertex = source(get_edge_to_parent(current_vertex), m_g); + ++current_distance; + } else{ + //no path found + return false; + } + } + current_vertex=v; + while(m_time_map[current_vertex] != m_time){ + m_dist_map[current_vertex] = current_distance-- ; + m_time_map[current_vertex] = m_time; + current_vertex = source(get_edge_to_parent(current_vertex), m_g); + } + return true; + } + + /** + * returns true, if p is closer to a terminal than q + */ + inline bool is_closer_to_terminal(vertex_descriptor p, vertex_descriptor q){ + //checks the timestamps first, to build no cycles, and after that the real distance + return (m_time_map[q] <= m_time_map[p] && m_dist_map[q] > m_dist_map[p]+1); + } + + //////// + // member vars + //////// + Graph& m_g; + IndexMap m_index_map; + EdgeCapacityMap m_cap_map; + ResidualCapacityEdgeMap m_res_cap_map; + ReverseEdgeMap m_rev_edge_map; + PredecessorMap m_pre_map; //stores paths found in the growth stage + ColorMap m_tree_map; //maps each vertex into one of the two search tree or none (gray()) + DistanceMap m_dist_map; //stores distance to source/sink nodes + vertex_descriptor m_source; + vertex_descriptor m_sink; + + tQueue m_active_nodes; + std::vector m_in_active_list_vec; + iterator_property_map::iterator, IndexMap> m_in_active_list_map; + + std::list m_orphans; + tQueue m_child_orphans; // we use a second queuqe for child orphans, as they are FIFO processed + + std::vector m_has_parent_vec; + iterator_property_map::iterator, IndexMap> m_has_parent_map; + + std::vector m_time_vec; //timestamp of each node, used for sink/source-path calculations + iterator_property_map::iterator, IndexMap> m_time_map; + tEdgeVal m_flow; + long m_time; + vertex_descriptor m_last_grow_vertex; + out_edge_iterator m_last_grow_edge_it; + out_edge_iterator m_last_grow_edge_end; + }; + } //namespace detail + + /** + * non-named-parameter version, given everything + * this is the catch all version + */ + template + typename property_traits::value_type + kolmogorov_max_flow + (Graph& g, + CapacityEdgeMap cap, + ResidualCapacityEdgeMap res_cap, + ReverseEdgeMap rev_map, + PredecessorMap pre_map, + ColorMap color, + DistanceMap dist, + IndexMap idx, + typename graph_traits::vertex_descriptor src, + typename graph_traits::vertex_descriptor sink + ) + { + typedef typename graph_traits::vertex_descriptor vertex_descriptor; + typedef typename graph_traits::edge_descriptor edge_descriptor; + //as this method is the last one before we instantiate the solver, we do the concept checks here + function_requires >(); //to have vertices(), num_vertices(), + function_requires >(); //to have edges() + function_requires >(); //to have source(), target() and out_edges() + function_requires >(); //read flow-values from edges + function_requires >(); //write flow-values to residuals + function_requires >(); //read out reverse edges + function_requires >(); //store predecessor there + function_requires >(); //write corresponding tree + function_requires >(); //write distance to source/sink + function_requires >(); //get index 0...|V|-1 + assert(num_vertices(g) >= 2 && src != sink); + detail::kolmogorov + algo(g, cap, res_cap, rev_map, pre_map, color, dist, idx, src, sink); + return algo.max_flow(); + } + + /** + * non-named-parameter version, given: capacity, residucal_capacity, reverse_edges, and an index map. + */ + template + typename property_traits::value_type + kolmogorov_max_flow + (Graph& g, + CapacityEdgeMap cap, + ResidualCapacityEdgeMap res_cap, + ReverseEdgeMap rev, + IndexMap idx, + typename graph_traits::vertex_descriptor src, + typename graph_traits::vertex_descriptor sink) + { + typename graph_traits::vertices_size_type n_verts = num_vertices(g); + std::vector::edge_descriptor> predecessor_vec(n_verts); + std::vector color_vec(n_verts); + std::vector::vertices_size_type> distance_vec(n_verts); + return kolmogorov_max_flow + (g, cap, res_cap, rev, + make_iterator_property_map(predecessor_vec.begin(), idx), + make_iterator_property_map(color_vec.begin(), idx), + make_iterator_property_map(distance_vec.begin(), idx), + idx, src, sink); + } + + /** + * non-named-parameter version, some given: capacity, residual_capacity, reverse_edges, color_map and an index map. + * Use this if you are interested in the minimum cut, as the color map provides that info + */ + template + typename property_traits::value_type + kolmogorov_max_flow + (Graph& g, + CapacityEdgeMap cap, + ResidualCapacityEdgeMap res_cap, + ReverseEdgeMap rev, + ColorMap color, + IndexMap idx, + typename graph_traits::vertex_descriptor src, + typename graph_traits::vertex_descriptor sink) + { + typename graph_traits::vertices_size_type n_verts = num_vertices(g); + std::vector::edge_descriptor> predecessor_vec(n_verts); + std::vector::vertices_size_type> distance_vec(n_verts); + + return kolmogorov_max_flow + (g, cap, res_cap, rev, + make_iterator_property_map(predecessor_vec.begin(), idx), + color, + make_iterator_property_map(distance_vec.begin(), idx), + idx, src, sink); + } + + /** + * named-parameter version, some given + */ + template + typename property_traits::const_type>::value_type + kolmogorov_max_flow + (Graph& g, + typename graph_traits::vertex_descriptor src, + typename graph_traits::vertex_descriptor sink, + const bgl_named_params& params) + { + return kolmogorov_max_flow(g, + choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity), + choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity), + choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse), + choose_pmap(get_param(params, vertex_predecessor), g, vertex_predecessor), + choose_pmap(get_param(params, vertex_color), g, vertex_color), + choose_pmap(get_param(params, vertex_distance), g, vertex_distance), + choose_const_pmap(get_param(params, vertex_index), g, vertex_index), + src, sink); + } + + /** + * named-parameter version, none given + */ + template + typename property_traits::const_type>::value_type + kolmogorov_max_flow + (Graph& g, + typename graph_traits::vertex_descriptor src, + typename graph_traits::vertex_descriptor sink) + { + bgl_named_params params(0); // bogus empty param + return kolmogorov_max_flow(g, src, sink, params); + } +} // namespace boost + +#endif // BOOST_KOLMOGOROV_MAX_FLOW_HPP + diff --git a/include/boost/graph/leda_graph.hpp b/include/boost/graph/leda_graph.hpp index 89c98ac2..770874c5 100644 --- a/include/boost/graph/leda_graph.hpp +++ b/include/boost/graph/leda_graph.hpp @@ -1,7 +1,9 @@ //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Copyright 2004 The Trustees of Indiana University. -// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Douglas Gregor +// Copyright 2007 University of Karlsruhe +// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Douglas Gregor, +// Jens Mueller // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -23,9 +25,6 @@ // treat a LEDA GRAPH object as a boost graph "as is". No // wrapper is needed for the GRAPH object. -// Remember to define LEDA_PREFIX so that LEDA types such as -// leda_edge show up as "leda_edge" and not just "edge". - // Warning: this implementation relies on partial specialization // for the graph_traits class (so it won't compile with Visual C++) @@ -41,95 +40,103 @@ namespace boost { template struct graph_traits< leda::GRAPH > { - typedef leda_node vertex_descriptor; - typedef leda_edge edge_descriptor; + typedef leda::node vertex_descriptor; + typedef leda::edge edge_descriptor; class adjacency_iterator : public iterator_facade + leda::node, + const leda::node*> { public: - explicit adjacency_iterator(leda_edge edge = 0) : base(edge) {} - + adjacency_iterator(leda::node node = 0, + const leda::GRAPH* g = 0) + : base(node), g(g) {} private: - leda_node dereference() const { return leda::target(base); } + leda::node dereference() const { return leda::target(base); } bool equal(const adjacency_iterator& other) const { return base == other.base; } - void increment() { base = Succ_Adj_Edge(base, 0); } - void decrement() { base = Pred_Adj_Edge(base, 0); } + void increment() { base = g->adj_succ(base); } + void decrement() { base = g->adj_pred(base); } - leda_edge base; + leda::edge base; + const leda::GRAPH* g; friend class iterator_core_access; }; - + class out_edge_iterator : public iterator_facade + const leda::edge&, + const leda::edge*> { public: - explicit out_edge_iterator(leda_edge edge = 0) : base(edge) {} + out_edge_iterator(leda::node node = 0, + const leda::GRAPH* g = 0) + : base(node), g(g) {} private: - const leda_edge& dereference() const { return base; } + const leda::edge& dereference() const { return base; } bool equal(const out_edge_iterator& other) const { return base == other.base; } - void increment() { base = Succ_Adj_Edge(base, 0); } - void decrement() { base = Pred_Adj_Edge(base, 0); } + void increment() { base = g->adj_succ(base); } + void decrement() { base = g->adj_pred(base); } - leda_edge base; + leda::edge base; + const leda::GRAPH* g; friend class iterator_core_access; }; - + class in_edge_iterator : public iterator_facade + const leda::edge&, + const leda::edge*> { public: - explicit in_edge_iterator(leda_edge edge = 0) : base(edge) {} + in_edge_iterator(leda::node node = 0, + const leda::GRAPH* g = 0) + : base(node), g(g) {} private: - const leda_edge& dereference() const { return base; } + const leda::edge& dereference() const { return base; } bool equal(const in_edge_iterator& other) const { return base == other.base; } - void increment() { base = Succ_Adj_Edge(base, 1); } - void decrement() { base = Pred_Adj_Edge(base, 1); } + void increment() { base = g->in_succ(base); } + void decrement() { base = g->in_pred(base); } - leda_edge base; + leda::edge base; + const leda::GRAPH* g; friend class iterator_core_access; }; class vertex_iterator : public iterator_facade + const leda::node&, + const leda::node*> { public: - vertex_iterator(leda_node node = 0, + vertex_iterator(leda::node node = 0, const leda::GRAPH* g = 0) : base(node), g(g) {} private: - const leda_node& dereference() const { return base; } + const leda::node& dereference() const { return base; } bool equal(const vertex_iterator& other) const { return base == other.base; } @@ -137,7 +144,34 @@ namespace boost { void increment() { base = g->succ_node(base); } void decrement() { base = g->pred_node(base); } - leda_node base; + leda::node base; + const leda::GRAPH* g; + + friend class iterator_core_access; + }; + + class edge_iterator + : public iterator_facade + { + public: + edge_iterator(leda::edge edge = 0, + const leda::GRAPH* g = 0) + : base(edge), g(g) {} + + private: + const leda::edge& dereference() const { return base; } + + bool equal(const edge_iterator& other) const + { return base == other.base; } + + void increment() { base = g->succ_edge(base); } + void decrement() { base = g->pred_edge(base); } + + leda::node base; const leda::GRAPH* g; friend class iterator_core_access; @@ -151,14 +185,154 @@ namespace boost { typedef int degree_size_type; }; - template - struct vertex_property< leda::GRAPH > { - typedef vtype type; - }; - template - struct edge_property< leda::GRAPH > { - typedef etype type; + + template<> + struct graph_traits { + typedef leda::node vertex_descriptor; + typedef leda::edge edge_descriptor; + + class adjacency_iterator + : public iterator_facade + { + public: + adjacency_iterator(leda::edge edge = 0, + const leda::graph* g = 0) + : base(edge), g(g) {} + + private: + leda::node dereference() const { return leda::target(base); } + + bool equal(const adjacency_iterator& other) const + { return base == other.base; } + + void increment() { base = g->adj_succ(base); } + void decrement() { base = g->adj_pred(base); } + + leda::edge base; + const leda::graph* g; + + friend class iterator_core_access; + }; + + class out_edge_iterator + : public iterator_facade + { + public: + out_edge_iterator(leda::edge edge = 0, + const leda::graph* g = 0) + : base(edge), g(g) {} + + private: + const leda::edge& dereference() const { return base; } + + bool equal(const out_edge_iterator& other) const + { return base == other.base; } + + void increment() { base = g->adj_succ(base); } + void decrement() { base = g->adj_pred(base); } + + leda::edge base; + const leda::graph* g; + + friend class iterator_core_access; + }; + + class in_edge_iterator + : public iterator_facade + { + public: + in_edge_iterator(leda::edge edge = 0, + const leda::graph* g = 0) + : base(edge), g(g) {} + + private: + const leda::edge& dereference() const { return base; } + + bool equal(const in_edge_iterator& other) const + { return base == other.base; } + + void increment() { base = g->in_succ(base); } + void decrement() { base = g->in_pred(base); } + + leda::edge base; + const leda::graph* g; + + friend class iterator_core_access; + }; + + class vertex_iterator + : public iterator_facade + { + public: + vertex_iterator(leda::node node = 0, + const leda::graph* g = 0) + : base(node), g(g) {} + + private: + const leda::node& dereference() const { return base; } + + bool equal(const vertex_iterator& other) const + { return base == other.base; } + + void increment() { base = g->succ_node(base); } + void decrement() { base = g->pred_node(base); } + + leda::node base; + const leda::graph* g; + + friend class iterator_core_access; + }; + + class edge_iterator + : public iterator_facade + { + public: + edge_iterator(leda::edge edge = 0, + const leda::graph* g = 0) + : base(edge), g(g) {} + + private: + const leda::edge& dereference() const { return base; } + + bool equal(const edge_iterator& other) const + { return base == other.base; } + + void increment() { base = g->succ_edge(base); } + void decrement() { base = g->pred_edge(base); } + + leda::edge base; + const leda::graph* g; + + friend class iterator_core_access; + }; + + typedef directed_tag directed_category; + typedef allow_parallel_edge_tag edge_parallel_category; // not sure here + typedef leda_graph_traversal_category traversal_category; + typedef int vertices_size_type; + typedef int edges_size_type; + typedef int degree_size_type; }; } // namespace boost @@ -166,6 +340,9 @@ namespace boost { namespace boost { + //=========================================================================== + // functions for GRAPH + template typename graph_traits< leda::GRAPH >::vertex_descriptor source(typename graph_traits< leda::GRAPH >::edge_descriptor e, @@ -193,7 +370,16 @@ namespace boost { return std::make_pair( Iter(g.first_node(),&g), Iter(0,&g) ); } - // no edges(g) function + template + inline std::pair< + typename graph_traits< leda::GRAPH >::edge_iterator, + typename graph_traits< leda::GRAPH >::edge_iterator > + edges(const leda::GRAPH& g) + { + typedef typename graph_traits< leda::GRAPH >::edge_iterator + Iter; + return std::make_pair( Iter(g.first_edge(),&g), Iter(0,&g) ); + } template inline std::pair< @@ -205,7 +391,7 @@ namespace boost { { typedef typename graph_traits< leda::GRAPH > ::out_edge_iterator Iter; - return std::make_pair( Iter(First_Adj_Edge(u,0)), Iter(0) ); + return std::make_pair( Iter(g.first_adj_edge(u,0),&g), Iter(0,&g) ); } template @@ -218,7 +404,7 @@ namespace boost { { typedef typename graph_traits< leda::GRAPH > ::in_edge_iterator Iter; - return std::make_pair( Iter(First_Adj_Edge(u,1)), Iter(0) ); + return std::make_pair( Iter(g.first_adj_edge(u,1),&g), Iter(0,&g) ); } template @@ -231,7 +417,7 @@ namespace boost { { typedef typename graph_traits< leda::GRAPH > ::adjacency_iterator Iter; - return std::make_pair( Iter(First_Adj_Edge(u,0)), Iter(0) ); + return std::make_pair( Iter(g.first_adj_edge(u,0),&g), Iter(0,&g) ); } template @@ -252,29 +438,29 @@ namespace boost { typename graph_traits< leda::GRAPH >::degree_size_type out_degree( typename graph_traits< leda::GRAPH >::vertex_descriptor u, - const leda::GRAPH&) + const leda::GRAPH& g) { - return outdeg(u); + return g.outdeg(u); } template typename graph_traits< leda::GRAPH >::degree_size_type in_degree( typename graph_traits< leda::GRAPH >::vertex_descriptor u, - const leda::GRAPH&) + const leda::GRAPH& g) { - return indeg(u); + return g.indeg(u); } template typename graph_traits< leda::GRAPH >::degree_size_type degree( typename graph_traits< leda::GRAPH >::vertex_descriptor u, - const leda::GRAPH&) + const leda::GRAPH& g) { - return outdeg(u) + indeg(u); + return g.outdeg(u) + g.indeg(u); } - + template typename graph_traits< leda::GRAPH >::vertex_descriptor add_vertex(leda::GRAPH& g) @@ -289,14 +475,18 @@ namespace boost { return g.new_node(vp); } - // Hmm, LEDA doesn't have the equivalent of clear_vertex() -JGS - // need to write an implementation template void clear_vertex( typename graph_traits< leda::GRAPH >::vertex_descriptor u, leda::GRAPH& g) { - g.del_node(u); + typename graph_traits< leda::GRAPH >::out_edge_iterator ei, ei_end; + for (tie(ei, ei_end)=out_edges(u,g); ei!=ei_end; ei++) + remove_edge(*ei); + + typename graph_traits< leda::GRAPH >::in_edge_iterator iei, iei_end; + for (tie(iei, iei_end)=in_edges(u,g); iei!=iei_end; iei++) + remove_edge(*iei); } template @@ -356,8 +546,174 @@ namespace boost { } //=========================================================================== - // property maps - + // functions for graph (non-templated version) + + graph_traits::vertex_descriptor + source(graph_traits::edge_descriptor e, + const leda::graph& g) + { + return source(e); + } + + graph_traits::vertex_descriptor + target(graph_traits::edge_descriptor e, + const leda::graph& g) + { + return target(e); + } + + inline std::pair< + graph_traits::vertex_iterator, + graph_traits::vertex_iterator > + vertices(const leda::graph& g) + { + typedef graph_traits::vertex_iterator + Iter; + return std::make_pair( Iter(g.first_node(),&g), Iter(0,&g) ); + } + + inline std::pair< + graph_traits::edge_iterator, + graph_traits::edge_iterator > + edges(const leda::graph& g) + { + typedef graph_traits::edge_iterator + Iter; + return std::make_pair( Iter(g.first_edge(),&g), Iter(0,&g) ); + } + + inline std::pair< + graph_traits::out_edge_iterator, + graph_traits::out_edge_iterator > + out_edges( + graph_traits::vertex_descriptor u, const leda::graph& g) + { + typedef graph_traits::out_edge_iterator Iter; + return std::make_pair( Iter(g.first_adj_edge(u),&g), Iter(0,&g) ); + } + + inline std::pair< + graph_traits::in_edge_iterator, + graph_traits::in_edge_iterator > + in_edges( + graph_traits::vertex_descriptor u, + const leda::graph& g) + { + typedef graph_traits + ::in_edge_iterator Iter; + return std::make_pair( Iter(g.first_in_edge(u),&g), Iter(0,&g) ); + } + + inline std::pair< + graph_traits::adjacency_iterator, + graph_traits::adjacency_iterator > + adjacent_vertices( + graph_traits::vertex_descriptor u, + const leda::graph& g) + { + typedef graph_traits + ::adjacency_iterator Iter; + return std::make_pair( Iter(g.first_adj_edge(u),&g), Iter(0,&g) ); + } + + graph_traits::vertices_size_type + num_vertices(const leda::graph& g) + { + return g.number_of_nodes(); + } + + graph_traits::edges_size_type + num_edges(const leda::graph& g) + { + return g.number_of_edges(); + } + + graph_traits::degree_size_type + out_degree( + graph_traits::vertex_descriptor u, + const leda::graph& g) + { + return g.outdeg(u); + } + + graph_traits::degree_size_type + in_degree( + graph_traits::vertex_descriptor u, + const leda::graph& g) + { + return g.indeg(u); + } + + graph_traits::degree_size_type + degree( + graph_traits::vertex_descriptor u, + const leda::graph& g) + { + return g.outdeg(u) + g.indeg(u); + } + + graph_traits::vertex_descriptor + add_vertex(leda::graph& g) + { + return g.new_node(); + } + + void + remove_edge( + graph_traits::vertex_descriptor u, + graph_traits::vertex_descriptor v, + leda::graph& g) + { + graph_traits::out_edge_iterator + i,iend; + for (boost::tie(i,iend) = out_edges(u,g); i != iend; ++i) + if (target(*i,g) == v) + g.del_edge(*i); + } + + void + remove_edge( + graph_traits::edge_descriptor e, + leda::graph& g) + { + g.del_edge(e); + } + + void clear_vertex( + graph_traits::vertex_descriptor u, + leda::graph& g) + { + graph_traits::out_edge_iterator ei, ei_end; + for (tie(ei, ei_end)=out_edges(u,g); ei!=ei_end; ei++) + remove_edge(*ei, g); + + graph_traits::in_edge_iterator iei, iei_end; + for (tie(iei, iei_end)=in_edges(u,g); iei!=iei_end; iei++) + remove_edge(*iei, g); + } + + void remove_vertex( + graph_traits::vertex_descriptor u, + leda::graph& g) + { + g.del_node(u); + } + + std::pair< + graph_traits::edge_descriptor, + bool> + add_edge( + graph_traits::vertex_descriptor u, + graph_traits::vertex_descriptor v, + leda::graph& g) + { + return std::make_pair(g.new_edge(u, v), true); + } + + + //=========================================================================== + // property maps for GRAPH + class leda_graph_id_map : public put_get_helper { @@ -365,7 +721,7 @@ namespace boost { typedef readable_property_map_tag category; typedef int value_type; typedef int reference; - typedef leda_node key_type; + typedef leda::node key_type; leda_graph_id_map() { } template long operator[](T x) const { return x->id(); } @@ -476,42 +832,42 @@ namespace boost { public: typedef E value_type; typedef ERef reference; - typedef leda_node key_type; + typedef leda::node key_type; typedef lvalue_property_map_tag category; leda_node_property_map(NodeMapPtr a) : m_array(a) { } - ERef operator[](leda_node n) const { return (*m_array)[n]; } + ERef operator[](leda::node n) const { return (*m_array)[n]; } protected: NodeMapPtr m_array; }; template - leda_node_property_map*> - make_leda_node_property_map(const leda_node_array& a) + leda_node_property_map*> + make_leda_node_property_map(const leda::node_array& a) { - typedef leda_node_property_map*> + typedef leda_node_property_map*> pmap_type; return pmap_type(&a); } template - leda_node_property_map*> - make_leda_node_property_map(leda_node_array& a) + leda_node_property_map*> + make_leda_node_property_map(leda::node_array& a) { - typedef leda_node_property_map*> pmap_type; + typedef leda_node_property_map*> pmap_type; return pmap_type(&a); } template - leda_node_property_map*> - make_leda_node_property_map(const leda_node_map& a) + leda_node_property_map*> + make_leda_node_property_map(const leda::node_map& a) { - typedef leda_node_property_map*> + typedef leda_node_property_map*> pmap_type; return pmap_type(&a); } template - leda_node_property_map*> - make_leda_node_property_map(leda_node_map& a) + leda_node_property_map*> + make_leda_node_property_map(leda::node_map& a) { - typedef leda_node_property_map*> pmap_type; + typedef leda_node_property_map*> pmap_type; return pmap_type(&a); } @@ -528,11 +884,11 @@ namespace boost { inline typename boost::property_traits< typename boost::property_map,PropertyTag>::const_type - >::value_type +::value_type get(PropertyTag p, const leda::GRAPH& g, const Key& key) { return get(get(p, g), key); } - + template inline void put(PropertyTag p, leda::GRAPH& g, @@ -543,7 +899,54 @@ namespace boost { put(pmap, key, value); } + // property map interface to the LEDA edge_array class + + template + class leda_edge_property_map + : public put_get_helper > + { + public: + typedef E value_type; + typedef ERef reference; + typedef leda::edge key_type; + typedef lvalue_property_map_tag category; + leda_edge_property_map(EdgeMapPtr a) : m_array(a) { } + ERef operator[](leda::edge n) const { return (*m_array)[n]; } + protected: + EdgeMapPtr m_array; + }; + template + leda_edge_property_map*> + make_leda_node_property_map(const leda::node_array& a) + { + typedef leda_edge_property_map*> + pmap_type; + return pmap_type(&a); + } + template + leda_edge_property_map*> + make_leda_edge_property_map(leda::edge_array& a) + { + typedef leda_edge_property_map*> pmap_type; + return pmap_type(&a); + } + + template + leda_edge_property_map*> + make_leda_edge_property_map(const leda::edge_map& a) + { + typedef leda_edge_property_map*> + pmap_type; + return pmap_type(&a); + } + template + leda_edge_property_map*> + make_leda_edge_property_map(leda::edge_map& a) + { + typedef leda_edge_property_map*> pmap_type; + return pmap_type(&a); + } + } // namespace boost - #endif // BOOST_GRAPH_LEDA_HPP diff --git a/include/boost/graph/make_biconnected_planar.hpp b/include/boost/graph/make_biconnected_planar.hpp new file mode 100644 index 00000000..b7daef5a --- /dev/null +++ b/include/boost/graph/make_biconnected_planar.hpp @@ -0,0 +1,121 @@ +//======================================================================= +// Copyright 2007 Aaron Windsor +// +// 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 __MAKE_BICONNECTED_PLANAR_HPP__ +#define __MAKE_BICONNECTED_PLANAR_HPP__ + +#include +#include //for tie +#include +#include +#include +#include +#include + +#include + + +namespace boost +{ + + + + template + void make_biconnected_planar(Graph& g, + PlanarEmbedding embedding, + EdgeIndexMap em, + AddEdgeVisitor& vis + ) + { + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::edge_descriptor edge_t; + typedef typename graph_traits::edges_size_type edge_size_t; + typedef typename + property_traits::value_type embedding_value_t; + typedef typename embedding_value_t::const_iterator embedding_iterator_t; + typedef iterator_property_map + ::iterator, EdgeIndexMap> component_map_t; + + edge_size_t n_edges(num_edges(g)); + std::vector articulation_points; + std::vector component_vector(n_edges); + component_map_t component_map(component_vector.begin(), em); + + biconnected_components(g, component_map, + std::back_inserter(articulation_points)); + + typename std::vector::iterator ap, ap_end; + ap_end = articulation_points.end(); + for(ap = articulation_points.begin(); ap != ap_end; ++ap) + { + vertex_t v(*ap); + embedding_iterator_t pi = embedding[v].begin(); + embedding_iterator_t pi_end = embedding[v].end(); + edge_size_t previous_component(n_edges + 1); + vertex_t previous_vertex = graph_traits::null_vertex(); + + for(; pi != pi_end; ++pi) + { + edge_t e(*pi); + vertex_t e_source(source(e,g)); + vertex_t e_target(target(e,g)); + + //Skip self-loops and parallel edges + if (e_source == e_target || previous_vertex == e_target) + continue; + + vertex_t current_vertex = e_source == v ? e_target : e_source; + edge_size_t current_component = component_map[e]; + if (previous_vertex != graph_traits::null_vertex() && + current_component != previous_component) + { + vis.visit_vertex_pair(current_vertex, previous_vertex, g); + } + previous_vertex = current_vertex; + previous_component = current_component; + } + } + + } + + + + + template + inline void make_biconnected_planar(Graph& g, + PlanarEmbedding embedding, + EdgeIndexMap em + ) + { + default_add_edge_visitor vis; + make_biconnected_planar(g, embedding, em, vis); + } + + + + + template + inline void make_biconnected_planar(Graph& g, PlanarEmbedding embedding) + { + make_biconnected_planar(g, embedding, get(edge_index,g)); + } + + +} // namespace boost + + + +#endif //__MAKE_BICONNECTED_PLANAR_HPP__ diff --git a/include/boost/graph/make_connected.hpp b/include/boost/graph/make_connected.hpp new file mode 100644 index 00000000..94e57295 --- /dev/null +++ b/include/boost/graph/make_connected.hpp @@ -0,0 +1,99 @@ +//======================================================================= +// Copyright 2007 Aaron Windsor +// +// 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 __MAKE_CONNECTED_HPP__ +#define __MAKE_CONNECTED_HPP__ + +#include +#include //for next +#include //for tie +#include +#include +#include + +#include +#include + + +namespace boost +{ + + + template + void make_connected(Graph& g, VertexIndexMap vm, AddEdgeVisitor& vis) + { + typedef typename graph_traits::vertex_iterator vertex_iterator_t; + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::vertices_size_type v_size_t; + typedef iterator_property_map< typename std::vector::iterator, + VertexIndexMap + > vertex_to_v_size_map_t; + + std::vector component_vector(num_vertices(g)); + vertex_to_v_size_map_t component(component_vector.begin(), vm); + std::vector vertices_by_component(num_vertices(g)); + + v_size_t num_components = connected_components(g, component); + + if (num_components < 2) + return; + + vertex_iterator_t vi, vi_end; + tie(vi,vi_end) = vertices(g); + std::copy(vi, vi_end, vertices_by_component.begin()); + + bucket_sort(vertices_by_component.begin(), + vertices_by_component.end(), + component, + num_components + ); + + typedef typename std::vector::iterator vec_of_vertices_itr_t; + + vec_of_vertices_itr_t ci_end = vertices_by_component.end(); + vec_of_vertices_itr_t ci_prev = vertices_by_component.begin(); + if (ci_prev == ci_end) + return; + + for(vec_of_vertices_itr_t ci = next(ci_prev); + ci != ci_end; ci_prev = ci, ++ci + ) + { + if (component[*ci_prev] != component[*ci]) + vis.visit_vertex_pair(*ci_prev, *ci, g); + } + + } + + + + + template + inline void make_connected(Graph& g, VertexIndexMap vm) + { + default_add_edge_visitor vis; + make_connected(g, vm, vis); + } + + + + + template + inline void make_connected(Graph& g) + { + make_connected(g, get(vertex_index,g)); + } + + + + +} // namespace boost + +#endif //__MAKE_CONNECTED_HPP__ diff --git a/include/boost/graph/make_maximal_planar.hpp b/include/boost/graph/make_maximal_planar.hpp new file mode 100644 index 00000000..458de0a7 --- /dev/null +++ b/include/boost/graph/make_maximal_planar.hpp @@ -0,0 +1,275 @@ +//======================================================================= +// Copyright 2007 Aaron Windsor +// +// 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 __MAKE_MAXIMAL_PLANAR_HPP__ +#define __MAKE_MAXIMAL_PLANAR_HPP__ + +#include +#include //for tie +#include +#include +#include +#include +#include + +#include +#include + + +namespace boost +{ + + + template + struct triangulation_visitor : public planar_face_traversal_visitor + { + + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::edge_descriptor edge_t; + typedef typename graph_traits::vertices_size_type v_size_t; + typedef typename graph_traits::degree_size_type degree_size_t; + typedef typename graph_traits::edge_iterator edge_iterator_t; + typedef typename graph_traits::vertex_iterator vertex_iterator_t; + typedef typename graph_traits::adjacency_iterator + adjacency_iterator_t; + typedef typename std::vector vertex_vector_t; + typedef typename std::vector v_size_vector_t; + typedef typename std::vector degree_size_vector_t; + typedef iterator_property_map + < typename v_size_vector_t::iterator, VertexIndexMap > + vertex_to_v_size_map_t; + typedef iterator_property_map + < typename degree_size_vector_t::iterator, VertexIndexMap > + vertex_to_degree_size_map_t; + typedef typename vertex_vector_t::iterator face_iterator; + + + triangulation_visitor(Graph& arg_g, + VertexIndexMap arg_vm, + AddEdgeVisitor arg_add_edge_visitor + ) : + g(arg_g), + vm(arg_vm), + add_edge_visitor(arg_add_edge_visitor), + timestamp(0), + marked_vector(num_vertices(g), timestamp), + degree_vector(num_vertices(g), 0), + marked(marked_vector.begin(), vm), + degree(degree_vector.begin(), vm) + { + vertex_iterator_t vi, vi_end; + for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + put(degree, *vi, out_degree(*vi, g)); + } + + template + void next_vertex(Vertex v) + { + // Self-loops will appear as consecutive vertices in the list of + // vertices on a face. We want to skip these. + if (!vertices_on_face.empty() && + (vertices_on_face.back() == v || vertices_on_face.front() == v) + ) + return; + + vertices_on_face.push_back(v); + } + + void end_face() + { + ++timestamp; + + if (vertices_on_face.size() <= 3) + { + // At most three vertices on this face - don't need to triangulate + vertices_on_face.clear(); + return; + } + + // Find vertex on face of minimum degree + degree_size_t min_degree = num_vertices(g); + typename vertex_vector_t::iterator min_degree_vertex_itr; + face_iterator fi_end = vertices_on_face.end(); + for(face_iterator fi = vertices_on_face.begin(); fi != fi_end; ++fi) + { + degree_size_t deg = get(degree,*fi); + if (deg < min_degree) + { + min_degree_vertex_itr = fi; + min_degree = deg; + } + } + + // To simplify some of the manipulations, we'll re-arrange + // vertices_on_face so that it still contains the same + // (counter-clockwise) order of the vertices on this face, but now the + // min_degree_vertex is the first element in vertices_on_face. + vertex_vector_t temp_vector; + std::copy(min_degree_vertex_itr, vertices_on_face.end(), + std::back_inserter(temp_vector)); + std::copy(vertices_on_face.begin(), min_degree_vertex_itr, + std::back_inserter(temp_vector)); + vertices_on_face.swap(temp_vector); + + // Mark all of the min degree vertex's neighbors + adjacency_iterator_t ai, ai_end; + for(tie(ai,ai_end) = adjacent_vertices(vertices_on_face.front(),g); + ai != ai_end; ++ai + ) + { + put(marked, *ai, timestamp); + } + + typename vertex_vector_t::iterator marked_neighbor + = vertices_on_face.end(); + + // The iterator manipulations on the next two lines are safe because + // vertices_on_face.size() > 3 (from the first test in this function) + fi_end = prior(vertices_on_face.end()); + for(face_iterator fi = next(next(vertices_on_face.begin())); + fi != fi_end; ++fi + ) + { + if (get(marked, *fi) == timestamp) + { + marked_neighbor = fi; + break; + } + } + + if (marked_neighbor == vertices_on_face.end()) + { + add_edge_range( + vertices_on_face[0], + next(next(vertices_on_face.begin())), + prior(vertices_on_face.end()) + ); + } + else + { + add_edge_range( + vertices_on_face[1], + next(marked_neighbor), + vertices_on_face.end() + ); + + add_edge_range( + *next(marked_neighbor), + next(next(vertices_on_face.begin())), + marked_neighbor + ); + } + + //reset for the next face + vertices_on_face.clear(); + + } + + private: + + + void add_edge_range(vertex_t anchor, + face_iterator fi, + face_iterator fi_end + ) + { + for (; fi != fi_end; ++fi) + { + vertex_t v(*fi); + add_edge_visitor.visit_vertex_pair(anchor, v, g); + put(degree, anchor, get(degree, anchor) + 1); + put(degree, v, get(degree, v) + 1); + } + } + + + Graph& g; + VertexIndexMap vm; + AddEdgeVisitor add_edge_visitor; + v_size_t timestamp; + vertex_vector_t vertices_on_face; + v_size_vector_t marked_vector; + degree_size_vector_t degree_vector; + vertex_to_v_size_map_t marked; + vertex_to_degree_size_map_t degree; + + }; + + + + + template + void make_maximal_planar(Graph& g, + PlanarEmbedding embedding, + VertexIndexMap vm, + EdgeIndexMap em, + AddEdgeVisitor& vis) + { + triangulation_visitor + visitor(g, vm, vis); + planar_face_traversal(g, embedding, visitor, em); + } + + + + + template + void make_maximal_planar(Graph& g, + PlanarEmbedding embedding, + VertexIndexMap vm, + EdgeIndexMap em + ) + { + default_add_edge_visitor vis; + make_maximal_planar(g, embedding, vm, em, vis); + } + + + + + template + void make_maximal_planar(Graph& g, + PlanarEmbedding embedding, + VertexIndexMap vm + ) + { + make_maximal_planar(g, embedding, vm, get(edge_index,g)); + } + + + + + template + void make_maximal_planar(Graph& g, + PlanarEmbedding embedding + ) + { + make_maximal_planar(g, embedding, get(vertex_index,g)); + } + + + + +} // namespace boost + + + +#endif //__MAKE_MAXIMAL_PLANAR_HPP__ diff --git a/include/boost/graph/max_cardinality_matching.hpp b/include/boost/graph/max_cardinality_matching.hpp index 48cb053b..34edc763 100755 --- a/include/boost/graph/max_cardinality_matching.hpp +++ b/include/boost/graph/max_cardinality_matching.hpp @@ -45,10 +45,10 @@ namespace boost for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) { - vertex_descriptor_t v = *vi; - if (get(mate,v) != graph_traits::null_vertex() + vertex_descriptor_t v = *vi; + if (get(mate,v) != graph_traits::null_vertex() && get(vm,v) < get(vm,get(mate,v))) - ++size_of_matching; + ++size_of_matching; } return size_of_matching; } @@ -76,10 +76,10 @@ namespace boost vertex_iterator_t vi, vi_end; for( tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) { - vertex_descriptor_t v = *vi; - if (get(mate,v) != graph_traits::null_vertex() + vertex_descriptor_t v = *vi; + if (get(mate,v) != graph_traits::null_vertex() && v != get(mate,get(mate,v))) - return false; + return false; } return true; } @@ -188,7 +188,7 @@ namespace boost { vertex_iterator_t vi, vi_end; for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) - mate[*vi] = get(arg_mate, *vi); + mate[*vi] = get(arg_mate, *vi); } @@ -206,25 +206,25 @@ namespace boost vertex_iterator_t vi, vi_end; for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) - { - vertex_descriptor_t u = *vi; + { + vertex_descriptor_t u = *vi; - origin[u] = u; - pred[u] = u; - ancestor_of_v[u] = 0; - ancestor_of_w[u] = 0; - ds.make_set(u); + origin[u] = u; + pred[u] = u; + ancestor_of_v[u] = 0; + ancestor_of_w[u] = 0; + ds.make_set(u); - if (mate[u] == graph_traits::null_vertex()) + if (mate[u] == graph_traits::null_vertex()) { vertex_state[u] = graph::detail::V_EVEN; out_edge_iterator_t ei, ei_end; for(tie(ei,ei_end) = out_edges(u,g); ei != ei_end; ++ei) - even_edges.push_back( *ei ); + even_edges.push_back( *ei ); } - else - vertex_state[u] = graph::detail::V_UNREACHED; - } + else + vertex_state[u] = graph::detail::V_UNREACHED; + } //end initializations @@ -234,40 +234,41 @@ namespace boost bool found_alternating_path = false; while(!even_edges.empty() && !found_alternating_path) - { - // since we push even edges onto the back of the list as - // they're discovered, taking them off the back will search - // for augmenting paths depth-first. - edge_descriptor_t current_edge = even_edges.back(); - even_edges.pop_back(); + { + // since we push even edges onto the back of the list as + // they're discovered, taking them off the back will search + // for augmenting paths depth-first. + edge_descriptor_t current_edge = even_edges.back(); + even_edges.pop_back(); - v = source(current_edge,g); - w = target(current_edge,g); + v = source(current_edge,g); + w = target(current_edge,g); - vertex_descriptor_t v_prime = origin[ds.find_set(v)]; - vertex_descriptor_t w_prime = origin[ds.find_set(w)]; + vertex_descriptor_t v_prime = origin[ds.find_set(v)]; + vertex_descriptor_t w_prime = origin[ds.find_set(w)]; - // because of the way we put all of the edges on the queue, - // v_prime should be labeled V_EVEN; the following is a - // little paranoid but it could happen... - if (vertex_state[v_prime] != graph::detail::V_EVEN) + // because of the way we put all of the edges on the queue, + // v_prime should be labeled V_EVEN; the following is a + // little paranoid but it could happen... + if (vertex_state[v_prime] != graph::detail::V_EVEN) { std::swap(v_prime,w_prime); std::swap(v,w); } - if (vertex_state[w_prime] == graph::detail::V_UNREACHED) + if (vertex_state[w_prime] == graph::detail::V_UNREACHED) { vertex_state[w_prime] = graph::detail::V_ODD; vertex_state[mate[w_prime]] = graph::detail::V_EVEN; out_edge_iterator_t ei, ei_end; for( tie(ei,ei_end) = out_edges(mate[w_prime], g); ei != ei_end; ++ei) - even_edges.push_back(*ei); + even_edges.push_back(*ei); pred[w_prime] = v; } - //w_prime == v_prime can happen below if we get an edge that has been - //shrunk into a blossom - else if (vertex_state[w_prime] == graph::detail::V_EVEN && w_prime != v_prime) + + //w_prime == v_prime can happen below if we get an edge that has been + //shrunk into a blossom + else if (vertex_state[w_prime] == graph::detail::V_EVEN && w_prime != v_prime) { vertex_descriptor_t w_up = w_prime; vertex_descriptor_t v_up = v_prime; @@ -291,42 +292,42 @@ namespace boost w_free_ancestor == graph_traits::null_vertex() ) ) - { - ancestor_of_w[w_up] = timestamp; - ancestor_of_v[v_up] = timestamp; + { + ancestor_of_w[w_up] = timestamp; + ancestor_of_v[v_up] = timestamp; - if (w_free_ancestor == graph_traits::null_vertex()) - w_up = parent(w_up); - if (v_free_ancestor == graph_traits::null_vertex()) - v_up = parent(v_up); + if (w_free_ancestor == graph_traits::null_vertex()) + w_up = parent(w_up); + if (v_free_ancestor == graph_traits::null_vertex()) + v_up = parent(v_up); - if (mate[v_up] == graph_traits::null_vertex()) - v_free_ancestor = v_up; - if (mate[w_up] == graph_traits::null_vertex()) - w_free_ancestor = w_up; + if (mate[v_up] == graph_traits::null_vertex()) + v_free_ancestor = v_up; + if (mate[w_up] == graph_traits::null_vertex()) + w_free_ancestor = w_up; - if (ancestor_of_w[v_up] == timestamp) + if (ancestor_of_w[v_up] == timestamp) + nearest_common_ancestor = v_up; + else if (ancestor_of_v[w_up] == timestamp) + nearest_common_ancestor = w_up; + else if (v_free_ancestor == w_free_ancestor && + v_free_ancestor != graph_traits::null_vertex()) nearest_common_ancestor = v_up; - else if (ancestor_of_v[w_up] == timestamp) - nearest_common_ancestor = w_up; - else if (v_free_ancestor == w_free_ancestor && - v_free_ancestor != graph_traits::null_vertex()) - nearest_common_ancestor = v_up; - } + } if (nearest_common_ancestor == graph_traits::null_vertex()) - found_alternating_path = true; //to break out of the loop + found_alternating_path = true; //to break out of the loop else - { - //shrink the blossom - link_and_set_bridges(w_prime, nearest_common_ancestor, std::make_pair(w,v)); - link_and_set_bridges(v_prime, nearest_common_ancestor, std::make_pair(v,w)); - } + { + //shrink the blossom + link_and_set_bridges(w_prime, nearest_common_ancestor, std::make_pair(w,v)); + link_and_set_bridges(v_prime, nearest_common_ancestor, std::make_pair(v,w)); + } } - } + } if (!found_alternating_path) - return false; + return false; // retrieve the augmenting path and put it in aug_path reversed_retrieve_augmenting_path(v, v_free_ancestor); @@ -335,14 +336,14 @@ namespace boost // augment the matching along aug_path vertex_descriptor_t a,b; while (!aug_path.empty()) - { - a = aug_path.front(); - aug_path.pop_front(); - b = aug_path.front(); - aug_path.pop_front(); - mate[a] = b; - mate[b] = a; - } + { + a = aug_path.front(); + aug_path.pop_front(); + b = aug_path.front(); + aug_path.pop_front(); + mate[a] = b; + mate[b] = a; + } return true; @@ -356,7 +357,7 @@ namespace boost { vertex_iterator_t vi,vi_end; for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) - put(pm, *vi, mate[*vi]); + put(pm, *vi, mate[*vi]); } @@ -367,7 +368,7 @@ namespace boost { vertex_iterator_t vi,vi_end; for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) - put(pm, *vi, vertex_state[origin[ds.find_set(*vi)]]); + put(pm, *vi, vertex_state[origin[ds.find_set(*vi)]]); } @@ -379,11 +380,11 @@ namespace boost { if (vertex_state[x] == graph::detail::V_EVEN && mate[x] != graph_traits::null_vertex()) - return mate[x]; + return mate[x]; else if (vertex_state[x] == graph::detail::V_ODD) - return origin[ds.find_set(pred[x])]; + return origin[ds.find_set(pred[x])]; else - return x; + return x; } @@ -394,18 +395,18 @@ namespace boost vertex_pair_t the_bridge) { for(vertex_descriptor_t v = x; v != stop_vertex; v = parent(v)) - { - ds.union_set(v, stop_vertex); - origin[ds.find_set(stop_vertex)] = stop_vertex; + { + ds.union_set(v, stop_vertex); + origin[ds.find_set(stop_vertex)] = stop_vertex; - if (vertex_state[v] == graph::detail::V_ODD) + if (vertex_state[v] == graph::detail::V_ODD) { bridge[v] = the_bridge; out_edge_iterator_t oei, oei_end; for(tie(oei, oei_end) = out_edges(v,g); oei != oei_end; ++oei) - even_edges.push_back(*oei); + even_edges.push_back(*oei); } - } + } } @@ -426,19 +427,19 @@ namespace boost void retrieve_augmenting_path(vertex_descriptor_t v, vertex_descriptor_t w) { if (v == w) - aug_path.push_back(v); + aug_path.push_back(v); else if (vertex_state[v] == graph::detail::V_EVEN) - { - aug_path.push_back(v); - aug_path.push_back(mate[v]); - retrieve_augmenting_path(pred[mate[v]], w); - } + { + aug_path.push_back(v); + aug_path.push_back(mate[v]); + retrieve_augmenting_path(pred[mate[v]], w); + } else //vertex_state[v] == graph::detail::V_ODD - { - aug_path.push_back(v); - reversed_retrieve_augmenting_path(bridge[v].first, mate[v]); - retrieve_augmenting_path(bridge[v].second, w); - } + { + aug_path.push_back(v); + reversed_retrieve_augmenting_path(bridge[v].first, mate[v]); + retrieve_augmenting_path(bridge[v].second, w); + } } @@ -447,19 +448,19 @@ namespace boost { if (v == w) - aug_path.push_back(v); + aug_path.push_back(v); else if (vertex_state[v] == graph::detail::V_EVEN) - { - reversed_retrieve_augmenting_path(pred[mate[v]], w); - aug_path.push_back(mate[v]); - aug_path.push_back(v); - } + { + reversed_retrieve_augmenting_path(pred[mate[v]], w); + aug_path.push_back(mate[v]); + aug_path.push_back(v); + } else //vertex_state[v] == graph::detail::V_ODD - { - reversed_retrieve_augmenting_path(bridge[v].second, w); - retrieve_augmenting_path(bridge[v].first, mate[v]); - aug_path.push_back(v); - } + { + reversed_retrieve_augmenting_path(bridge[v].second, w); + retrieve_augmenting_path(bridge[v].first, mate[v]); + aug_path.push_back(v); + } } @@ -520,23 +521,23 @@ namespace boost { vertex_iterator_t vi, vi_end; for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) - put(mate, *vi, graph_traits::null_vertex()); + put(mate, *vi, graph_traits::null_vertex()); edge_iterator_t ei, ei_end; for( tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) - { - edge_descriptor_t e = *ei; - vertex_descriptor_t u = source(e,g); - vertex_descriptor_t v = target(e,g); + { + edge_descriptor_t e = *ei; + vertex_descriptor_t u = source(e,g); + vertex_descriptor_t v = target(e,g); - if (get(mate,u) == get(mate,v)) + if (get(mate,u) == get(mate,v)) //only way equality can hold is if - // mate[u] == mate[v] == null_vertex + // mate[u] == mate[v] == null_vertex { put(mate,u,v); put(mate,v,u); } - } + } } }; @@ -581,9 +582,9 @@ namespace boost less_than_by_degree(const Graph& g): m_g(g) {} bool operator() (const vertex_pair_t x, const vertex_pair_t y) { - return - out_degree(PairSelector::select_vertex(x), m_g) - < out_degree(PairSelector::select_vertex(y), m_g); + return + out_degree(PairSelector::select_vertex(x), m_g) + < out_degree(PairSelector::select_vertex(y), m_g); } private: const Graph& m_g; @@ -598,17 +599,17 @@ namespace boost directed_edges_vector_t edge_list; vertex_iterator_t vi, vi_end; for(tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) - put(mate, *vi, graph_traits::null_vertex()); + put(mate, *vi, graph_traits::null_vertex()); edge_iterator_t ei, ei_end; for(tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) - { - edge_descriptor_t e = *ei; - vertex_descriptor_t u = source(e,g); - vertex_descriptor_t v = target(e,g); - edge_list.push_back(std::make_pair(u,v)); - edge_list.push_back(std::make_pair(v,u)); - } + { + edge_descriptor_t e = *ei; + vertex_descriptor_t u = source(e,g); + vertex_descriptor_t v = target(e,g); + edge_list.push_back(std::make_pair(u,v)); + edge_list.push_back(std::make_pair(v,u)); + } //sort the edges by the degree of the target, then (using a //stable sort) by degree of the source @@ -619,14 +620,14 @@ namespace boost //construct the extra greedy matching for(typename directed_edges_vector_t::const_iterator itr = edge_list.begin(); itr != edge_list.end(); ++itr) - { - if (get(mate,itr->first) == get(mate,itr->second)) + { + if (get(mate,itr->first) == get(mate,itr->second)) //only way equality can hold is if mate[itr->first] == mate[itr->second] == null_vertex { put(mate, itr->first, itr->second); put(mate, itr->second, itr->first); } - } + } } }; @@ -642,7 +643,7 @@ namespace boost { vertex_iterator_t vi, vi_end; for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) - put(mate, *vi, graph_traits::null_vertex()); + put(mate, *vi, graph_traits::null_vertex()); } }; @@ -666,29 +667,29 @@ namespace boost { public: odd_components_counter(SizeType& c_count): - m_count(c_count) + m_count(c_count) { - m_count = 0; + m_count = 0; } template void start_vertex(Vertex v, Graph&) - { - addend = -1; + { + m_parity = false; } template void discover_vertex(Vertex u, Graph&) { - addend *= -1; - m_count += addend; + m_parity = !m_parity; + m_parity ? ++m_count : --m_count; } protected: SizeType& m_count; private: - SizeType addend; + bool m_parity; }; @@ -728,21 +729,27 @@ namespace boost typedef typename map_vertex_to_::type vertex_to_vertex_map_t; + template struct non_odd_vertex { //this predicate is used to create a filtered graph that //excludes vertices labeled "graph::detail::V_ODD" non_odd_vertex() : vertex_state(0) { } - non_odd_vertex(VertexStateMap* arg_vertex_state) + + non_odd_vertex(VertexStateMap* arg_vertex_state) : vertex_state(arg_vertex_state) { } - template - bool operator()(const Vertex& v) const { - BOOST_ASSERT(vertex_state); - return get(*vertex_state, v) != graph::detail::V_ODD; + + template + bool operator()(const Vertex& v) const + { + BOOST_ASSERT(vertex_state); + return get(*vertex_state, v) != graph::detail::V_ODD; } + VertexStateMap* vertex_state; }; + static bool verify_matching(const Graph& g, MateMap mate, VertexIndexMap vm) { //For any graph G, let o(G) be the number of connected @@ -763,7 +770,7 @@ namespace boost //first, make sure it's a valid matching if (!is_a_matching(g,mate,vm)) - return false; + return false; //We'll try to augment the matching once. This serves two //purposes: first, if we find some augmenting path, the matching @@ -775,7 +782,7 @@ namespace boost edmonds_augmenting_path_finder augmentor(g,mate,vm); if (augmentor.augment_matching()) - return false; + return false; std::vector vertex_state_vector(num_vertices(g)); vertex_to_int_map_t vertex_state(vertex_state_vector.begin(), vm); @@ -785,8 +792,8 @@ namespace boost v_size_t num_odd_vertices = 0; vertex_iterator_t vi, vi_end; for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) - if (vertex_state[*vi] == graph::detail::V_ODD) - ++num_odd_vertices; + if (vertex_state[*vi] == graph::detail::V_ODD) + ++num_odd_vertices; //count the number of connected components with odd cardinality //in the graph without graph::detail::V_ODD vertices @@ -798,9 +805,9 @@ namespace boost depth_first_search(fg, visitor(occ).vertex_index_map(vm)); if (2 * matching_size(g,mate,vm) == num_vertices(g) + num_odd_vertices - num_odd_components) - return true; + return true; else - return false; + return false; } }; @@ -822,7 +829,7 @@ namespace boost bool not_maximum_yet = true; while(not_maximum_yet) { - not_maximum_yet = augmentor.augment_matching(); + not_maximum_yet = augmentor.augment_matching(); } augmentor.get_current_matching(mate); diff --git a/include/boost/graph/named_function_params.hpp b/include/boost/graph/named_function_params.hpp index e1658460..db77ae3b 100644 --- a/include/boost/graph/named_function_params.hpp +++ b/include/boost/graph/named_function_params.hpp @@ -284,6 +284,27 @@ namespace boost { return Params(c, *this); } + template + bgl_named_params + vertex_invariant1(const VertexInvar& c) const { + typedef bgl_named_params Params; + return Params(c, *this); + } + + template + bgl_named_params + vertex_invariant2(const VertexInvar& c) const { + typedef bgl_named_params Params; + return Params(c, *this); + } + + template + bgl_named_params + vertex_max_invariant(const VertexMaxInvar& c) const { + typedef bgl_named_params Params; + return Params(c, *this); + } + template bgl_named_params displacement_map(const VertexDisplacement& c) const { @@ -547,6 +568,27 @@ namespace boost { return Params(c); } + template + bgl_named_params + vertex_invariant1(const VertexInvar& c) { + typedef bgl_named_params Params; + return Params(c); + } + + template + bgl_named_params + vertex_invariant2(const VertexInvar& c) { + typedef bgl_named_params Params; + return Params(c); + } + + template + bgl_named_params + vertex_max_invariant(const VertexMaxInvar& c) { + typedef bgl_named_params Params; + return Params(c); + } + template bgl_named_params displacement_map(const VertexDisplacement& c) { diff --git a/include/boost/graph/planar_canonical_ordering.hpp b/include/boost/graph/planar_canonical_ordering.hpp new file mode 100644 index 00000000..6f8e2579 --- /dev/null +++ b/include/boost/graph/planar_canonical_ordering.hpp @@ -0,0 +1,211 @@ +//======================================================================= +// 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 __PLANAR_CANONICAL_ORDERING_HPP__ +#define __PLANAR_CANONICAL_ORDERING_HPP__ + +#include +#include +#include +#include //for next and prior +#include +#include + + +namespace boost +{ + + + template + void planar_canonical_ordering(const Graph& g, + PlanarEmbedding embedding, + OutputIterator ordering, + VertexIndexMap vm) + { + + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::edge_descriptor edge_t; + typedef typename graph_traits::vertex_iterator vertex_iterator_t; + typedef typename graph_traits::adjacency_iterator + adjacency_iterator_t; + typedef typename std::pair vertex_pair_t; + typedef typename property_traits::value_type + embedding_value_t; + typedef typename embedding_value_t::const_iterator embedding_iterator_t; + typedef iterator_property_map + ::iterator, VertexIndexMap> + vertex_to_vertex_map_t; + typedef iterator_property_map + ::iterator, VertexIndexMap> + vertex_to_size_t_map_t; + + enum {PROCESSED, + UNPROCESSED, + ONE_NEIGHBOR_PROCESSED, + READY_TO_BE_PROCESSED}; + + std::vector processed_neighbor_vector(num_vertices(g)); + vertex_to_vertex_map_t processed_neighbor + (processed_neighbor_vector.begin(), vm); + + std::vector status_vector(num_vertices(g), UNPROCESSED); + vertex_to_size_t_map_t status(status_vector.begin(), vm); + + std::list ready_to_be_processed; + + vertex_t first_vertex = *vertices(g).first; + vertex_t second_vertex; + adjacency_iterator_t ai, ai_end; + for(tie(ai,ai_end) = adjacent_vertices(first_vertex,g); ai != ai_end; ++ai) + { + if (*ai == first_vertex) + continue; + second_vertex = *ai; + break; + } + + ready_to_be_processed.push_back(first_vertex); + status[first_vertex] = READY_TO_BE_PROCESSED; + ready_to_be_processed.push_back(second_vertex); + status[second_vertex] = READY_TO_BE_PROCESSED; + + while(!ready_to_be_processed.empty()) + { + vertex_t u = ready_to_be_processed.front(); + ready_to_be_processed.pop_front(); + + if (status[u] != READY_TO_BE_PROCESSED && u != second_vertex) + continue; + + embedding_iterator_t ei, ei_start, ei_end; + embedding_iterator_t next_edge_itr, prior_edge_itr; + + ei_start = embedding[u].begin(); + ei_end = embedding[u].end(); + prior_edge_itr = prior(ei_end); + while(source(*prior_edge_itr, g) == target(*prior_edge_itr,g)) + prior_edge_itr = prior(prior_edge_itr); + + for(ei = ei_start; ei != ei_end; ++ei) + { + + edge_t e(*ei); // e = (u,v) + next_edge_itr = next(ei) == ei_end ? ei_start : next(ei); + vertex_t v = source(e,g) == u ? target(e,g) : source(e,g); + + vertex_t prior_vertex = source(*prior_edge_itr, g) == u ? + target(*prior_edge_itr, g) : source(*prior_edge_itr, g); + vertex_t next_vertex = source(*next_edge_itr, g) == u ? + target(*next_edge_itr, g) : source(*next_edge_itr, g); + + // Need prior_vertex, u, v, and next_vertex to all be + // distinct. This is possible, since the input graph is + // triangulated. It'll be true all the time in a simple + // graph, but loops and parallel edges cause some complications. + if (prior_vertex == v || prior_vertex == u) + { + prior_edge_itr = ei; + continue; + } + + //Skip any self-loops + if (u == v) + continue; + + // Move next_edge_itr (and next_vertex) forwards + // past any loops or parallel edges + while (next_vertex == v || next_vertex == u) + { + next_edge_itr = next(next_edge_itr) == ei_end ? + ei_start : next(next_edge_itr); + next_vertex = source(*next_edge_itr, g) == u ? + target(*next_edge_itr, g) : source(*next_edge_itr, g); + } + + + if (status[v] == UNPROCESSED) + { + status[v] = ONE_NEIGHBOR_PROCESSED; + processed_neighbor[v] = u; + } + else if (status[v] == ONE_NEIGHBOR_PROCESSED) + { + vertex_t x = processed_neighbor[v]; + //are edges (v,u) and (v,x) adjacent in the planar + //embedding? if so, set status[v] = 1. otherwise, set + //status[v] = 2. + + if ((next_vertex == x && + !(first_vertex == u && second_vertex == x) + ) + || + (prior_vertex == x && + !(first_vertex == x && second_vertex == u) + ) + ) + { + status[v] = READY_TO_BE_PROCESSED; + } + else + { + status[v] = READY_TO_BE_PROCESSED + 1; + } + } + else if (status[v] > ONE_NEIGHBOR_PROCESSED) + { + //check the two edges before and after (v,u) in the planar + //embedding, and update status[v] accordingly + + bool processed_before = false; + if (status[prior_vertex] == PROCESSED) + processed_before = true; + + bool processed_after = false; + if (status[next_vertex] == PROCESSED) + processed_after = true; + + if (!processed_before && !processed_after) + ++status[v]; + + else if (processed_before && processed_after) + --status[v]; + + } + + if (status[v] == READY_TO_BE_PROCESSED) + ready_to_be_processed.push_back(v); + + prior_edge_itr = ei; + + } + + status[u] = PROCESSED; + *ordering = u; + ++ordering; + + } + + } + + + template + void planar_canonical_ordering(const Graph& g, + PlanarEmbedding embedding, + OutputIterator ordering + ) + { + planar_canonical_ordering(g, embedding, ordering, get(vertex_index,g)); + } + + +} //namespace boost + +#endif //__PLANAR_CANONICAL_ORDERING_HPP__ diff --git a/include/boost/graph/planar_detail/add_edge_visitors.hpp b/include/boost/graph/planar_detail/add_edge_visitors.hpp new file mode 100644 index 00000000..3ad65b82 --- /dev/null +++ b/include/boost/graph/planar_detail/add_edge_visitors.hpp @@ -0,0 +1,59 @@ +//======================================================================= +// Copyright 2007 Aaron Windsor +// +// 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 __ADD_EDGE_VISITORS_HPP__ +#define __ADD_EDGE_VISITORS_HPP__ + +#include + +namespace boost +{ + + struct default_add_edge_visitor + { + + template + void visit_vertex_pair(Vertex u, Vertex v, Graph& g) + { + add_edge(u,v,g); + } + + }; + + template + struct edge_index_update_visitor + { + + typedef typename + property_traits::value_type edge_index_value_t; + + edge_index_update_visitor(EdgeIndexMap em, + edge_index_value_t next_index_available + ) : + m_em(em), + m_next_index(next_index_available) + {} + + template + void visit_vertex_pair(Vertex u, Vertex v, Graph& g) + { + typedef typename graph_traits::edge_descriptor edge_t; + std::pair return_value = add_edge(u,v,g); + if (return_value.second) + put( m_em, return_value.first, m_next_index++); + } + + private: + + EdgeIndexMap m_em; + edge_index_value_t m_next_index; + + }; + +} // namespace boost + +#endif //__ADD_EDGE_VISITORS_HPP__ diff --git a/include/boost/graph/planar_detail/boyer_myrvold_impl.hpp b/include/boost/graph/planar_detail/boyer_myrvold_impl.hpp new file mode 100644 index 00000000..d0955221 --- /dev/null +++ b/include/boost/graph/planar_detail/boyer_myrvold_impl.hpp @@ -0,0 +1,2010 @@ +//======================================================================= +// 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 __BOYER_MYRVOLD_IMPL_HPP__ +#define __BOYER_MYRVOLD_IMPL_HPP__ + +#include +#include +#include //for boost::next +#include //for std::min macros +#include +#include +#include +#include +#include +#include +#include +#include + + + +namespace boost +{ + + template + struct planar_dfs_visitor : public dfs_visitor<> + { + planar_dfs_visitor(LowPointMap lpm, DFSParentMap dfs_p, + DFSNumberMap dfs_n, LeastAncestorMap lam, + DFSParentEdgeMap dfs_edge) + : low(lpm), + parent(dfs_p), + df_number(dfs_n), + least_ancestor(lam), + df_edge(dfs_edge), + count(0) + {} + + + template + void start_vertex(const Vertex& u, Graph&) + { + put(parent, u, u); + put(least_ancestor, u, count); + } + + + template + void discover_vertex(const Vertex& u, Graph&) + { + put(low, u, count); + put(df_number, u, count); + ++count; + } + + template + void tree_edge(const Edge& e, Graph& g) + { + typedef typename graph_traits::vertex_descriptor vertex_t; + vertex_t s(source(e,g)); + vertex_t t(target(e,g)); + + put(parent, t, s); + put(df_edge, t, e); + put(least_ancestor, t, get(df_number, s)); + } + + template + void back_edge(const Edge& e, Graph& g) + { + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::vertices_size_type v_size_t; + + vertex_t s(source(e,g)); + vertex_t t(target(e,g)); + BOOST_USING_STD_MIN(); + + if ( t != get(parent, s) ) { + v_size_t s_low_df_number = get(low, s); + v_size_t t_df_number = get(df_number, t); + v_size_t s_least_ancestor_df_number = get(least_ancestor, s); + + put(low, s, + min BOOST_PREVENT_MACRO_SUBSTITUTION(s_low_df_number, + t_df_number) + ); + + put(least_ancestor, s, + min BOOST_PREVENT_MACRO_SUBSTITUTION(s_least_ancestor_df_number, + t_df_number + ) + ); + + } + } + + template + void finish_vertex(const Vertex& u, Graph& g) + { + typedef typename graph_traits::vertices_size_type v_size_t; + + Vertex u_parent = get(parent, u); + v_size_t u_parent_lowpoint = get(low, u_parent); + v_size_t u_lowpoint = get(low, u); + BOOST_USING_STD_MIN(); + + if (u_parent != u) + { + put(low, u_parent, + min BOOST_PREVENT_MACRO_SUBSTITUTION(u_lowpoint, + u_parent_lowpoint + ) + ); + } + } + + LowPointMap low; + DFSParentMap parent; + DFSNumberMap df_number; + LeastAncestorMap least_ancestor; + DFSParentEdgeMap df_edge; + SizeType count; + + }; + + + + + + + template + class boyer_myrvold_impl + { + + typedef typename graph_traits::vertices_size_type v_size_t; + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::edge_descriptor edge_t; + typedef typename graph_traits::vertex_iterator vertex_iterator_t; + typedef typename graph_traits::edge_iterator edge_iterator_t; + typedef typename graph_traits::out_edge_iterator + out_edge_iterator_t; + typedef graph::detail::face_handle + face_handle_t; + typedef std::vector vertex_vector_t; + typedef std::vector edge_vector_t; + typedef std::list vertex_list_t; + typedef std::list< face_handle_t > face_handle_list_t; + typedef boost::shared_ptr< face_handle_list_t > face_handle_list_ptr_t; + typedef boost::shared_ptr< vertex_list_t > vertex_list_ptr_t; + typedef boost::tuple merge_stack_frame_t; + typedef std::vector merge_stack_t; + + template + struct map_vertex_to_ + { + typedef iterator_property_map + ::iterator, VertexIndexMap> type; + }; + + typedef typename map_vertex_to_::type vertex_to_v_size_map_t; + typedef typename map_vertex_to_::type vertex_to_vertex_map_t; + typedef typename map_vertex_to_::type vertex_to_edge_map_t; + typedef typename map_vertex_to_::type + vertex_to_vertex_list_ptr_map_t; + typedef typename map_vertex_to_< edge_vector_t >::type + vertex_to_edge_vector_map_t; + typedef typename map_vertex_to_::type vertex_to_bool_map_t; + typedef typename map_vertex_to_::type + vertex_to_face_handle_map_t; + typedef typename map_vertex_to_::type + vertex_to_face_handle_list_ptr_map_t; + typedef typename map_vertex_to_::type + vertex_to_separated_node_map_t; + + template + struct face_vertex_iterator + { + typedef face_iterator + type; + }; + + template + struct face_edge_iterator + { + typedef face_iterator + type; + }; + + + + public: + + + + boyer_myrvold_impl(const Graph& arg_g, VertexIndexMap arg_vm): + g(arg_g), + vm(arg_vm), + + low_point_vector(num_vertices(g)), + dfs_parent_vector(num_vertices(g)), + dfs_number_vector(num_vertices(g)), + least_ancestor_vector(num_vertices(g)), + pertinent_roots_vector(num_vertices(g)), + backedge_flag_vector(num_vertices(g), num_vertices(g) + 1), + visited_vector(num_vertices(g), num_vertices(g) + 1), + face_handles_vector(num_vertices(g)), + dfs_child_handles_vector(num_vertices(g)), + separated_dfs_child_list_vector(num_vertices(g)), + separated_node_in_parent_list_vector(num_vertices(g)), + canonical_dfs_child_vector(num_vertices(g)), + flipped_vector(num_vertices(g), false), + backedges_vector(num_vertices(g)), + dfs_parent_edge_vector(num_vertices(g)), + + vertices_by_dfs_num(num_vertices(g)), + + low_point(low_point_vector.begin(), vm), + dfs_parent(dfs_parent_vector.begin(), vm), + dfs_number(dfs_number_vector.begin(), vm), + least_ancestor(least_ancestor_vector.begin(), vm), + pertinent_roots(pertinent_roots_vector.begin(), vm), + backedge_flag(backedge_flag_vector.begin(), vm), + visited(visited_vector.begin(), vm), + face_handles(face_handles_vector.begin(), vm), + dfs_child_handles(dfs_child_handles_vector.begin(), vm), + separated_dfs_child_list(separated_dfs_child_list_vector.begin(), vm), + separated_node_in_parent_list + (separated_node_in_parent_list_vector.begin(), vm), + canonical_dfs_child(canonical_dfs_child_vector.begin(), vm), + flipped(flipped_vector.begin(), vm), + backedges(backedges_vector.begin(), vm), + dfs_parent_edge(dfs_parent_edge_vector.begin(), vm) + + { + + planar_dfs_visitor + vis + (low_point, dfs_parent, dfs_number, least_ancestor, dfs_parent_edge); + + // Perform a depth-first search to find each vertex's low point, least + // ancestor, and dfs tree information + depth_first_search(g, visitor(vis).vertex_index_map(vm)); + + // Sort vertices by their lowpoint - need this later in the constructor + vertex_vector_t vertices_by_lowpoint(num_vertices(g)); + std::copy( vertices(g).first, vertices(g).second, + vertices_by_lowpoint.begin() + ); + bucket_sort(vertices_by_lowpoint.begin(), + vertices_by_lowpoint.end(), + low_point, + num_vertices(g) + ); + + // Sort vertices by their dfs number - need this to iterate by reverse + // DFS number in the main loop. + std::copy( vertices(g).first, vertices(g).second, + vertices_by_dfs_num.begin() + ); + bucket_sort(vertices_by_dfs_num.begin(), + vertices_by_dfs_num.end(), + dfs_number, + num_vertices(g) + ); + + // Initialize face handles. A face handle is an abstraction that serves + // two uses in our implementation - it allows us to efficiently move + // along the outer face of embedded bicomps in a partially embedded + // graph, and it provides storage for the planar embedding. Face + // handles are implemented by a sequence of edges and are associated + // with a particular vertex - the sequence of edges represents the + // current embedding of edges around that vertex, and the first and + // last edges in the sequence represent the pair of edges on the outer + // face that are adjacent to the associated vertex. This lets us embed + // edges in the graph by just pushing them on the front or back of the + // sequence of edges held by the face handles. + // + // Our algorithm starts with a DFS tree of edges (where every vertex is + // an articulation point and every edge is a singleton bicomp) and + // repeatedly merges bicomps by embedding additional edges. Note that + // any bicomp at any point in the algorithm can be associated with a + // unique edge connecting the vertex of that bicomp with the lowest DFS + // number (which we refer to as the "root" of the bicomp) with its DFS + // child in the bicomp: the existence of two such edges would contradict + // the properties of a DFS tree. We refer to the DFS child of the root + // of a bicomp as the "canonical DFS child" of the bicomp. Note that a + // vertex can be the root of more than one bicomp. + // + // We move around the external faces of a bicomp using a few property + // maps, which we'll initialize presently: + // + // - face_handles: maps a vertex to a face handle that can be used to + // move "up" a bicomp. For a vertex that isn't an articulation point, + // this holds the face handles that can be used to move around that + // vertex's unique bicomp. For a vertex that is an articulation point, + // this holds the face handles associated with the unique bicomp that + // the vertex is NOT the root of. These handles can therefore be used + // to move from any point on the outer face of the tree of bicomps + // around the current outer face towards the root of the DFS tree. + // + // - dfs_child_handles: these are used to hold face handles for + // vertices that are articulation points - dfs_child_handles[v] holds + // the face handles corresponding to vertex u in the bicomp with root + // u and canonical DFS child v. + // + // - canonical_dfs_child: this property map allows one to determine the + // canonical DFS child of a bicomp while traversing the outer face. + // This property map is only valid when applied to one of the two + // vertices adjacent to the root of the bicomp on the outer face. To + // be more precise, if v is the canonical DFS child of a bicomp, + // canonical_dfs_child[dfs_child_handles[v].first_vertex()] == v and + // canonical_dfs_child[dfs_child_handles[v].second_vertex()] == v. + // + // - pertinent_roots: given a vertex v, pertinent_roots[v] contains a + // list of face handles pointing to the top of bicomps that need to + // be visited by the current walkdown traversal (since they lead to + // backedges that need to be embedded). These lists are populated by + // the walkup and consumed by the walkdown. + + vertex_iterator_t vi, vi_end; + for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + { + vertex_t v(*vi); + vertex_t parent = dfs_parent[v]; + + if (parent != v) + { + edge_t parent_edge = dfs_parent_edge[v]; + add_to_embedded_edges(parent_edge, StoreOldHandlesPolicy()); + face_handles[v] = face_handle_t(v, parent_edge, g); + dfs_child_handles[v] = face_handle_t(parent, parent_edge, g); + } + else + { + face_handles[v] = face_handle_t(v); + dfs_child_handles[v] = face_handle_t(parent); + } + + canonical_dfs_child[v] = v; + pertinent_roots[v] = face_handle_list_ptr_t(new face_handle_list_t); + separated_dfs_child_list[v] = vertex_list_ptr_t(new vertex_list_t); + + } + + // We need to create a list of not-yet-merged depth-first children for + // each vertex that will be updated as bicomps get merged. We sort each + // list by ascending lowpoint, which allows the externally_active + // function to run in constant time, and we keep a pointer to each + // vertex's representation in its parent's list, which allows merging + //in constant time. + + for(typename vertex_vector_t::iterator itr = + vertices_by_lowpoint.begin(); + itr != vertices_by_lowpoint.end(); ++itr) + { + vertex_t v(*itr); + vertex_t parent(dfs_parent[v]); + if (v != parent) + { + separated_node_in_parent_list[v] = + separated_dfs_child_list[parent]->insert + (separated_dfs_child_list[parent]->end(), v); + } + } + + // The merge stack holds path information during a walkdown iteration + merge_stack.reserve(num_vertices(g)); + + } + + + + + + + bool is_planar() + { + + // This is the main algorithm: starting with a DFS tree of embedded + // edges (which, since it's a tree, is planar), iterate through all + // vertices by reverse DFS number, attempting to embed all backedges + // connecting the current vertex to vertices with higher DFS numbers. + // + // The walkup is a procedure that examines all such backedges and sets + // up the required data structures so that they can be searched by the + // walkdown in linear time. The walkdown does the actual work of + // embedding edges and flipping bicomps, and can identify when it has + // come across a kuratowski subgraph. + // + // store_old_face_handles caches face handles from the previous + // iteration - this is used only for the kuratowski subgraph isolation, + // and is therefore dispatched based on the StoreOldHandlesPolicy. + // + // clean_up_embedding does some clean-up and fills in values that have + // to be computed lazily during the actual execution of the algorithm + // (for instance, whether or not a bicomp is flipped in the final + // embedding). It's dispatched on the the StoreEmbeddingPolicy, since + // it's not needed if an embedding isn't desired. + + typename vertex_vector_t::reverse_iterator vi, vi_end; + + vi_end = vertices_by_dfs_num.rend(); + for(vi = vertices_by_dfs_num.rbegin(); vi != vi_end; ++vi) + { + + store_old_face_handles(StoreOldHandlesPolicy()); + + vertex_t v(*vi); + + walkup(v); + + if (!walkdown(v)) + return false; + + } + + clean_up_embedding(StoreEmbeddingPolicy()); + + return true; + + } + + + + + + + private: + + + + + + void walkup(vertex_t v) + { + + // The point of the walkup is to follow all backedges from v to + // vertices with higher DFS numbers, and update pertinent_roots + // for the bicomp roots on the path from backedge endpoints up + // to v. This will set the stage for the walkdown to efficiently + // traverse the graph of bicomps down from v. + + typedef typename face_vertex_iterator::type walkup_iterator_t; + + out_edge_iterator_t oi, oi_end; + for(tie(oi,oi_end) = out_edges(v,g); oi != oi_end; ++oi) + { + edge_t e(*oi); + vertex_t e_source(source(e,g)); + vertex_t e_target(target(e,g)); + + if (e_source == e_target) + { + self_loops.push_back(e); + continue; + } + + vertex_t w(e_source == v ? e_target : e_source); + + //continue if not a back edge or already embedded + if (dfs_number[w] < dfs_number[v] || e == dfs_parent_edge[w]) + continue; + + backedges[w].push_back(e); + + v_size_t timestamp = dfs_number[v]; + backedge_flag[w] = timestamp; + + walkup_iterator_t walkup_itr(w, face_handles); + walkup_iterator_t walkup_end; + vertex_t lead_vertex = w; + + while (true) + { + + // Move to the root of the current bicomp or the first visited + // vertex on the bicomp by going up each side in parallel + + while(walkup_itr != walkup_end && + visited[*walkup_itr] != timestamp + ) + { + lead_vertex = *walkup_itr; + visited[lead_vertex] = timestamp; + ++walkup_itr; + } + + // If we've found the root of a bicomp through a path we haven't + // seen before, update pertinent_roots with a handle to the + // current bicomp. Otherwise, we've just seen a path we've been + // up before, so break out of the main while loop. + + if (walkup_itr == walkup_end) + { + vertex_t dfs_child = canonical_dfs_child[lead_vertex]; + vertex_t parent = dfs_parent[dfs_child]; + + visited[dfs_child_handles[dfs_child].first_vertex()] + = timestamp; + visited[dfs_child_handles[dfs_child].second_vertex()] + = timestamp; + + if (low_point[dfs_child] < dfs_number[v] || + least_ancestor[dfs_child] < dfs_number[v] + ) + { + pertinent_roots[parent]->push_back + (dfs_child_handles[dfs_child]); + } + else + { + pertinent_roots[parent]->push_front + (dfs_child_handles[dfs_child]); + } + + if (parent != v && visited[parent] != timestamp) + { + walkup_itr = walkup_iterator_t(parent, face_handles); + lead_vertex = parent; + } + else + break; + } + else + break; + } + + } + + } + + + + + + + + bool walkdown(vertex_t v) + { + // This procedure is where all of the action is - pertinent_roots + // has already been set up by the walkup, so we just need to move + // down bicomps from v until we find vertices that have been + // labeled as backedge endpoints. Once we find such a vertex, we + // embed the corresponding edge and glue together the bicomps on + // the path connecting the two vertices in the edge. This may + // involve flipping bicomps along the way. + + vertex_t w; //the other endpoint of the edge we're embedding + + while (!pertinent_roots[v]->empty()) + { + + face_handle_t root_face_handle = pertinent_roots[v]->front(); + face_handle_t curr_face_handle = root_face_handle; + pertinent_roots[v]->pop_front(); + + merge_stack.clear(); + + while(true) + { + + typename face_vertex_iterator<>::type + first_face_itr, second_face_itr, face_end; + vertex_t first_side_vertex + = graph_traits::null_vertex(); + vertex_t second_side_vertex; + vertex_t first_tail, second_tail; + + first_tail = second_tail = curr_face_handle.get_anchor(); + first_face_itr = typename face_vertex_iterator<>::type + (curr_face_handle, face_handles, first_side()); + second_face_itr = typename face_vertex_iterator<>::type + (curr_face_handle, face_handles, second_side()); + + for(; first_face_itr != face_end; ++first_face_itr) + { + vertex_t face_vertex(*first_face_itr); + if (pertinent(face_vertex, v) || + externally_active(face_vertex, v) + ) + { + first_side_vertex = face_vertex; + second_side_vertex = face_vertex; + break; + } + first_tail = face_vertex; + } + + if (first_side_vertex == graph_traits::null_vertex() || + first_side_vertex == curr_face_handle.get_anchor() + ) + break; + + for(;second_face_itr != face_end; ++second_face_itr) + { + vertex_t face_vertex(*second_face_itr); + if (pertinent(face_vertex, v) || + externally_active(face_vertex, v) + ) + { + second_side_vertex = face_vertex; + break; + } + second_tail = face_vertex; + } + + vertex_t chosen; + bool chose_first_upper_path; + if (internally_active(first_side_vertex, v)) + { + chosen = first_side_vertex; + chose_first_upper_path = true; + } + else if (internally_active(second_side_vertex, v)) + { + chosen = second_side_vertex; + chose_first_upper_path = false; + } + else if (pertinent(first_side_vertex, v)) + { + chosen = first_side_vertex; + chose_first_upper_path = true; + } + else if (pertinent(second_side_vertex, v)) + { + chosen = second_side_vertex; + chose_first_upper_path = false; + } + else + { + + // If there's a pertinent vertex on the lower face + // between the first_face_itr and the second_face_itr, + // this graph isn't planar. + for(; + *first_face_itr != second_side_vertex; + ++first_face_itr + ) + { + vertex_t p(*first_face_itr); + if (pertinent(p,v)) + { + //Found a Kuratowski subgraph + kuratowski_v = v; + kuratowski_x = first_side_vertex; + kuratowski_y = second_side_vertex; + return false; + } + } + + // Otherwise, the fact that we didn't find a pertinent + // vertex on this face is fine - we should set the + // short-circuit edges and break out of this loop to + // start looking at a different pertinent root. + + if (first_side_vertex == second_side_vertex) + { + if (first_tail != v) + { + vertex_t first + = face_handles[first_tail].first_vertex(); + vertex_t second + = face_handles[first_tail].second_vertex(); + tie(first_side_vertex, first_tail) + = make_tuple(first_tail, + first == first_side_vertex ? + second : first + ); + } + else if (second_tail != v) + { + vertex_t first + = face_handles[second_tail].first_vertex(); + vertex_t second + = face_handles[second_tail].second_vertex(); + tie(second_side_vertex, second_tail) + = make_tuple(second_tail, + first == second_side_vertex ? + second : first); + } + else + break; + } + + canonical_dfs_child[first_side_vertex] + = canonical_dfs_child[root_face_handle.first_vertex()]; + canonical_dfs_child[second_side_vertex] + = canonical_dfs_child[root_face_handle.second_vertex()]; + root_face_handle.set_first_vertex(first_side_vertex); + root_face_handle.set_second_vertex(second_side_vertex); + + if (face_handles[first_side_vertex].first_vertex() == + first_tail + ) + face_handles[first_side_vertex].set_first_vertex(v); + else + face_handles[first_side_vertex].set_second_vertex(v); + + if (face_handles[second_side_vertex].first_vertex() == + second_tail + ) + face_handles[second_side_vertex].set_first_vertex(v); + else + face_handles[second_side_vertex].set_second_vertex(v); + + break; + + } + + + // When we unwind the stack, we need to know which direction + // we came down from on the top face handle + + bool chose_first_lower_path = + (chose_first_upper_path && + face_handles[chosen].first_vertex() == first_tail) + || + (!chose_first_upper_path && + face_handles[chosen].first_vertex() == second_tail); + + //If there's a backedge at the chosen vertex, embed it now + if (backedge_flag[chosen] == dfs_number[v]) + { + w = chosen; + + backedge_flag[chosen] = num_vertices(g) + 1; + add_to_merge_points(chosen, StoreOldHandlesPolicy()); + + typename edge_vector_t::iterator ei, ei_end; + ei_end = backedges[chosen].end(); + for(ei = backedges[chosen].begin(); ei != ei_end; ++ei) + { + edge_t e(*ei); + add_to_embedded_edges(e, StoreOldHandlesPolicy()); + + if (chose_first_lower_path) + face_handles[chosen].push_first(e, g); + else + face_handles[chosen].push_second(e, g); + } + + } + else + { + merge_stack.push_back(make_tuple + (chosen, chose_first_upper_path, chose_first_lower_path) + ); + curr_face_handle = *pertinent_roots[chosen]->begin(); + continue; + } + + //Unwind the merge stack to the root, merging all bicomps + + bool bottom_path_follows_first; + bool top_path_follows_first; + bool next_bottom_follows_first = chose_first_upper_path; + face_handle_t top_handle, bottom_handle; + + vertex_t merge_point = chosen; + + while(!merge_stack.empty()) + { + + bottom_path_follows_first = next_bottom_follows_first; + tie(merge_point, + next_bottom_follows_first, + top_path_follows_first + ) = merge_stack.back(); + merge_stack.pop_back(); + + face_handle_t top_handle(face_handles[merge_point]); + face_handle_t bottom_handle + (*pertinent_roots[merge_point]->begin()); + + vertex_t bottom_dfs_child = canonical_dfs_child + [pertinent_roots[merge_point]->begin()->first_vertex()]; + + remove_vertex_from_separated_dfs_child_list( + canonical_dfs_child + [pertinent_roots[merge_point]->begin()->first_vertex()] + ); + + pertinent_roots[merge_point]->pop_front(); + + add_to_merge_points(top_handle.get_anchor(), + StoreOldHandlesPolicy() + ); + + if (top_path_follows_first && bottom_path_follows_first) + { + bottom_handle.flip(); + top_handle.glue_first_to_second(bottom_handle); + } + else if (!top_path_follows_first && + bottom_path_follows_first + ) + { + flipped[bottom_dfs_child] = true; + top_handle.glue_second_to_first(bottom_handle); + } + else if (top_path_follows_first && + !bottom_path_follows_first + ) + { + flipped[bottom_dfs_child] = true; + top_handle.glue_first_to_second(bottom_handle); + } + else //!top_path_follows_first && !bottom_path_follows_first + { + bottom_handle.flip(); + top_handle.glue_second_to_first(bottom_handle); + } + + } + + //Finally, embed all edges (v,w) at their upper end points + canonical_dfs_child[w] + = canonical_dfs_child[root_face_handle.first_vertex()]; + + add_to_merge_points(root_face_handle.get_anchor(), + StoreOldHandlesPolicy() + ); + + typename edge_vector_t::iterator ei, ei_end; + ei_end = backedges[chosen].end(); + for(ei = backedges[chosen].begin(); ei != ei_end; ++ei) + { + if (next_bottom_follows_first) + root_face_handle.push_first(*ei, g); + else + root_face_handle.push_second(*ei, g); + } + + backedges[chosen].clear(); + curr_face_handle = root_face_handle; + + }//while(true) + + }//while(!pertinent_roots[v]->empty()) + + return true; + + } + + + + + + + void store_old_face_handles(graph::detail::no_old_handles) {} + + void store_old_face_handles(graph::detail::store_old_handles) + { + for(typename std::vector::iterator mp_itr + = current_merge_points.begin(); + mp_itr != current_merge_points.end(); ++mp_itr) + { + face_handles[*mp_itr].store_old_face_handles(); + } + current_merge_points.clear(); + } + + + void add_to_merge_points(vertex_t v, graph::detail::no_old_handles) {} + + void add_to_merge_points(vertex_t v, graph::detail::store_old_handles) + { + current_merge_points.push_back(v); + } + + + void add_to_embedded_edges(edge_t e, graph::detail::no_old_handles) {} + + void add_to_embedded_edges(edge_t e, graph::detail::store_old_handles) + { + embedded_edges.push_back(e); + } + + + + + void clean_up_embedding(graph::detail::no_embedding) {} + + void clean_up_embedding(graph::detail::store_embedding) + { + + // If the graph isn't biconnected, we'll still have entries + // in the separated_dfs_child_list for some vertices. Since + // these represent articulation points, we can obtain a + // planar embedding no matter what order we embed them in. + + vertex_iterator_t xi, xi_end; + for(tie(xi,xi_end) = vertices(g); xi != xi_end; ++xi) + { + if (!separated_dfs_child_list[*xi]->empty()) + { + typename vertex_list_t::iterator yi, yi_end; + yi_end = separated_dfs_child_list[*xi]->end(); + for(yi = separated_dfs_child_list[*xi]->begin(); + yi != yi_end; ++yi + ) + { + dfs_child_handles[*yi].flip(); + face_handles[*xi].glue_first_to_second + (dfs_child_handles[*yi]); + } + } + } + + // Up until this point, we've flipped bicomps lazily by setting + // flipped[v] to true if the bicomp rooted at v was flipped (the + // lazy aspect of this flip is that all descendents of that vertex + // need to have their orientations reversed as well). Now, we + // traverse the DFS tree by DFS number and perform the actual + // flipping as needed + + typedef typename vertex_vector_t::iterator vertex_vector_itr_t; + vertex_vector_itr_t vi_end = vertices_by_dfs_num.end(); + for(vertex_vector_itr_t vi = vertices_by_dfs_num.begin(); + vi != vi_end; ++vi + ) + { + vertex_t v(*vi); + bool v_flipped = flipped[v]; + bool p_flipped = flipped[dfs_parent[v]]; + if (v_flipped && !p_flipped) + { + face_handles[v].flip(); + } + else if (p_flipped && !v_flipped) + { + face_handles[v].flip(); + flipped[v] = true; + } + else + { + flipped[v] = false; + } + } + + // If there are any self-loops in the graph, they were flagged + // during the walkup, and we should add them to the embedding now. + // Adding a self loop anywhere in the embedding could never + // invalidate the embedding, but they would complicate the traversal + // if they were added during the walkup/walkdown. + + typename edge_vector_t::iterator ei, ei_end; + ei_end = self_loops.end(); + for(ei = self_loops.begin(); ei != ei_end; ++ei) + { + edge_t e(*ei); + face_handles[source(e,g)].push_second(e,g); + } + + } + + + + + + bool pertinent(vertex_t w, vertex_t v) + { + // w is pertinent with respect to v if there is a backedge (v,w) or if + // w is the root of a bicomp that contains a pertinent vertex. + + return backedge_flag[w] == dfs_number[v] || !pertinent_roots[w]->empty(); + } + + + + bool externally_active(vertex_t w, vertex_t v) + { + // Let a be any proper depth-first search ancestor of v. w is externally + // active with respect to v if there exists a backedge (a,w) or a + // backedge (a,w_0) for some w_0 in a descendent bicomp of w. + + v_size_t dfs_number_of_v = dfs_number[v]; + return (least_ancestor[w] < dfs_number_of_v) || + (!separated_dfs_child_list[w]->empty() && + low_point[separated_dfs_child_list[w]->front()] < dfs_number_of_v); + } + + + + bool internally_active(vertex_t w, vertex_t v) + { + return pertinent(w,v) && !externally_active(w,v); + } + + + + + void remove_vertex_from_separated_dfs_child_list(vertex_t v) + { + typename vertex_list_t::iterator to_delete + = separated_node_in_parent_list[v]; + garbage.splice(garbage.end(), + *separated_dfs_child_list[dfs_parent[v]], + to_delete, + next(to_delete) + ); + } + + + + + + // End of the implementation of the basic Boyer-Myrvold Algorithm. The rest + // of the code below implements the isolation of a Kuratowski subgraph in + // the case that the input graph is not planar. This is by far the most + // complicated part of the implementation. + + + + + public: + + + + + template + vertex_t kuratowski_walkup(vertex_t v, + EdgeToBoolPropertyMap forbidden_edge, + EdgeToBoolPropertyMap goal_edge, + EdgeToBoolPropertyMap is_embedded, + EdgeContainer& path_edges + ) + { + vertex_t current_endpoint; + bool seen_goal_edge = false; + out_edge_iterator_t oi, oi_end; + + for(tie(oi,oi_end) = out_edges(v,g); oi != oi_end; ++oi) + forbidden_edge[*oi] = true; + + for(tie(oi,oi_end) = out_edges(v,g); oi != oi_end; ++oi) + { + path_edges.clear(); + + edge_t e(*oi); + current_endpoint = target(*oi,g) == v ? + source(*oi,g) : target(*oi,g); + + if (dfs_number[current_endpoint] < dfs_number[v] || + is_embedded[e] || + v == current_endpoint //self-loop + ) + { + //Not a backedge + continue; + } + + path_edges.push_back(e); + if (goal_edge[e]) + { + return current_endpoint; + } + + typedef typename face_edge_iterator<>::type walkup_itr_t; + + walkup_itr_t + walkup_itr(current_endpoint, face_handles, first_side()); + walkup_itr_t walkup_end; + + seen_goal_edge = false; + + while (true) + { + + if (walkup_itr != walkup_end && forbidden_edge[*walkup_itr]) + break; + + while(walkup_itr != walkup_end && + !goal_edge[*walkup_itr] && + !forbidden_edge[*walkup_itr] + ) + { + edge_t f(*walkup_itr); + forbidden_edge[f] = true; + path_edges.push_back(f); + current_endpoint = + source(f, g) == current_endpoint ? + target(f, g) : + source(f,g); + ++walkup_itr; + } + + if (walkup_itr != walkup_end && goal_edge[*walkup_itr]) + { + path_edges.push_back(*walkup_itr); + seen_goal_edge = true; + break; + } + + walkup_itr + = walkup_itr_t(current_endpoint, face_handles, first_side()); + + } + + if (seen_goal_edge) + break; + + } + + if (seen_goal_edge) + return current_endpoint; + else + return graph_traits::null_vertex(); + + } + + + + + + + + + template + void extract_kuratowski_subgraph(OutputIterator o_itr, EdgeIndexMap em) + { + + // If the main algorithm has failed to embed one of the back-edges from + // a vertex v, we can use the current state of the algorithm to isolate + // a Kuratowksi subgraph. The isolation process breaks down into five + // cases, A - E. The general configuration of all five cases is shown in + // figure 1. There is a vertex v from which the planar + // v embedding process could not proceed. This means that + // | there exists some bicomp containing three vertices + // ----- x,y, and z as shown such that x and y are externally + // | | active with respect to v (which means that there are + // x y two vertices x_0 and y_0 such that (1) both x_0 and + // | | y_0 are proper depth-first search ancestors of v and + // --z-- (2) there are two disjoint paths, one connecting x + // and x_0 and one connecting y and y_0, both consisting + // fig. 1 entirely of unembedded edges). Furthermore, there + // exists a vertex z_0 such that z is a depth-first + // search ancestor of z_0 and (v,z_0) is an unembedded back-edge from v. + // x,y and z all exist on the same bicomp, which consists entirely of + // embedded edges. The five subcases break down as follows, and are + // handled by the algorithm logically in the order A-E: First, if v is + // not on the same bicomp as x,y, and z, a K_3_3 can be isolated - this + // is case A. So, we'll assume that v is on the same bicomp as x,y, and + // z. If z_0 is on a different bicomp than x,y, and z, a K_3_3 can also + // be isolated - this is a case B - so we'll assume from now on that v + // is on the same bicomp as x, y, and z=z_0. In this case, one can use + // properties of the Boyer-Myrvold algorithm to show the existence of an + // "x-y path" connecting some vertex on the "left side" of the x,y,z + // bicomp with some vertex on the "right side" of the bicomp (where the + // left and right are split by a line drawn through v and z.If either of + // the endpoints of the x-y path is above x or y on the bicomp, a K_3_3 + // can be isolated - this is a case C. Otherwise, both endpoints are at + // or below x and y on the bicomp. If there is a vertex alpha on the x-y + // path such that alpha is not x or y and there's a path from alpha to v + // that's disjoint from any of the edges on the bicomp and the x-y path, + // a K_3_3 can be isolated - this is a case D. Otherwise, properties of + // the Boyer-Myrvold algorithm can be used to show that another vertex + // w exists on the lower half of the bicomp such that w is externally + // active with respect to v. w can then be used to isolate a K_5 - this + // is the configuration of case E. + + vertex_iterator_t vi, vi_end; + edge_iterator_t ei, ei_end; + out_edge_iterator_t oei, oei_end; + typename std::vector::iterator xi, xi_end; + + // Clear the short-circuit edges - these are needed for the planar + // testing/embedding algorithm to run in linear time, but they'll + // complicate the kuratowski subgraph isolation + for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + { + face_handles[*vi].reset_vertex_cache(); + dfs_child_handles[*vi].reset_vertex_cache(); + } + + vertex_t v = kuratowski_v; + vertex_t x = kuratowski_x; + vertex_t y = kuratowski_y; + + typedef iterator_property_map + ::iterator, EdgeIndexMap> + edge_to_bool_map_t; + + std::vector is_in_subgraph_vector(num_edges(g), false); + edge_to_bool_map_t is_in_subgraph(is_in_subgraph_vector.begin(), em); + + std::vector is_embedded_vector(num_edges(g), false); + edge_to_bool_map_t is_embedded(is_embedded_vector.begin(), em); + + typename std::vector::iterator embedded_itr, embedded_end; + embedded_end = embedded_edges.end(); + for(embedded_itr = embedded_edges.begin(); + embedded_itr != embedded_end; ++embedded_itr + ) + is_embedded[*embedded_itr] = true; + + // upper_face_vertex is true for x,y, and all vertices above x and y in + // the bicomp + std::vector upper_face_vertex_vector(num_vertices(g), false); + vertex_to_bool_map_t upper_face_vertex + (upper_face_vertex_vector.begin(), vm); + + std::vector lower_face_vertex_vector(num_vertices(g), false); + vertex_to_bool_map_t lower_face_vertex + (lower_face_vertex_vector.begin(), vm); + + // These next few variable declarations are all things that we need + // to find. + vertex_t z; + vertex_t bicomp_root; + vertex_t w = graph_traits::null_vertex(); + face_handle_t w_handle; + face_handle_t v_dfchild_handle; + vertex_t first_x_y_path_endpoint = graph_traits::null_vertex(); + vertex_t second_x_y_path_endpoint = graph_traits::null_vertex(); + vertex_t w_ancestor = v; + + enum case_t{NO_CASE_CHOSEN, CASE_A, CASE_B, CASE_C, CASE_D, CASE_E}; + case_t chosen_case = NO_CASE_CHOSEN; + + std::vector x_external_path; + std::vector y_external_path; + std::vector case_d_edges; + + std::vector z_v_path; + std::vector w_path; + + //first, use a walkup to find a path from V that starts with a + //backedge from V, then goes up until it hits either X or Y + //(but doesn't find X or Y as the root of a bicomp) + + typename face_vertex_iterator<>::type + x_upper_itr(x, face_handles, first_side()); + typename face_vertex_iterator<>::type + x_lower_itr(x, face_handles, second_side()); + typename face_vertex_iterator<>::type face_itr, face_end; + + // Don't know which path from x is the upper or lower path - + // we'll find out here + for(face_itr = x_upper_itr; face_itr != face_end; ++face_itr) + { + if (*face_itr == y) + { + std::swap(x_upper_itr, x_lower_itr); + break; + } + } + + upper_face_vertex[x] = true; + + vertex_t current_vertex = x; + vertex_t previous_vertex; + for(face_itr = x_upper_itr; face_itr != face_end; ++face_itr) + { + previous_vertex = current_vertex; + current_vertex = *face_itr; + upper_face_vertex[current_vertex] = true; + } + + v_dfchild_handle + = dfs_child_handles[canonical_dfs_child[previous_vertex]]; + + for(face_itr = x_lower_itr; *face_itr != y; ++face_itr) + { + vertex_t current_vertex(*face_itr); + lower_face_vertex[current_vertex] = true; + + typename face_handle_list_t::iterator roots_itr, roots_end; + + if (w == graph_traits::null_vertex()) //haven't found a w yet + { + roots_end = pertinent_roots[current_vertex]->end(); + for(roots_itr = pertinent_roots[current_vertex]->begin(); + roots_itr != roots_end; ++roots_itr + ) + { + if (low_point[canonical_dfs_child[roots_itr->first_vertex()]] + < dfs_number[v] + ) + { + w = current_vertex; + w_handle = *roots_itr; + break; + } + } + } + + } + + for(; face_itr != face_end; ++face_itr) + { + vertex_t current_vertex(*face_itr); + upper_face_vertex[current_vertex] = true; + bicomp_root = current_vertex; + } + + typedef typename face_edge_iterator<>::type walkup_itr_t; + + std::vector outer_face_edge_vector(num_edges(g), false); + edge_to_bool_map_t outer_face_edge(outer_face_edge_vector.begin(), em); + + walkup_itr_t walkup_end; + for(walkup_itr_t walkup_itr(x, face_handles, first_side()); + walkup_itr != walkup_end; ++walkup_itr + ) + { + outer_face_edge[*walkup_itr] = true; + is_in_subgraph[*walkup_itr] = true; + } + + for(walkup_itr_t walkup_itr(x, face_handles, second_side()); + walkup_itr != walkup_end; ++walkup_itr + ) + { + outer_face_edge[*walkup_itr] = true; + is_in_subgraph[*walkup_itr] = true; + } + + std::vector forbidden_edge_vector(num_edges(g), false); + edge_to_bool_map_t forbidden_edge(forbidden_edge_vector.begin(), em); + + std::vector goal_edge_vector(num_edges(g), false); + edge_to_bool_map_t goal_edge(goal_edge_vector.begin(), em); + + + //Find external path to x and to y + + for(tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) + { + edge_t e(*ei); + goal_edge[e] + = !outer_face_edge[e] && (source(e,g) == x || target(e,g) == x); + forbidden_edge[*ei] = outer_face_edge[*ei]; + } + + vertex_t x_ancestor = v; + vertex_t x_endpoint = graph_traits::null_vertex(); + + while(x_endpoint == graph_traits::null_vertex()) + { + x_ancestor = dfs_parent[x_ancestor]; + x_endpoint = kuratowski_walkup(x_ancestor, + forbidden_edge, + goal_edge, + is_embedded, + x_external_path + ); + + } + + + for(tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) + { + edge_t e(*ei); + goal_edge[e] + = !outer_face_edge[e] && (source(e,g) == y || target(e,g) == y); + forbidden_edge[*ei] = outer_face_edge[*ei]; + } + + vertex_t y_ancestor = v; + vertex_t y_endpoint = graph_traits::null_vertex(); + + while(y_endpoint == graph_traits::null_vertex()) + { + y_ancestor = dfs_parent[y_ancestor]; + y_endpoint = kuratowski_walkup(y_ancestor, + forbidden_edge, + goal_edge, + is_embedded, + y_external_path + ); + + } + + + vertex_t parent, child; + + //If v isn't on the same bicomp as x and y, it's a case A + if (bicomp_root != v) + { + chosen_case = CASE_A; + + for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + if (lower_face_vertex[*vi]) + for(tie(oei,oei_end) = out_edges(*vi,g); oei != oei_end; ++oei) + if(!outer_face_edge[*oei]) + goal_edge[*oei] = true; + + for(tie(ei,ei_end) = edges(g); ei != ei_end; ++ei) + forbidden_edge[*ei] = outer_face_edge[*ei]; + + z = kuratowski_walkup + (v, forbidden_edge, goal_edge, is_embedded, z_v_path); + + } + else if (w != graph_traits::null_vertex()) + { + chosen_case = CASE_B; + + for(tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) + { + edge_t e(*ei); + goal_edge[e] = false; + forbidden_edge[e] = outer_face_edge[e]; + } + + goal_edge[w_handle.first_edge()] = true; + goal_edge[w_handle.second_edge()] = true; + + z = kuratowski_walkup(v, + forbidden_edge, + goal_edge, + is_embedded, + z_v_path + ); + + + for(tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) + { + forbidden_edge[*ei] = outer_face_edge[*ei]; + } + + typename std::vector::iterator pi, pi_end; + pi_end = z_v_path.end(); + for(pi = z_v_path.begin(); pi != pi_end; ++pi) + { + goal_edge[*pi] = true; + } + + w_ancestor = v; + vertex_t w_endpoint = graph_traits::null_vertex(); + + while(w_endpoint == graph_traits::null_vertex()) + { + w_ancestor = dfs_parent[w_ancestor]; + w_endpoint = kuratowski_walkup(w_ancestor, + forbidden_edge, + goal_edge, + is_embedded, + w_path + ); + + } + + // We really want both the w walkup and the z walkup to finish on + // exactly the same edge, but for convenience (since we don't have + // control over which side of a bicomp a walkup moves up) we've + // defined the walkup to either end at w_handle.first_edge() or + // w_handle.second_edge(). If both walkups ended at different edges, + // we'll do a little surgery on the w walkup path to make it follow + // the other side of the final bicomp. + + if ((w_path.back() == w_handle.first_edge() && + z_v_path.back() == w_handle.second_edge()) + || + (w_path.back() == w_handle.second_edge() && + z_v_path.back() == w_handle.first_edge()) + ) + { + walkup_itr_t wi, wi_end; + edge_t final_edge = w_path.back(); + vertex_t anchor + = source(final_edge, g) == w_handle.get_anchor() ? + target(final_edge, g) : source(final_edge, g); + if (face_handles[anchor].first_edge() == final_edge) + wi = walkup_itr_t(anchor, face_handles, second_side()); + else + wi = walkup_itr_t(anchor, face_handles, first_side()); + + w_path.pop_back(); + + for(; wi != wi_end; ++wi) + { + edge_t e(*wi); + if (w_path.back() == e) + w_path.pop_back(); + else + w_path.push_back(e); + } + } + + + } + else + { + + //We need to find a valid z, since the x-y path re-defines the lower + //face, and the z we found earlier may now be on the upper face. + + chosen_case = CASE_E; + + + // The z we've used so far is just an externally active vertex on the + // lower face path, but may not be the z we need for a case C, D, or + // E subgraph. the z we need now is any externally active vertex on + // the lower face path with both old_face_handles edges on the outer + // face. Since we know an x-y path exists, such a z must also exist. + + //TODO: find this z in the first place. + + //find the new z + + for(face_itr = x_lower_itr; *face_itr != y; ++face_itr) + { + vertex_t possible_z(*face_itr); + if (pertinent(possible_z,v) && + outer_face_edge[face_handles[possible_z].old_first_edge()] && + outer_face_edge[face_handles[possible_z].old_second_edge()] + ) + { + z = possible_z; + break; + } + } + + //find x-y path, and a w if one exists. + + if (externally_active(z,v)) + w = z; + + + typedef typename face_edge_iterator + ::type old_face_iterator_t; + + old_face_iterator_t + first_old_face_itr(z, face_handles, first_side()); + old_face_iterator_t + second_old_face_itr(z, face_handles, second_side()); + old_face_iterator_t old_face_itr, old_face_end; + + std::vector old_face_iterators; + old_face_iterators.push_back(first_old_face_itr); + old_face_iterators.push_back(second_old_face_itr); + + std::vector x_y_path_vertex_vector(num_vertices(g), false); + vertex_to_bool_map_t x_y_path_vertex + (x_y_path_vertex_vector.begin(), vm); + + typename std::vector::iterator + of_itr, of_itr_end; + of_itr_end = old_face_iterators.end(); + for(of_itr = old_face_iterators.begin(); + of_itr != of_itr_end; ++of_itr + ) + { + + old_face_itr = *of_itr; + + vertex_t previous_vertex; + bool seen_x_or_y = false; + vertex_t current_vertex = z; + for(; old_face_itr != old_face_end; ++old_face_itr) + { + edge_t e(*old_face_itr); + previous_vertex = current_vertex; + current_vertex = source(e,g) == current_vertex ? + target(e,g) : source(e,g); + + if (current_vertex == x || current_vertex == y) + seen_x_or_y = true; + + if (w == graph_traits::null_vertex() && + externally_active(current_vertex,v) && + outer_face_edge[e] && + outer_face_edge[*next(old_face_itr)] && + !seen_x_or_y + ) + { + w = current_vertex; + } + + if (!outer_face_edge[e]) + { + if (!upper_face_vertex[current_vertex] && + !lower_face_vertex[current_vertex] + ) + { + x_y_path_vertex[current_vertex] = true; + } + + is_in_subgraph[e] = true; + if (upper_face_vertex[source(e,g)] || + lower_face_vertex[source(e,g)] + ) + { + if (first_x_y_path_endpoint == + graph_traits::null_vertex() + ) + first_x_y_path_endpoint = source(e,g); + else + second_x_y_path_endpoint = source(e,g); + } + if (upper_face_vertex[target(e,g)] || + lower_face_vertex[target(e,g)] + ) + { + if (first_x_y_path_endpoint == + graph_traits::null_vertex() + ) + first_x_y_path_endpoint = target(e,g); + else + second_x_y_path_endpoint = target(e,g); + } + + + } + else if (previous_vertex == x || previous_vertex == y) + { + chosen_case = CASE_C; + } + + } + + } + + // Look for a case D - one of v's embedded edges will connect to the + // x-y path along an inner face path. + + //First, get a list of all of v's embedded child edges + + out_edge_iterator_t v_edge_itr, v_edge_end; + for(tie(v_edge_itr,v_edge_end) = out_edges(v,g); + v_edge_itr != v_edge_end; ++v_edge_itr + ) + { + edge_t embedded_edge(*v_edge_itr); + + if (!is_embedded[embedded_edge] || + embedded_edge == dfs_parent_edge[v] + ) + continue; + + case_d_edges.push_back(embedded_edge); + + vertex_t current_vertex + = source(embedded_edge,g) == v ? + target(embedded_edge,g) : source(embedded_edge,g); + + typename face_edge_iterator<>::type + internal_face_itr, internal_face_end; + if (face_handles[current_vertex].first_vertex() == v) + { + internal_face_itr = typename face_edge_iterator<>::type + (current_vertex, face_handles, second_side()); + } + else + { + internal_face_itr = typename face_edge_iterator<>::type + (current_vertex, face_handles, first_side()); + } + + while(internal_face_itr != internal_face_end && + !outer_face_edge[*internal_face_itr] && + !x_y_path_vertex[current_vertex] + ) + { + edge_t e(*internal_face_itr); + case_d_edges.push_back(e); + current_vertex = + source(e,g) == current_vertex ? target(e,g) : source(e,g); + ++internal_face_itr; + } + + if (x_y_path_vertex[current_vertex]) + { + chosen_case = CASE_D; + break; + } + else + { + case_d_edges.clear(); + } + + } + + + } + + + + + if (chosen_case != CASE_B && chosen_case != CASE_A) + { + + //Finding z and w. + + for(tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) + { + edge_t e(*ei); + goal_edge[e] = !outer_face_edge[e] && + (source(e,g) == z || target(e,g) == z); + forbidden_edge[e] = outer_face_edge[e]; + } + + kuratowski_walkup(v, + forbidden_edge, + goal_edge, + is_embedded, + z_v_path + ); + + if (chosen_case == CASE_E) + { + + for(tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) + { + forbidden_edge[*ei] = outer_face_edge[*ei]; + goal_edge[*ei] = !outer_face_edge[*ei] && + (source(*ei,g) == w || target(*ei,g) == w); + } + + for(tie(oei, oei_end) = out_edges(w,g); oei != oei_end; ++oei) + { + if (!outer_face_edge[*oei]) + goal_edge[*oei] = true; + } + + typename std::vector::iterator pi, pi_end; + pi_end = z_v_path.end(); + for(pi = z_v_path.begin(); pi != pi_end; ++pi) + { + goal_edge[*pi] = true; + } + + w_ancestor = v; + vertex_t w_endpoint = graph_traits::null_vertex(); + + while(w_endpoint == graph_traits::null_vertex()) + { + w_ancestor = dfs_parent[w_ancestor]; + w_endpoint = kuratowski_walkup(w_ancestor, + forbidden_edge, + goal_edge, + is_embedded, + w_path + ); + + } + + } + + + } + + + //We're done isolating the Kuratowski subgraph at this point - + //but there's still some cleaning up to do. + + //Update is_in_subgraph with the paths we just found + + xi_end = x_external_path.end(); + for(xi = x_external_path.begin(); xi != xi_end; ++xi) + is_in_subgraph[*xi] = true; + + xi_end = y_external_path.end(); + for(xi = y_external_path.begin(); xi != xi_end; ++xi) + is_in_subgraph[*xi] = true; + + xi_end = z_v_path.end(); + for(xi = z_v_path.begin(); xi != xi_end; ++xi) + is_in_subgraph[*xi] = true; + + xi_end = case_d_edges.end(); + for(xi = case_d_edges.begin(); xi != xi_end; ++xi) + is_in_subgraph[*xi] = true; + + xi_end = w_path.end(); + for(xi = w_path.begin(); xi != xi_end; ++xi) + is_in_subgraph[*xi] = true; + + child = bicomp_root; + parent = dfs_parent[child]; + while(child != parent) + { + is_in_subgraph[dfs_parent_edge[child]] = true; + tie(parent, child) = std::make_pair( dfs_parent[parent], parent ); + } + + + + + // At this point, we've already isolated the Kuratowski subgraph and + // collected all of the edges that compose it in the is_in_subgraph + // property map. But we want the verification of such a subgraph to be + // a deterministic process, and we can simplify the function + // is_kuratowski_subgraph by cleaning up some edges here. + + if (chosen_case == CASE_B) + { + is_in_subgraph[dfs_parent_edge[v]] = false; + } + else if (chosen_case == CASE_C) + { + // In a case C subgraph, at least one of the x-y path endpoints + // (call it alpha) is above either x or y on the outer face. The + // other endpoint may be attached at x or y OR above OR below. In + // any of these three cases, we can form a K_3_3 by removing the + // edge attached to v on the outer face that is NOT on the path to + // alpha. + + typename face_vertex_iterator::type + face_itr, face_end; + if (face_handles[v_dfchild_handle.first_vertex()].first_edge() == + v_dfchild_handle.first_edge() + ) + { + face_itr = typename face_vertex_iterator + ::type + (v_dfchild_handle.first_vertex(), face_handles, second_side()); + } + else + { + face_itr = typename face_vertex_iterator + ::type + (v_dfchild_handle.first_vertex(), face_handles, first_side()); + } + + for(; true; ++face_itr) + { + vertex_t current_vertex(*face_itr); + if (current_vertex == x || current_vertex == y) + { + is_in_subgraph[v_dfchild_handle.first_edge()] = false; + break; + } + else if (current_vertex == first_x_y_path_endpoint || + current_vertex == second_x_y_path_endpoint) + { + is_in_subgraph[v_dfchild_handle.second_edge()] = false; + break; + } + } + + } + else if (chosen_case == CASE_D) + { + // Need to remove both of the edges adjacent to v on the outer face. + // remove the connecting edges from v to bicomp, then + // is_kuratowski_subgraph will shrink vertices of degree 1 + // automatically... + + is_in_subgraph[v_dfchild_handle.first_edge()] = false; + is_in_subgraph[v_dfchild_handle.second_edge()] = false; + + } + else if (chosen_case == CASE_E) + { + // Similarly to case C, if the endpoints of the x-y path are both + // below x and y, we should remove an edge to allow the subgraph to + // contract to a K_3_3. + + + if ((first_x_y_path_endpoint != x && first_x_y_path_endpoint != y) || + (second_x_y_path_endpoint != x && second_x_y_path_endpoint != y) + ) + { + is_in_subgraph[dfs_parent_edge[v]] = false; + + vertex_t deletion_endpoint, other_endpoint; + if (lower_face_vertex[first_x_y_path_endpoint]) + { + deletion_endpoint = second_x_y_path_endpoint; + other_endpoint = first_x_y_path_endpoint; + } + else + { + deletion_endpoint = first_x_y_path_endpoint; + other_endpoint = second_x_y_path_endpoint; + } + + typename face_edge_iterator<>::type face_itr, face_end; + + bool found_other_endpoint = false; + for(face_itr = typename face_edge_iterator<>::type + (deletion_endpoint, face_handles, first_side()); + face_itr != face_end; ++face_itr + ) + { + edge_t e(*face_itr); + if (source(e,g) == other_endpoint || + target(e,g) == other_endpoint + ) + { + found_other_endpoint = true; + break; + } + } + + if (found_other_endpoint) + { + is_in_subgraph[face_handles[deletion_endpoint].first_edge()] + = false; + } + else + { + is_in_subgraph[face_handles[deletion_endpoint].second_edge()] + = false; + } + } + + } + + + for(tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) + if (is_in_subgraph[*ei]) + *o_itr = *ei; + + } + + + + template + void make_edge_permutation(EdgePermutation perm) + { + vertex_iterator_t vi, vi_end; + for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + { + vertex_t v(*vi); + perm[v].clear(); + face_handles[v].get_list(std::back_inserter(perm[v])); + } + } + + + private: + + const Graph& g; + VertexIndexMap vm; + + vertex_t kuratowski_v; + vertex_t kuratowski_x; + vertex_t kuratowski_y; + + vertex_list_t garbage; // we delete items from linked lists by + // splicing them into garbage + + //only need these two for kuratowski subgraph isolation + std::vector current_merge_points; + std::vector embedded_edges; + + //property map storage + std::vector low_point_vector; + std::vector dfs_parent_vector; + std::vector dfs_number_vector; + std::vector least_ancestor_vector; + std::vector pertinent_roots_vector; + std::vector backedge_flag_vector; + std::vector visited_vector; + std::vector< face_handle_t > face_handles_vector; + std::vector< face_handle_t > dfs_child_handles_vector; + std::vector< vertex_list_ptr_t > separated_dfs_child_list_vector; + std::vector< typename vertex_list_t::iterator > + separated_node_in_parent_list_vector; + std::vector canonical_dfs_child_vector; + std::vector flipped_vector; + std::vector backedges_vector; + edge_vector_t self_loops; + std::vector dfs_parent_edge_vector; + vertex_vector_t vertices_by_dfs_num; + + //property maps + vertex_to_v_size_map_t low_point; + vertex_to_vertex_map_t dfs_parent; + vertex_to_v_size_map_t dfs_number; + vertex_to_v_size_map_t least_ancestor; + vertex_to_face_handle_list_ptr_map_t pertinent_roots; + vertex_to_v_size_map_t backedge_flag; + vertex_to_v_size_map_t visited; + vertex_to_face_handle_map_t face_handles; + vertex_to_face_handle_map_t dfs_child_handles; + vertex_to_vertex_list_ptr_map_t separated_dfs_child_list; + vertex_to_separated_node_map_t separated_node_in_parent_list; + vertex_to_vertex_map_t canonical_dfs_child; + vertex_to_bool_map_t flipped; + vertex_to_edge_vector_map_t backedges; + vertex_to_edge_map_t dfs_parent_edge; //only need for kuratowski + + merge_stack_t merge_stack; + + }; + + +} //namespace boost + +#endif //__BOYER_MYRVOLD_IMPL_HPP__ diff --git a/include/boost/graph/planar_detail/bucket_sort.hpp b/include/boost/graph/planar_detail/bucket_sort.hpp new file mode 100644 index 00000000..f0726285 --- /dev/null +++ b/include/boost/graph/planar_detail/bucket_sort.hpp @@ -0,0 +1,144 @@ +//======================================================================= +// Copyright 2007 Aaron Windsor +// +// 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 __BUCKET_SORT_HPP__ +#define __BUCKET_SORT_HPP__ + +#include +#include +#include + + + +namespace boost +{ + + + template + struct rank_comparison + { + rank_comparison(ItemToRankMap arg_itrm) : itrm(arg_itrm) {} + + template + bool operator() (Item x, Item y) const + { + return get(itrm, x) < get(itrm, y); + } + + private: + ItemToRankMap itrm; + + }; + + + template + struct property_map_tuple_adaptor : + public put_get_helper< typename PropertyMapWrapper::value_type, + property_map_tuple_adaptor + + > + { + typedef typename PropertyMapWrapper::reference reference; + typedef typename PropertyMapWrapper::value_type value_type; + typedef TupleType key_type; + typedef readable_property_map_tag category; + + property_map_tuple_adaptor() {} + + property_map_tuple_adaptor(PropertyMapWrapper wrapper_map) : + m_wrapper_map(wrapper_map) + {} + + inline value_type operator[](const key_type& x) const + { + return get(m_wrapper_map, get(x)); + } + + static const int n = N; + PropertyMapWrapper m_wrapper_map; + + }; + + + + + // This function sorts a sequence of n items by their ranks in linear time, + // given that all ranks are in the range [0, range). This sort is stable. + template + void bucket_sort(ForwardIterator begin, + ForwardIterator end, + ItemToRankMap rank, + SizeType range = 0) + { +#ifdef BOOST_GRAPH_PREFER_STD_LIB + std::stable_sort(begin, end, rank_comparison(rank)); +#else + typedef std::vector + < typename boost::property_traits::key_type > + vector_of_values_t; + typedef std::vector< vector_of_values_t > vector_of_vectors_t; + + if (!range) + { + rank_comparison cmp(rank); + ForwardIterator max_by_rank = std::max_element(begin, end, cmp); + if (max_by_rank == end) + return; + range = get(rank, *max_by_rank) + 1; + } + + vector_of_vectors_t temp_values(range); + + for(ForwardIterator itr = begin; itr != end; ++itr) + { + temp_values[get(rank, *itr)].push_back(*itr); + } + + ForwardIterator orig_seq_itr = begin; + typename vector_of_vectors_t::iterator itr_end = temp_values.end(); + for(typename vector_of_vectors_t::iterator itr = temp_values.begin(); + itr != itr_end; ++itr + ) + { + typename vector_of_values_t::iterator jtr_end = itr->end(); + for(typename vector_of_values_t::iterator jtr = itr->begin(); + jtr != jtr_end; ++jtr + ) + { + *orig_seq_itr = *jtr; + ++orig_seq_itr; + } + } +#endif + } + + + template + void bucket_sort(ForwardIterator begin, + ForwardIterator end, + ItemToRankMap rank) + { + bucket_sort(begin, end, rank, 0); + } + + template + void bucket_sort(ForwardIterator begin, + ForwardIterator end + ) + { + bucket_sort(begin, end, identity_property_map()); + } + + +} //namespace boost + + +#endif //__BUCKET_SORT_HPP__ diff --git a/include/boost/graph/planar_detail/face_handles.hpp b/include/boost/graph/planar_detail/face_handles.hpp new file mode 100644 index 00000000..4e28d4af --- /dev/null +++ b/include/boost/graph/planar_detail/face_handles.hpp @@ -0,0 +1,497 @@ +//======================================================================= +// 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 +#include +#include + + +// 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 + struct lazy_list_node + { + typedef shared_ptr< lazy_list_node > 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 m_left_child; + shared_ptr m_right_child; + }; + + + + template + struct old_handles_storage; + + template + struct old_handles_storage + { + Vertex first_vertex; + Vertex second_vertex; + Edge first_edge; + Edge second_edge; + }; + + template + struct old_handles_storage + {}; + + + + + + + template + struct edge_list_storage; + + + + + + template + struct edge_list_storage + { + typedef void type; + + void push_back(Edge) {} + void push_front(Edge) {} + void reverse() {} + void concat_front(edge_list_storage) {} + void concat_back(edge_list_storage) {} + template + void get_list(OutputIterator) {} + }; + + + + + + template + struct edge_list_storage + { + typedef lazy_list_node 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 other) + { + value = type(new node_type(other.value, value)); + } + + void concat_back(edge_list_storage other) + { + value = type(new node_type(value, other.value)); + } + + template + void get_list(OutputIterator out) + { + get_list_helper(out, value); + } + + private: + + template + 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 + struct edge_list_storage + { + typedef std::list 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 other) + { + value.splice(value.begin(), other.value); + } + + void concat_back(edge_list_storage other) + { + value.splice(value.end(), other.value); + } + + template + void get_list(OutputIterator out) + { + std::copy(value.begin(), value.end(), out); + } + + }; + + + + + + + + template + struct face_handle_impl + { + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::edge_descriptor edge_t; + typedef typename edge_list_storage::type + edge_list_storage_t; + + + face_handle_impl() : + cached_first_vertex(graph_traits::null_vertex()), + cached_second_vertex(graph_traits::null_vertex()), + true_first_vertex(graph_traits::null_vertex()), + true_second_vertex(graph_traits::null_vertex()), + anchor(graph_traits::null_vertex()) + { + initialize_old_vertices_dispatch(StoreOldHandlesPolicy()); + } + + void initialize_old_vertices_dispatch(store_old_handles) + { + old_handles.first_vertex = graph_traits::null_vertex(); + old_handles.second_vertex = graph_traits::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 edge_list; + old_handles_storage old_handles; + + }; + + + + + + + + + + + + template + class face_handle + { + public: + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::edge_descriptor edge_t; + typedef face_handle_impl + impl_t; + typedef face_handle + self_t; + + face_handle(vertex_t anchor = graph_traits::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& 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& 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 + 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 pimpl; + + }; + + +} /* namespace detail */ } /* namespace graph */ } /* namespace boost */ + + +#endif //__FACE_HANDLES_HPP__ diff --git a/include/boost/graph/planar_detail/face_iterators.hpp b/include/boost/graph/planar_detail/face_iterators.hpp new file mode 100644 index 00000000..2cd1df5e --- /dev/null +++ b/include/boost/graph/planar_detail/face_iterators.hpp @@ -0,0 +1,375 @@ +//======================================================================= +// 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_ITERATORS_HPP__ +#define __FACE_ITERATORS_HPP__ + +#include +#include +#include + +namespace boost +{ + + //tags for defining traversal properties + + //VisitorType + struct lead_visitor {}; + struct follow_visitor {}; + + //TraversalType + struct single_side {}; + struct both_sides {}; + + //TraversalSubType + struct first_side {}; //for single_side + struct second_side {}; //for single_side + struct alternating {}; //for both_sides + + //Time + struct current_iteration {}; + struct previous_iteration {}; + + // Why TraversalType AND TraversalSubType? TraversalSubType is a function + // template parameter passed in to the constructor of the face iterator, + // whereas TraversalType is a class template parameter. This lets us decide + // at runtime whether to move along the first or second side of a bicomp (by + // assigning a face_iterator that has been constructed with TraversalSubType + // = first_side or second_side to a face_iterator variable) without any of + // the virtual function overhead that comes with implementing this + // functionality as a more structured form of type erasure. It also allows + // a single face_iterator to be the end iterator of two iterators traversing + // both sides of a bicomp. + + //ValueType is either graph_traits::vertex_descriptor + //or graph_traits::edge_descriptor + + + //forward declaration (defining defaults) + template + class face_iterator; + + + + template + struct edge_storage + {}; + + template + struct edge_storage + { + typename graph_traits::edge_descriptor value; + }; + + + + + //specialization for TraversalType = traverse_vertices + template + + class face_iterator + : public boost::iterator_facade < face_iterator, + ValueType, + boost::forward_traversal_tag, + ValueType + > + { + public: + + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::edge_descriptor edge_t; + typedef face_iterator + self; + typedef typename FaceHandlesMap::value_type face_handle_t; + + face_iterator() : + m_lead(graph_traits::null_vertex()), + m_follow(graph_traits::null_vertex()) + {} + + template + face_iterator(face_handle_t anchor_handle, + FaceHandlesMap face_handles, + TraversalSubType traversal_type): + m_follow(anchor_handle.get_anchor()), + m_face_handles(face_handles) + { + set_lead_dispatch(anchor_handle, traversal_type); + } + + template + face_iterator(vertex_t anchor, + FaceHandlesMap face_handles, + TraversalSubType traversal_type): + m_follow(anchor), + m_face_handles(face_handles) + { + set_lead_dispatch(m_face_handles[anchor], traversal_type); + } + + private: + + friend class boost::iterator_core_access; + + + + + inline vertex_t get_first_vertex(face_handle_t anchor_handle, + current_iteration + ) + { + return anchor_handle.first_vertex(); + } + + inline vertex_t get_second_vertex(face_handle_t anchor_handle, + current_iteration + ) + { + return anchor_handle.second_vertex(); + } + + inline vertex_t get_first_vertex(face_handle_t anchor_handle, + previous_iteration + ) + { + return anchor_handle.old_first_vertex(); + } + + inline vertex_t get_second_vertex(face_handle_t anchor_handle, + previous_iteration + ) + { + return anchor_handle.old_second_vertex(); + } + + + + + + inline void set_lead_dispatch(face_handle_t anchor_handle, first_side) + { + m_lead = get_first_vertex(anchor_handle, Time()); + set_edge_to_first_dispatch(anchor_handle, ValueType(), Time()); + } + + inline void set_lead_dispatch(face_handle_t anchor_handle, second_side) + { + m_lead = get_second_vertex(anchor_handle, Time()); + set_edge_to_second_dispatch(anchor_handle, ValueType(), Time()); + } + + + + + + inline void set_edge_to_first_dispatch(face_handle_t anchor_handle, + edge_t, + current_iteration + ) + { + m_edge.value = anchor_handle.first_edge(); + } + + inline void set_edge_to_second_dispatch(face_handle_t anchor_handle, + edge_t, + current_iteration + ) + { + m_edge.value = anchor_handle.second_edge(); + } + + inline void set_edge_to_first_dispatch(face_handle_t anchor_handle, + edge_t, + previous_iteration + ) + { + m_edge.value = anchor_handle.old_first_edge(); + } + + inline void set_edge_to_second_dispatch(face_handle_t anchor_handle, + edge_t, + previous_iteration + ) + { + m_edge.value = anchor_handle.old_second_edge(); + } + + template + inline void set_edge_to_first_dispatch(face_handle_t, vertex_t, T) + {} + + template + inline void set_edge_to_second_dispatch(face_handle_t, vertex_t, T) + {} + + void increment() + { + face_handle_t curr_face_handle(m_face_handles[m_lead]); + vertex_t first = get_first_vertex(curr_face_handle, Time()); + vertex_t second = get_second_vertex(curr_face_handle, Time()); + if (first == m_follow) + { + m_follow = m_lead; + set_edge_to_second_dispatch(curr_face_handle, ValueType(), Time()); + m_lead = second; + } + else if (second == m_follow) + { + m_follow = m_lead; + set_edge_to_first_dispatch(curr_face_handle, ValueType(), Time()); + m_lead = first; + } + else + m_lead = m_follow = graph_traits::null_vertex(); + } + + bool equal(self const& other) const + { + return m_lead == other.m_lead && m_follow == other.m_follow; + } + + ValueType dereference() const + { + return dereference_dispatch(VisitorType(), ValueType()); + } + + inline ValueType dereference_dispatch(lead_visitor, vertex_t) const + { return m_lead; } + + inline ValueType dereference_dispatch(follow_visitor, vertex_t) const + { return m_follow; } + + inline ValueType dereference_dispatch(lead_visitor, edge_t) const + { return m_edge.value; } + + inline ValueType dereference_dispatch(follow_visitor, edge_t) const + { return m_edge.value; } + + vertex_t m_lead; + vertex_t m_follow; + edge_storage::value > m_edge; + FaceHandlesMap m_face_handles; + }; + + + + + + + + + + template + class face_iterator + + : public boost::iterator_facade< face_iterator, + ValueType, + boost::forward_traversal_tag, + ValueType > + { + public: + + typedef face_iterator + self; + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename FaceHandlesMap::value_type face_handle_t; + + face_iterator() {} + + face_iterator(face_handle_t anchor_handle, FaceHandlesMap face_handles): + first_itr(anchor_handle, face_handles, first_side()), + second_itr(anchor_handle, face_handles, second_side()), + first_is_active(true), + first_increment(true) + {} + + face_iterator(vertex_t anchor, FaceHandlesMap face_handles): + first_itr(face_handles[anchor], face_handles, first_side()), + second_itr(face_handles[anchor], face_handles, second_side()), + first_is_active(true), + first_increment(true) + {} + + private: + + friend class boost::iterator_core_access; + + typedef face_iterator + + inner_itr_t; + + void increment() + { + if (first_increment) + { + ++first_itr; + ++second_itr; + first_increment = false; + } + else if (first_is_active) + ++first_itr; + else + ++second_itr; + first_is_active = !first_is_active; + } + + bool equal(self const& other) const + { + //Want this iterator to be equal to the "end" iterator when at least + //one of the iterators has reached the root of the current bicomp. + //This isn't ideal, but it works. + + return (first_itr == other.first_itr || second_itr == other.second_itr); + } + + ValueType dereference() const + { + return first_is_active ? *first_itr : *second_itr; + } + + inner_itr_t first_itr; + inner_itr_t second_itr; + inner_itr_t face_end; + bool first_is_active; + bool first_increment; + + }; + + +} /* namespace boost */ + + +#endif //__FACE_ITERATORS_HPP__ diff --git a/include/boost/graph/planar_face_traversal.hpp b/include/boost/graph/planar_face_traversal.hpp new file mode 100644 index 00000000..95e8401f --- /dev/null +++ b/include/boost/graph/planar_face_traversal.hpp @@ -0,0 +1,210 @@ +//======================================================================= +// 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 __PLANAR_FACE_TRAVERSAL_HPP__ +#define __PLANAR_FACE_TRAVERSAL_HPP__ + +#include +#include //for next and prior +#include + + +namespace boost +{ + + + + + struct planar_face_traversal_visitor + { + void begin_traversal() + {} + + void begin_face() + {} + + template + void next_edge(Edge e) + {} + + template + void next_vertex(Vertex v) + {} + + void end_face() + {} + + void end_traversal() + {} + + }; + + + + + + template + void planar_face_traversal(const Graph& g, + PlanarEmbedding embedding, + Visitor& visitor, EdgeIndexMap em + ) + { + typedef typename graph_traits::vertex_descriptor vertex_t; + typedef typename graph_traits::edge_descriptor edge_t; + typedef typename graph_traits::vertex_iterator vertex_iterator_t; + typedef typename graph_traits::edge_iterator edge_iterator_t; + typedef typename + property_traits::value_type embedding_value_t; + typedef typename embedding_value_t::const_iterator embedding_iterator_t; + + typedef typename + std::vector< std::set > distinguished_edge_storage_t; + typedef typename + std::vector< std::map > + distinguished_edge_to_edge_storage_t; + + typedef typename + boost::iterator_property_map + + distinguished_edge_map_t; + + typedef typename + boost::iterator_property_map + + distinguished_edge_to_edge_map_t; + + distinguished_edge_storage_t visited_vector(num_edges(g)); + distinguished_edge_to_edge_storage_t next_edge_vector(num_edges(g)); + + distinguished_edge_map_t visited(visited_vector.begin(), em); + distinguished_edge_to_edge_map_t next_edge(next_edge_vector.begin(), em); + + vertex_iterator_t vi, vi_end; + typename std::vector::iterator ei, ei_end; + edge_iterator_t fi, fi_end; + embedding_iterator_t pi, pi_begin, pi_end; + + visitor.begin_traversal(); + + // Initialize the next_edge property map. This map is initialized from the + // PlanarEmbedding so that get(next_edge, e)[v] is the edge that comes + // after e in the clockwise embedding around vertex v. + + for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + { + vertex_t v(*vi); + pi_begin = embedding[v].begin(); + pi_end = embedding[v].end(); + for(pi = pi_begin; pi != pi_end; ++pi) + { + edge_t e(*pi); + std::map m = get(next_edge, e); + m[v] = next(pi) == pi_end ? *pi_begin : *next(pi); + put(next_edge, e, m); + } + } + + // Take a copy of the edges in the graph here, since we want to accomodate + // face traversals that add edges to the graph (for triangulation, in + // particular) and don't want to use invalidated edge iterators. + // Also, while iterating over all edges in the graph, we single out + // any self-loops, which need some special treatment in the face traversal. + + std::vector self_loops; + std::vector edges_cache; + std::vector vertices_in_edge; + + for(tie(fi,fi_end) = edges(g); fi != fi_end; ++fi) + { + edge_t e(*fi); + edges_cache.push_back(e); + if (source(e,g) == target(e,g)) + self_loops.push_back(e); + } + + + // Iterate over all edges in the graph + ei_end = edges_cache.end(); + for(ei = edges_cache.begin(); ei != ei_end; ++ei) + { + + edge_t e(*ei); + vertices_in_edge.clear(); + vertices_in_edge.push_back(source(e,g)); + vertices_in_edge.push_back(target(e,g)); + + typename std::vector::iterator vi, vi_end; + vi_end = vertices_in_edge.end(); + + //Iterate over both vertices in the current edge + for(vi = vertices_in_edge.begin(); vi != vi_end; ++vi) + { + + vertex_t v(*vi); + std::set e_visited = get(visited, e); + typename std::set::iterator e_visited_found + = e_visited.find(v); + + if (e_visited_found == e_visited.end()) + visitor.begin_face(); + + while (e_visited.find(v) == e_visited.end()) + { + visitor.next_vertex(v); + visitor.next_edge(e); + e_visited.insert(v); + put(visited, e, e_visited); + v = source(e,g) == v ? target(e,g) : source(e,g); + e = get(next_edge, e)[v]; + e_visited = get(visited, e); + } + + if (e_visited_found == e_visited.end()) + visitor.end_face(); + + } + + } + + // Iterate over all self-loops, visiting them once separately + // (they've already been visited once, this visitation is for + // the "inside" of the self-loop) + + ei_end = self_loops.end(); + for(ei = self_loops.begin(); ei != ei_end; ++ei) + { + visitor.begin_face(); + visitor.next_edge(*ei); + visitor.next_vertex(source(*ei,g)); + visitor.end_face(); + } + + visitor.end_traversal(); + + } + + + + template + inline void planar_face_traversal(const Graph& g, + PlanarEmbedding embedding, + Visitor& visitor + ) + { + planar_face_traversal(g, embedding, visitor, get(edge_index, g)); + } + + + + +} //namespace boost + +#endif //__PLANAR_FACE_TRAVERSAL_HPP__ diff --git a/include/boost/graph/properties.hpp b/include/boost/graph/properties.hpp index 5f10d04c..e3816e36 100644 --- a/include/boost/graph/properties.hpp +++ b/include/boost/graph/properties.hpp @@ -16,6 +16,13 @@ #include #include + +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Stay out of the way of the concept checking class +# define Graph Graph_ +# define RandomAccessContainer RandomAccessContainer_ +#endif + namespace boost { enum default_color_type { white_color, gray_color, green_color, red_color, black_color }; @@ -322,7 +329,7 @@ namespace boost { #if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) # define BOOST_GRAPH_NO_BUNDLED_PROPERTIES #endif - + #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES template struct bundle_property_map @@ -354,11 +361,11 @@ namespace boost { typedef graph_traits traits; typedef typename Graph::vertex_bundled vertex_bundled; typedef typename Graph::edge_bundled edge_bundled; - typedef typename ct_if<(detail::is_vertex_bundle::value), + typedef typename mpl::if_c<(detail::is_vertex_bundle::value), typename traits::vertex_descriptor, typename traits::edge_descriptor>::type descriptor; - typedef typename ct_if<(detail::is_vertex_bundle::value), + typedef typename mpl::if_c<(detail::is_vertex_bundle::value), vertex_bundled, edge_bundled>::type actual_bundle; @@ -372,4 +379,11 @@ namespace boost { } // namespace boost +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Stay out of the way of the concept checking class +# undef Graph +# undef RandomAccessIterator +#endif + + #endif /* BOOST_GRAPH_PROPERTIES_HPPA */ diff --git a/include/boost/graph/property_iter_range.hpp b/include/boost/graph/property_iter_range.hpp index 1e93c384..69ff7f00 100644 --- a/include/boost/graph/property_iter_range.hpp +++ b/include/boost/graph/property_iter_range.hpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include namespace boost { @@ -34,7 +34,7 @@ namespace boost { typedef typename property_map::const_type const_map_type; typedef typename property_kind::type Kind; - typedef typename ct_if::value, + typedef typename mpl::if_c::value, typename graph_traits::vertex_iterator, typename graph_traits::edge_iterator>::type iter; public: diff --git a/include/boost/graph/read_dimacs.hpp b/include/boost/graph/read_dimacs.hpp index 5f4cfe3c..4d4d1601 100644 --- a/include/boost/graph/read_dimacs.hpp +++ b/include/boost/graph/read_dimacs.hpp @@ -9,15 +9,13 @@ /* Reads maximal flow problem in extended DIMACS format. - - Reads from stdin. - This works, but could use some polishing. */ /* ----------------------------------------------------------------- */ #include +#include #include namespace boost { @@ -27,7 +25,8 @@ int read_dimacs_max_flow(Graph& g, CapacityMap capacity, ReverseEdgeMap reverse_edge, typename graph_traits::vertex_descriptor& src, - typename graph_traits::vertex_descriptor& sink) + typename graph_traits::vertex_descriptor& sink, + std::istream& in=std::cin) { // const int MAXLINE = 100; /* max line length in the input file */ const int ARC_FIELDS = 3; /* no of fields in arc line */ @@ -114,7 +113,7 @@ int read_dimacs_max_flow(Graph& g, - does service functions */ - while (std::getline(std::cin, in_line)) { + while (std::getline(in, in_line)) { ++no_lines; switch (in_line[0]) { diff --git a/include/boost/graph/relax.hpp b/include/boost/graph/relax.hpp index a3781d5e..29205d19 100644 --- a/include/boost/graph/relax.hpp +++ b/include/boost/graph/relax.hpp @@ -24,11 +24,11 @@ namespace boost { { T operator()(const T& a, const T& b) const { using namespace std; - T zero(0); - T result = a + b; - if (result < zero && a >= zero && b >= zero) - return (numeric_limits::max)(); - return result; + T zero(0); + T result = a + b; + if (result < zero && a >= zero && b >= zero) + return (numeric_limits::max)(); + return result; } }; diff --git a/include/boost/graph/reverse_graph.hpp b/include/boost/graph/reverse_graph.hpp index 06c135ff..314584fa 100644 --- a/include/boost/graph/reverse_graph.hpp +++ b/include/boost/graph/reverse_graph.hpp @@ -10,6 +10,11 @@ #include #include +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Stay out of the way of the concept checking class +# define BidirectionalGraph BidirectionalGraph_ +#endif + namespace boost { struct reverse_graph_tag { }; @@ -311,4 +316,9 @@ get_property(const reverse_graph& g, Tag tag) } // namespace boost +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Stay out of the way of the concept checking class +# undef BidirectionalGraph +#endif + #endif diff --git a/include/boost/graph/visitors.hpp b/include/boost/graph/visitors.hpp index 892f0241..2b88ed06 100644 --- a/include/boost/graph/visitors.hpp +++ b/include/boost/graph/visitors.hpp @@ -20,6 +20,11 @@ #include #include +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Stay out of the way of the concept checking class +# define Graph Graph_ +#endif + namespace boost { // This is a bit more convenient than std::numeric_limits because @@ -266,4 +271,9 @@ namespace boost { } /* namespace boost */ +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Stay out of the way of the concept checking class +# undef Graph +#endif + #endif diff --git a/include/boost/graph/write_dimacs.hpp b/include/boost/graph/write_dimacs.hpp new file mode 100644 index 00000000..0b8af17d --- /dev/null +++ b/include/boost/graph/write_dimacs.hpp @@ -0,0 +1,72 @@ +// Copyright (c) 2006, Stephan Diederich +// +// This code may be used under either of the following two licences: +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE. +// +// Or: +// +// 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) + +/* + Writes maximal flow problem in extended DIMACS format to an OutputIterator + Vertex indices are read from an IndexMap and shiftet by 1. + so their new range is [1..num_vertices(g)] +*/ + +/* ----------------------------------------------------------------- */ + +#include +#include +#include + +namespace boost { + +template +void write_dimacs_max_flow(const Graph& g, + CapacityMap capacity, + IndexMap idx, + typename graph_traits::vertex_descriptor src, + typename graph_traits::vertex_descriptor sink, + std::ostream& out) +{ + typedef typename graph_traits::vertex_descriptor vertex_descriptor; + typedef typename graph_traits::vertices_size_type vertices_size_type; + typedef typename graph_traits::edge_descriptor edge_descriptor; + typedef typename graph_traits::edges_size_type edges_size_type; + typedef typename graph_traits::edge_iterator edge_iterator; + + out << "c DIMACS max-flow file generated from boost::write_dimacs_max_flow" << std::endl; + out << "p max " << num_vertices(g) << " " << num_edges(g) << std::endl; //print problem description "max" and number of verts and edges + out << "n " << get(idx, src) + 1 << " s" << std::endl;; //say which one is source + out << "n " << get(idx, sink) + 1 << " t" << std::endl; //say which one is sink + + //output the edges + edge_iterator ei, e_end; + for(tie(ei,e_end) = edges(g); ei!=e_end; ++ei){ + out << "a " << idx[ source(*ei, g) ] + 1 << " " << idx[ target(*ei, g) ] + 1 << " " << get(capacity,*ei) << std::endl; + } +} + +} // namespace boost diff --git a/include/boost/pending/container_traits.hpp b/include/boost/pending/container_traits.hpp index 6faa831f..571eedb1 100644 --- a/include/boost/pending/container_traits.hpp +++ b/include/boost/pending/container_traits.hpp @@ -39,6 +39,12 @@ # endif #endif +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Stay out of the way of concept checking class templates +# define Container Container_ +# define AssociativeContainer AssociativeContainer_ +#endif + // The content of this file is in 'graph_detail' because otherwise // there will be name clashes with // sandbox/boost/sequence_algo/container_traits.hpp @@ -410,4 +416,10 @@ namespace boost { namespace graph_detail { }} // namespace boost::graph_detail +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Stay out of the way of concept checking class templates +# undef Container +# undef AssociativeContainer +#endif + #endif // BOOST_GRAPH_DETAIL_CONTAINER_TRAITS_H diff --git a/include/boost/pending/fibonacci_heap.hpp b/include/boost/pending/fibonacci_heap.hpp index a8ea2efe..76f28a8a 100644 --- a/include/boost/pending/fibonacci_heap.hpp +++ b/include/boost/pending/fibonacci_heap.hpp @@ -120,12 +120,14 @@ public: new_roots[r] = nil(); if (_compare(_key[u], _key[v])) { _degree[v] = r; + _mark[v] = false; std::swap(u, v); } make_child(u, v, r); ++r; } _degree[v] = r; + _mark[v] = false; } // 40 void make_child(size_type u, size_type v, size_type r) { @@ -178,7 +180,7 @@ public: if (p == nil()) { if (_compare(d, _key[_root])) _root = v; - } else if (_compare(d, _key[_root])) + } else if (_compare(d, _key[p])) while (1) { size_type r = _degree[p]; if (r >= 2) @@ -191,6 +193,7 @@ public: } if (_mark[p] == false) { _mark[p] = true; + --_degree[p]; break; } else --_degree[p]; @@ -237,7 +240,7 @@ protected: void print_recur(size_type x, std::ostream& os) { if (x != nil()) { os << x; - if (_child[x] != nil()) { + if (_degree[x] > 0) { os << "("; size_type i = _child[x]; do { diff --git a/include/boost/pending/relaxed_heap.hpp b/include/boost/pending/relaxed_heap.hpp index 0035254d..727009a6 100644 --- a/include/boost/pending/relaxed_heap.hpp +++ b/include/boost/pending/relaxed_heap.hpp @@ -13,6 +13,8 @@ #include #include #include +#include // for CHAR_BIT +#include #ifdef BOOST_RELAXED_HEAP_DEBUG # include @@ -172,14 +174,14 @@ public: value_type& top() { find_smallest(); - assert(smallest_value->value != 0); + assert(smallest_value->value != none); return *smallest_value->value; } const value_type& top() const { find_smallest(); - assert(smallest_value->value != 0); + assert(smallest_value->value != none); return *smallest_value->value; } @@ -202,7 +204,7 @@ public: rank_type r = x->rank; group* p = x->parent; { - assert(x->value != 0); + assert(x->value != none); // Find x's group size_type start = get(id, *x->value) - get(id, *x->value) % log_n; diff --git a/include/boost/pending/stringtok.hpp b/include/boost/pending/stringtok.hpp index a7065644..3b8e5e32 100644 --- a/include/boost/pending/stringtok.hpp +++ b/include/boost/pending/stringtok.hpp @@ -3,6 +3,9 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_STRINGTOK_HPP +#define BOOST_STRINGTOK_HPP + /* * stringtok.hpp -- Breaks a string into tokens. This is an example for lib3. * @@ -109,3 +112,5 @@ stringtok (Container &l, std::string const &s, char const * const ws = " \t\n") } // namespace boost + +#endif // BOOST_STRINGTOK_HPP