Chris@16: /** Chris@16: * Chris@16: * Copyright (c) 2010 Matthias Walter (xammy@xammy.homelinux.net) Chris@16: * Chris@16: * Authors: Matthias Walter Chris@16: * Chris@16: * Distributed under the Boost Software License, Version 1.0. (See Chris@16: * accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: * Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_GRAPH_BIPARTITE_HPP Chris@16: #define BOOST_GRAPH_BIPARTITE_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: /** Chris@16: * The bipartite_visitor_error is thrown if an edge cannot be colored. Chris@16: * The witnesses are the edges incident vertices. Chris@16: */ Chris@16: Chris@16: template Chris@16: struct bipartite_visitor_error: std::exception Chris@16: { Chris@16: std::pair witnesses; Chris@16: Chris@16: bipartite_visitor_error (Vertex a, Vertex b) : Chris@16: witnesses (a, b) Chris@16: { Chris@16: Chris@16: } Chris@16: Chris@16: const char* what () const throw () Chris@16: { Chris@16: return "Graph is not bipartite."; Chris@16: } Chris@16: }; Chris@16: Chris@16: /** Chris@16: * Functor which colors edges to be non-monochromatic. Chris@16: */ Chris@16: Chris@16: template Chris@16: struct bipartition_colorize Chris@16: { Chris@16: typedef on_tree_edge event_filter; Chris@16: Chris@16: bipartition_colorize (PartitionMap partition_map) : Chris@16: partition_map_ (partition_map) Chris@16: { Chris@16: Chris@16: } Chris@16: Chris@16: template Chris@16: void operator() (Edge e, const Graph& g) Chris@16: { Chris@16: typedef typename graph_traits ::vertex_descriptor vertex_descriptor_t; Chris@16: typedef color_traits ::value_type> color_traits; Chris@16: Chris@16: vertex_descriptor_t source_vertex = source (e, g); Chris@16: vertex_descriptor_t target_vertex = target (e, g); Chris@16: if (get (partition_map_, source_vertex) == color_traits::white ()) Chris@16: put (partition_map_, target_vertex, color_traits::black ()); Chris@16: else Chris@16: put (partition_map_, target_vertex, color_traits::white ()); Chris@16: } Chris@16: Chris@16: private: Chris@16: PartitionMap partition_map_; Chris@16: }; Chris@16: Chris@16: /** Chris@16: * Creates a bipartition_colorize functor which colors edges Chris@16: * to be non-monochromatic. Chris@16: * Chris@16: * @param partition_map Color map for the bipartition Chris@16: * @return The functor. Chris@16: */ Chris@16: Chris@16: template Chris@16: inline bipartition_colorize colorize_bipartition (PartitionMap partition_map) Chris@16: { Chris@16: return bipartition_colorize (partition_map); Chris@16: } Chris@16: Chris@16: /** Chris@16: * Functor which tests an edge to be monochromatic. Chris@16: */ Chris@16: Chris@16: template Chris@16: struct bipartition_check Chris@16: { Chris@16: typedef on_back_edge event_filter; Chris@16: Chris@16: bipartition_check (PartitionMap partition_map) : Chris@16: partition_map_ (partition_map) Chris@16: { Chris@16: Chris@16: } Chris@16: Chris@16: template Chris@16: void operator() (Edge e, const Graph& g) Chris@16: { Chris@16: typedef typename graph_traits ::vertex_descriptor vertex_descriptor_t; Chris@16: Chris@16: vertex_descriptor_t source_vertex = source (e, g); Chris@16: vertex_descriptor_t target_vertex = target (e, g); Chris@16: if (get (partition_map_, source_vertex) == get (partition_map_, target_vertex)) Chris@16: throw bipartite_visitor_error (source_vertex, target_vertex); Chris@16: } Chris@16: Chris@16: private: Chris@16: PartitionMap partition_map_; Chris@16: }; Chris@16: Chris@16: /** Chris@16: * Creates a bipartition_check functor which raises an error if a Chris@16: * monochromatic edge is found. Chris@16: * Chris@16: * @param partition_map The map for a bipartition. Chris@16: * @return The functor. Chris@16: */ Chris@16: Chris@16: template Chris@16: inline bipartition_check check_bipartition (PartitionMap partition_map) Chris@16: { Chris@16: return bipartition_check (partition_map); Chris@16: } Chris@16: Chris@16: /** Chris@16: * Find the beginning of a common suffix of two sequences Chris@16: * Chris@16: * @param sequence1 Pair of bidirectional iterators defining the first sequence. Chris@16: * @param sequence2 Pair of bidirectional iterators defining the second sequence. Chris@16: * @return Pair of iterators pointing to the beginning of the common suffix. Chris@16: */ Chris@16: Chris@16: template Chris@16: inline std::pair reverse_mismatch (std::pair < Chris@16: BiDirectionalIterator1, BiDirectionalIterator1> sequence1, std::pair sequence2) Chris@16: { Chris@16: if (sequence1.first == sequence1.second || sequence2.first == sequence2.second) Chris@16: return std::make_pair (sequence1.first, sequence2.first); Chris@16: Chris@16: BiDirectionalIterator1 iter1 = sequence1.second; Chris@16: BiDirectionalIterator2 iter2 = sequence2.second; Chris@16: Chris@16: while (true) Chris@16: { Chris@16: --iter1; Chris@16: --iter2; Chris@16: if (*iter1 != *iter2) Chris@16: { Chris@16: ++iter1; Chris@16: ++iter2; Chris@16: break; Chris@16: } Chris@16: if (iter1 == sequence1.first) Chris@16: break; Chris@16: if (iter2 == sequence2.first) Chris@16: break; Chris@16: } Chris@16: Chris@16: return std::make_pair (iter1, iter2); Chris@16: } Chris@16: Chris@16: } Chris@16: Chris@16: /** Chris@16: * Checks a given graph for bipartiteness and fills the given color map with Chris@16: * white and black according to the bipartition. If the graph is not Chris@16: * bipartite, the contents of the color map are undefined. Runs in linear Chris@16: * time in the size of the graph, if access to the property maps is in Chris@16: * constant time. Chris@16: * Chris@16: * @param graph The given graph. Chris@16: * @param index_map An index map associating vertices with an index. Chris@16: * @param partition_map A color map to fill with the bipartition. Chris@16: * @return true if and only if the given graph is bipartite. Chris@16: */ Chris@16: Chris@16: template Chris@16: bool is_bipartite (const Graph& graph, const IndexMap index_map, PartitionMap partition_map) Chris@16: { Chris@16: /// General types and variables Chris@16: typedef typename property_traits ::value_type partition_color_t; Chris@16: typedef typename graph_traits ::vertex_descriptor vertex_descriptor_t; Chris@16: Chris@16: /// Declare dfs visitor Chris@16: // detail::empty_recorder recorder; Chris@16: // typedef detail::bipartite_visitor dfs_visitor_t; Chris@16: // dfs_visitor_t dfs_visitor (partition_map, recorder); Chris@16: Chris@16: Chris@16: /// Call dfs Chris@16: try Chris@16: { Chris@16: depth_first_search (graph, vertex_index_map (index_map).visitor (make_dfs_visitor (std::make_pair ( Chris@16: detail::colorize_bipartition (partition_map), std::make_pair (detail::check_bipartition (partition_map), Chris@16: put_property (partition_map, color_traits ::white (), on_start_vertex ())))))); Chris@16: } Chris@16: catch (detail::bipartite_visitor_error error) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: Chris@16: return true; Chris@16: } Chris@16: Chris@16: /** Chris@16: * Checks a given graph for bipartiteness. Chris@16: * Chris@16: * @param graph The given graph. Chris@16: * @param index_map An index map associating vertices with an index. Chris@16: * @return true if and only if the given graph is bipartite. Chris@16: */ Chris@16: Chris@16: template Chris@16: bool is_bipartite (const Graph& graph, const IndexMap index_map) Chris@16: { Chris@16: typedef one_bit_color_map partition_map_t; Chris@16: partition_map_t partition_map (num_vertices (graph), index_map); Chris@16: Chris@16: return is_bipartite (graph, index_map, partition_map); Chris@16: } Chris@16: Chris@16: /** Chris@16: * Checks a given graph for bipartiteness. The graph must Chris@16: * have an internal vertex_index property. Runs in linear time in the Chris@16: * size of the graph, if access to the property maps is in constant time. Chris@16: * Chris@16: * @param graph The given graph. Chris@16: * @return true if and only if the given graph is bipartite. Chris@16: */ Chris@16: Chris@16: template Chris@16: bool is_bipartite (const Graph& graph) Chris@16: { Chris@16: return is_bipartite (graph, get (vertex_index, graph)); Chris@16: } Chris@16: Chris@16: /** Chris@16: * Checks a given graph for bipartiteness and fills a given color map with Chris@16: * white and black according to the bipartition. If the graph is not Chris@16: * bipartite, a sequence of vertices, producing an odd-cycle, is written to Chris@16: * the output iterator. The final iterator value is returned. Runs in linear Chris@16: * time in the size of the graph, if access to the property maps is in Chris@16: * constant time. Chris@16: * Chris@16: * @param graph The given graph. Chris@16: * @param index_map An index map associating vertices with an index. Chris@16: * @param partition_map A color map to fill with the bipartition. Chris@16: * @param result An iterator to write the odd-cycle vertices to. Chris@16: * @return The final iterator value after writing. Chris@16: */ Chris@16: Chris@16: template Chris@16: OutputIterator find_odd_cycle (const Graph& graph, const IndexMap index_map, PartitionMap partition_map, Chris@16: OutputIterator result) Chris@16: { Chris@16: /// General types and variables Chris@16: typedef typename property_traits ::value_type partition_color_t; Chris@16: typedef typename graph_traits ::vertex_descriptor vertex_descriptor_t; Chris@16: typedef typename graph_traits ::vertex_iterator vertex_iterator_t; Chris@16: vertex_iterator_t vertex_iter, vertex_end; Chris@16: Chris@16: /// Declare predecessor map Chris@16: typedef std::vector predecessors_t; Chris@16: typedef iterator_property_map predecessor_map_t; Chris@16: Chris@16: predecessors_t predecessors (num_vertices (graph), graph_traits ::null_vertex ()); Chris@16: predecessor_map_t predecessor_map (predecessors.begin (), index_map); Chris@16: Chris@16: /// Initialize predecessor map Chris@16: for (boost::tie (vertex_iter, vertex_end) = vertices (graph); vertex_iter != vertex_end; ++vertex_iter) Chris@16: { Chris@16: put (predecessor_map, *vertex_iter, *vertex_iter); Chris@16: } Chris@16: Chris@16: /// Call dfs Chris@16: try Chris@16: { Chris@16: depth_first_search (graph, vertex_index_map (index_map).visitor (make_dfs_visitor (std::make_pair ( Chris@16: detail::colorize_bipartition (partition_map), std::make_pair (detail::check_bipartition (partition_map), Chris@16: std::make_pair (put_property (partition_map, color_traits ::white (), Chris@16: on_start_vertex ()), record_predecessors (predecessor_map, on_tree_edge ()))))))); Chris@16: } Chris@16: catch (detail::bipartite_visitor_error error) Chris@16: { Chris@16: typedef std::vector path_t; Chris@16: Chris@16: path_t path1, path2; Chris@16: vertex_descriptor_t next, current; Chris@16: Chris@16: /// First path Chris@16: next = error.witnesses.first; Chris@16: do Chris@16: { Chris@16: current = next; Chris@16: path1.push_back (current); Chris@16: next = predecessor_map[current]; Chris@16: } Chris@16: while (current != next); Chris@16: Chris@16: /// Second path Chris@16: next = error.witnesses.second; Chris@16: do Chris@16: { Chris@16: current = next; Chris@16: path2.push_back (current); Chris@16: next = predecessor_map[current]; Chris@16: } Chris@16: while (current != next); Chris@16: Chris@16: /// Find beginning of common suffix Chris@16: std::pair mismatch = detail::reverse_mismatch ( Chris@16: std::make_pair (path1.begin (), path1.end ()), std::make_pair (path2.begin (), path2.end ())); Chris@16: Chris@16: /// Copy the odd-length cycle Chris@16: result = std::copy (path1.begin (), mismatch.first + 1, result); Chris@16: return std::reverse_copy (path2.begin (), mismatch.second, result); Chris@16: } Chris@16: Chris@16: return result; Chris@16: } Chris@16: Chris@16: /** Chris@16: * Checks a given graph for bipartiteness. If the graph is not bipartite, a Chris@16: * sequence of vertices, producing an odd-cycle, is written to the output Chris@16: * iterator. The final iterator value is returned. Runs in linear time in the Chris@16: * size of the graph, if access to the property maps is in constant time. Chris@16: * Chris@16: * @param graph The given graph. Chris@16: * @param index_map An index map associating vertices with an index. Chris@16: * @param result An iterator to write the odd-cycle vertices to. Chris@16: * @return The final iterator value after writing. Chris@16: */ Chris@16: Chris@16: template Chris@16: OutputIterator find_odd_cycle (const Graph& graph, const IndexMap index_map, OutputIterator result) Chris@16: { Chris@16: typedef one_bit_color_map partition_map_t; Chris@16: partition_map_t partition_map (num_vertices (graph), index_map); Chris@16: Chris@16: return find_odd_cycle (graph, index_map, partition_map, result); Chris@16: } Chris@16: Chris@16: /** Chris@16: * Checks a given graph for bipartiteness. If the graph is not bipartite, a Chris@16: * sequence of vertices, producing an odd-cycle, is written to the output Chris@16: * iterator. The final iterator value is returned. The graph must have an Chris@16: * internal vertex_index property. Runs in linear time in the size of the Chris@16: * graph, if access to the property maps is in constant time. Chris@16: * Chris@16: * @param graph The given graph. Chris@16: * @param result An iterator to write the odd-cycle vertices to. Chris@16: * @return The final iterator value after writing. Chris@16: */ Chris@16: Chris@16: template Chris@16: OutputIterator find_odd_cycle (const Graph& graph, OutputIterator result) Chris@16: { Chris@16: return find_odd_cycle (graph, get (vertex_index, graph), result); Chris@16: } Chris@16: } Chris@16: Chris@16: #endif /// BOOST_GRAPH_BIPARTITE_HPP