diff --git a/doc/find_odd_cycle.html b/doc/find_odd_cycle.html
new file mode 100644
index 00000000..f29aba48
--- /dev/null
+++ b/doc/find_odd_cycle.html
@@ -0,0 +1,152 @@
+
+
+
+
+Boost Graph Library: find_odd_cycle
+
+
+
+
+
+find_odd_cycle
+
+
+
+// Version with a colormap to retrieve the bipartition
+template <typename Graph, typename IndexMap, typename PartitionMap, typename OutputIterator>
+OutputIterator find_odd_cycle (const Graph& graph, const IndexMap index_map, PartitionMap partition_map, OutputIterator result)
+
+template <typename Graph, typename IndexMap, typename OutputIterator>
+OutputIterator find_odd_cycle (const Graph& graph, const IndexMap index_map, OutputIterator result)
+
+// Version which uses the internal index map
+template <typename Graph, typename OutputIterator>
+OutputIterator find_odd_cycle (const Graph& graph, OutputIterator result)
+
+
+
+The find_odd_cycle function tests a given graph for bipartiteness
+using a DFS-based coloring approach.
+
+
+
+An undirected graph is bipartite if one can partition its set of vertices
+into two sets "left" and "right", such that each edge goes from either side
+to the other. Obviously, a two-coloring of the graph is exactly the same as
+a two-partition. is_bipartite() tests whether such a two-coloring
+is possible and can return it in a given property map.
+
+
+
+Another equivalent characterization is the non-existance of odd-length cycles,
+meaning that a graph is bipartite if and only if it does not contain a
+cycle with an odd number of vertices as a subgraph.
+find_odd_cycle() does nearly the same as
+is_bipartite(),
+but additionally constructs an odd-length cycle if the graph is found to be
+not bipartite.
+
+
+
+The bipartition is recorded in the color map partition_map,
+which will contain a two-coloring of the graph, i.e. an assignment of
+black and white to the vertices such that no edge is monochromatic.
+The odd-length cycle is written into the Output Iterator result if
+one exists. The final final iterator is returned by the function.
+
+
+Where Defined
+
+
+boost/graph/bipartite.hpp
+
+
+Parameters
+
+
+IN: const Graph& graph
+
+
+An undirected graph. The graph type must be a model of Vertex List Graph and Incidence Graph.
+
+
+
+IN: const IndexMap index_map
+
+
+This maps each vertex to an integer in the range [0,
+num_vertices(graph)). The type VertexIndexMap
+must be a model of Readable Property
+Map. The value type of the map must be an integer type. The
+vertex descriptor type of the graph needs to be usable as the key
+type of the map.
+
+
+
+
+OUT: PartitionMap partition_map
+
+
+The algorithm tests whether the graph is bipartite and assigns each
+vertex either a white or a black color, according to the partition.
+The PartitionMap type must be a model of
+Readable Property
+Map and
+Writable Property
+Map. The value type must model ColorValue.
+
+
+
+OUT: OutputIterator result
+
+
+The find_odd_cycle function finds an odd-length cycle if the graph is
+not bipartite. The sequence of vertices producing such a cycle is written
+into this iterator. The OutputIterator type must be a model of
+
+OutputIterator. The graph's vertex descriptor type must be in the set
+of value types of the iterator. The final value is returned by the
+function. If the graph is bipartite (i.e. no odd-length cycle exists), nothing
+is written, thus the given iterator matches the return value.
+
+
+
+Complexity
+
+
+The time complexity for the algorithm is O(V + E).
+
+
+See Also
+
+
+is_bipartite()
+
+
+Example
+
+
+The file example/bipartite_example.cpp
+contains an example of testing an undirected graph for bipartiteness.
+
+
+
+
+
+
+Copyright © 2010 Matthias Walter
+(xammy@xammy.homelinux.net)
+
+
+
+
diff --git a/doc/is_bipartite.html b/doc/is_bipartite.html
new file mode 100644
index 00000000..f0a5c93e
--- /dev/null
+++ b/doc/is_bipartite.html
@@ -0,0 +1,127 @@
+
+
+
+
+Boost Graph Library: is_bipartite
+
+
+
+
+
+is_bipartite
+
+
+
+// Version with a colormap to retrieve the bipartition
+template <typename Graph, typename IndexMap, typename PartitionMap>
+bool is_bipartite (const Graph& graph, const IndexMap index_map, PartitionMap partition_map)
+
+template <typename Graph, typename IndexMap>
+bool is_bipartite (const Graph& graph, const IndexMap index_map)
+
+// Version which uses the internal index map
+template <typename Graph>
+bool is_bipartite (const Graph& graph);
+
+
+
+The is_bipartite() functions tests a given graph for
+bipartiteness using a DFS-based coloring approach.
+
+
+
+An undirected graph is bipartite if one can partition its set of vertices
+into two sets "left" and "right", such that each edge goes from either side
+to the other. Obviously, a two-coloring of the graph is exactly the same as
+a two-partition. is_bipartite() tests whether such a two-coloring
+is possible and can return it in a given property map.
+
+
+
+The bipartition is recorded in the color map partition_map,
+which will contain a two-coloring of the graph, i.e. an assignment of
+black and white to the vertices such that no edge is monochromatic.
+The predicate whether the graph is bipartite is the return value of the function.
+
+
+Where Defined
+
+
+boost/graph/bipartite.hpp
+
+
+Parameters
+
+
+IN: const Graph& graph
+
+
+An undirected graph. The graph type must be a model of Vertex List Graph and Incidence Graph.
+
+
+
+IN: const IndexMap index_map
+
+
+This maps each vertex to an integer in the range [0,
+num_vertices(graph)). The type VertexIndexMap
+must be a model of Readable Property
+Map. The value type of the map must be an integer type. The
+vertex descriptor type of the graph needs to be usable as the key
+type of the map.
+
+
+
+
+OUT: PartitionMap partition_map
+
+
+The algorithm tests whether the graph is bipartite and assigns each
+vertex either a white or a black color, according to the partition.
+The PartitionMap type must be a model of
+Readable Property
+Map and
+Writable Property
+Map The value type must model ColorValue.
+
+
+
+Complexity
+
+
+The time complexity for the algorithm is O(V + E).
+
+
+See Also
+
+
+find_odd_cycle()
+
+
+Example
+
+
+The file examples/bipartite.cpp
+contains an example of testing an undirected graph for bipartiteness.
+
+
+
+
+
+
+Copyright © 2010 Matthias Walter
+(xammy@xammy.homelinux.net)
+
+
+
+
diff --git a/doc/table_of_contents.html b/doc/table_of_contents.html
index 5cfa7191..438a07ae 100644
--- a/doc/table_of_contents.html
+++ b/doc/table_of_contents.html
@@ -265,6 +265,8 @@
- metric_tsp_approx
- sequential_vertex_coloring
+
- is_bipartite (including two-coloring of bipartite graphs)
+
- find_odd_cycle
diff --git a/example/Jamfile.v2 b/example/Jamfile.v2
index b57f8ef3..561612d0 100644
--- a/example/Jamfile.v2
+++ b/example/Jamfile.v2
@@ -20,3 +20,4 @@ exe bron_kerbosch_print_cliques : bron_kerbosch_print_cliques.cpp ;
exe bron_kerbosch_clique_number : bron_kerbosch_clique_number.cpp ;
exe mcgregor_subgraphs_example : mcgregor_subgraphs_example.cpp ;
exe grid_graph_example : grid_graph_example.cpp ;
+exe bipartite_example : bipartite_example.cpp ;
diff --git a/example/bipartite_example.cpp b/example/bipartite_example.cpp
new file mode 100644
index 00000000..b1a912e8
--- /dev/null
+++ b/example/bipartite_example.cpp
@@ -0,0 +1,115 @@
+/**
+ *
+ * Copyright (c) 2010 Matthias Walter (xammy@xammy.homelinux.net)
+ *
+ * Authors: Matthias Walter
+ *
+ * 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)
+ *
+ */
+
+#include
+#include
+#include
+
+using namespace boost;
+
+/// Example to test for bipartiteness and print the certificates.
+
+template
+void print_bipartite (const Graph& g)
+{
+ typedef graph_traits traits;
+ typename traits::vertex_iterator vertex_iter, vertex_end;
+
+ /// Most simple interface just tests for bipartiteness.
+
+ bool bipartite = is_bipartite (g);
+
+ if (bipartite)
+ {
+ typedef std::vector partition_t;
+ typedef vec_adj_list_vertex_id_map index_map_t;
+ typedef iterator_property_map partition_map_t;
+
+ partition_t partition (num_vertices (g));
+ partition_map_t partition_map (partition.begin (), get (vertex_index, g));
+
+ /// A second interface yields a bipartition in a color map, if the graph is bipartite.
+
+ is_bipartite (g, get (vertex_index, g), partition_map);
+
+ for (tie (vertex_iter, vertex_end) = vertices (g); vertex_iter != vertex_end; ++vertex_iter)
+ {
+ std::cout << "Vertex " << *vertex_iter << " has color " << (get (partition_map, *vertex_iter) == color_traits <
+ default_color_type>::white () ? "white" : "black") << std::endl;
+ }
+ }
+ else
+ {
+ typedef std::vector vertex_vector_t;
+ vertex_vector_t odd_cycle;
+
+ /// A third interface yields an odd-cycle if the graph is not bipartite.
+
+ find_odd_cycle (g, get (vertex_index, g), std::back_inserter (odd_cycle));
+
+ std::cout << "Odd cycle consists of the vertices:";
+ for (size_t i = 0; i < odd_cycle.size (); ++i)
+ {
+ std::cout << " " << odd_cycle[i];
+ }
+ std::cout << std::endl;
+ }
+}
+
+int main (int argc, char **argv)
+{
+ typedef adjacency_list vector_graph_t;
+ typedef std::pair E;
+
+ /**
+ * Create the graph drawn below.
+ *
+ * 0 - 1 - 2
+ * | |
+ * 3 - 4 - 5 - 6
+ * / \ /
+ * | 7
+ * | |
+ * 8 - 9 - 10
+ **/
+
+ E bipartite_edges[] = { E (0, 1), E (0, 4), E (1, 2), E (2, 6), E (3, 4), E (3, 8), E (4, 5), E (4, 7), E (5, 6), E (
+ 6, 7), E (7, 10), E (8, 9), E (9, 10) };
+ vector_graph_t bipartite_vector_graph (&bipartite_edges[0],
+ &bipartite_edges[0] + sizeof(bipartite_edges) / sizeof(E), 11);
+
+ /**
+ * Create the graph drawn below.
+ *
+ * 2 - 1 - 0
+ * | |
+ * 3 - 6 - 5 - 4
+ * / \ /
+ * | 7
+ * | /
+ * 8 ---- 9
+ *
+ **/
+
+ E non_bipartite_edges[] = { E (0, 1), E (0, 4), E (1, 2), E (2, 6), E (3, 6), E (3, 8), E (4, 5), E (4, 7), E (5, 6),
+ E (6, 7), E (7, 9), E (8, 9) };
+ vector_graph_t non_bipartite_vector_graph (&non_bipartite_edges[0], &non_bipartite_edges[0]
+ + sizeof(non_bipartite_edges) / sizeof(E), 10);
+
+ /// Call test routine for a bipartite and a non-bipartite graph.
+
+ print_bipartite (bipartite_vector_graph);
+
+ print_bipartite (non_bipartite_vector_graph);
+
+ return 0;
+}
diff --git a/include/boost/graph/bipartite.hpp b/include/boost/graph/bipartite.hpp
new file mode 100644
index 00000000..90cff6fe
--- /dev/null
+++ b/include/boost/graph/bipartite.hpp
@@ -0,0 +1,386 @@
+/**
+ *
+ * Copyright (c) 2010 Matthias Walter (xammy@xammy.homelinux.net)
+ *
+ * Authors: Matthias Walter
+ *
+ * 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_GRAPH_BIPARTITE_HPP
+#define BOOST_GRAPH_BIPARTITE_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+
+ namespace detail {
+
+ /**
+ * The bipartite_visitor_error is thrown if an edge cannot be colored.
+ * The witnesses are the edges incident vertices.
+ */
+
+ template
+ struct bipartite_visitor_error: std::exception
+ {
+ std::pair witnesses;
+
+ bipartite_visitor_error (Vertex a, Vertex b) :
+ witnesses (a, b)
+ {
+
+ }
+
+ const char* what () const throw ()
+ {
+ return "Graph is not bipartite.";
+ }
+ };
+
+ /**
+ * Functor which colors edges to be non-monochromatic.
+ */
+
+ template
+ struct bipartition_colorize
+ {
+ typedef on_tree_edge event_filter;
+
+ bipartition_colorize (PartitionMap partition_map) :
+ partition_map_ (partition_map)
+ {
+
+ }
+
+ template
+ void operator() (Edge e, const Graph& g)
+ {
+ typedef typename graph_traits ::vertex_descriptor vertex_descriptor_t;
+ typedef color_traits ::value_type> color_traits;
+
+ vertex_descriptor_t source_vertex = source (e, g);
+ vertex_descriptor_t target_vertex = target (e, g);
+ if (get (partition_map_, source_vertex) == color_traits::white ())
+ put (partition_map_, target_vertex, color_traits::black ());
+ else
+ put (partition_map_, target_vertex, color_traits::white ());
+ }
+
+ private:
+ PartitionMap partition_map_;
+ };
+
+ /**
+ * Creates a bipartition_colorize functor which colors edges
+ * to be non-monochromatic.
+ *
+ * @param partition_map Color map for the bipartition
+ * @return The functor.
+ */
+
+ template
+ inline bipartition_colorize colorize_bipartition (PartitionMap partition_map)
+ {
+ return bipartition_colorize (partition_map);
+ }
+
+ /**
+ * Functor which tests an edge to be monochromatic.
+ */
+
+ template
+ struct bipartition_check
+ {
+ typedef on_back_edge event_filter;
+
+ bipartition_check (PartitionMap partition_map) :
+ partition_map_ (partition_map)
+ {
+
+ }
+
+ template
+ void operator() (Edge e, const Graph& g)
+ {
+ typedef typename graph_traits ::vertex_descriptor vertex_descriptor_t;
+
+ vertex_descriptor_t source_vertex = source (e, g);
+ vertex_descriptor_t target_vertex = target (e, g);
+ if (get (partition_map_, source_vertex) == get (partition_map_, target_vertex))
+ throw bipartite_visitor_error (source_vertex, target_vertex);
+ }
+
+ private:
+ PartitionMap partition_map_;
+ };
+
+ /**
+ * Creates a bipartition_check functor which raises an error if a
+ * monochromatic edge is found.
+ *
+ * @param partition_map The map for a bipartition.
+ * @return The functor.
+ */
+
+ template
+ inline bipartition_check check_bipartition (PartitionMap partition_map)
+ {
+ return bipartition_check (partition_map);
+ }
+
+ /**
+ * Find the beginning of a common suffix of two sequences
+ *
+ * @param sequence1 Pair of bidirectional iterators defining the first sequence.
+ * @param sequence2 Pair of bidirectional iterators defining the second sequence.
+ * @return Pair of iterators pointing to the beginning of the common suffix.
+ */
+
+ template
+ inline std::pair reverse_mismatch (std::pair <
+ BiDirectionalIterator1, BiDirectionalIterator1> sequence1, std::pair sequence2)
+ {
+ if (sequence1.first == sequence1.second || sequence2.first == sequence2.second)
+ return std::make_pair (sequence1.first, sequence2.first);
+
+ BiDirectionalIterator1 iter1 = sequence1.second;
+ BiDirectionalIterator2 iter2 = sequence2.second;
+
+ while (true)
+ {
+ --iter1;
+ --iter2;
+ if (*iter1 != *iter2)
+ {
+ ++iter1;
+ ++iter2;
+ break;
+ }
+ if (iter1 == sequence1.first)
+ break;
+ if (iter2 == sequence2.first)
+ break;
+ }
+
+ return std::make_pair (iter1, iter2);
+ }
+
+ }
+
+ /**
+ * Checks a given graph for bipartiteness and fills the given color map with
+ * white and black according to the bipartition. If the graph is not
+ * bipartite, the contents of the color map are undefined. Runs in linear
+ * time in the size of the graph, if access to the property maps is in
+ * constant time.
+ *
+ * @param graph The given graph.
+ * @param index_map An index map associating vertices with an index.
+ * @param partition_map A color map to fill with the bipartition.
+ * @return true if and only if the given graph is bipartite.
+ */
+
+ template
+ bool is_bipartite (const Graph& graph, const IndexMap index_map, PartitionMap partition_map)
+ {
+ /// General types and variables
+ typedef typename property_traits ::value_type partition_color_t;
+ typedef typename graph_traits ::vertex_descriptor vertex_descriptor_t;
+ typedef typename graph_traits ::vertex_iterator vertex_iterator_t;
+
+ /// Declare dfs visitor
+ // detail::empty_recorder recorder;
+ // typedef detail::bipartite_visitor dfs_visitor_t;
+ // dfs_visitor_t dfs_visitor (partition_map, recorder);
+
+
+ /// Call dfs
+ try
+ {
+ depth_first_search (graph, vertex_index_map (index_map).visitor (make_dfs_visitor (std::make_pair (
+ detail::colorize_bipartition (partition_map), std::make_pair (detail::check_bipartition (partition_map),
+ put_property (partition_map, color_traits ::white (), on_start_vertex ()))))));
+
+ // depth_first_search (graph, vertex_index_map (index_map).visitor (dfs_visitor));
+ }
+ catch (detail::bipartite_visitor_error error)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks a given graph for bipartiteness.
+ *
+ * @param graph The given graph.
+ * @param index_map An index map associating vertices with an index.
+ * @return true if and only if the given graph is bipartite.
+ */
+
+ template
+ bool is_bipartite (const Graph& graph, const IndexMap index_map)
+ {
+ typedef one_bit_color_map partition_map_t;
+ partition_map_t partition_map (num_vertices (graph), index_map);
+
+ return is_bipartite (graph, index_map, partition_map);
+ }
+
+ /**
+ * Checks a given graph for bipartiteness. The graph must
+ * have an internal vertex_index property. Runs in linear time in the
+ * size of the graph, if access to the property maps is in constant time.
+ *
+ * @param graph The given graph.
+ * @return true if and only if the given graph is bipartite.
+ */
+
+ template
+ bool is_bipartite (const Graph& graph)
+ {
+ return is_bipartite (graph, get (vertex_index, graph));
+ }
+
+ /**
+ * Checks a given graph for bipartiteness and fills a given color map with
+ * white and black according to the bipartition. If the graph is not
+ * bipartite, a sequence of vertices, producing an odd-cycle, is written to
+ * the output iterator. The final iterator value is returned. Runs in linear
+ * time in the size of the graph, if access to the property maps is in
+ * constant time.
+ *
+ * @param graph The given graph.
+ * @param index_map An index map associating vertices with an index.
+ * @param partition_map A color map to fill with the bipartition.
+ * @param result An iterator to write the odd-cycle vertices to.
+ * @return The final iterator value after writing.
+ */
+
+ template
+ OutputIterator find_odd_cycle (const Graph& graph, const IndexMap index_map, PartitionMap partition_map,
+ OutputIterator result)
+ {
+ /// General types and variables
+ typedef typename property_traits ::value_type partition_color_t;
+ typedef typename graph_traits ::vertex_descriptor vertex_descriptor_t;
+ typedef typename graph_traits ::vertex_iterator vertex_iterator_t;
+ vertex_iterator_t vertex_iter, vertex_end;
+
+ /// Declare predecessor map
+ typedef std::vector predecessors_t;
+ typedef iterator_property_map predecessor_map_t;
+ typedef predecessor_recorder predecessor_recorder_t;
+
+ predecessors_t predecessors (num_vertices (graph), graph_traits ::null_vertex ());
+ predecessor_map_t predecessor_map (predecessors.begin (), index_map);
+ predecessor_recorder_t predecessor_recorder (predecessor_map);
+
+ /// Initialize predecessor map
+ for (tie (vertex_iter, vertex_end) = vertices (graph); vertex_iter != vertex_end; ++vertex_iter)
+ {
+ put (predecessor_map, *vertex_iter, *vertex_iter);
+ }
+
+ /// Call dfs
+ try
+ {
+ depth_first_search (graph, vertex_index_map (index_map).visitor (make_dfs_visitor (std::make_pair (
+ detail::colorize_bipartition (partition_map), std::make_pair (detail::check_bipartition (partition_map),
+ std::make_pair (put_property (partition_map, color_traits ::white (),
+ on_start_vertex ()), record_predecessors (predecessor_map, on_tree_edge ())))))));
+ }
+ catch (detail::bipartite_visitor_error error)
+ {
+ typedef std::vector path_t;
+
+ path_t path1, path2;
+ vertex_descriptor_t next, current;
+
+ /// First path
+ next = error.witnesses.first;
+ do
+ {
+ current = next;
+ path1.push_back (current);
+ next = predecessor_map[current];
+ }
+ while (current != next);
+
+ /// Second path
+ next = error.witnesses.second;
+ do
+ {
+ current = next;
+ path2.push_back (current);
+ next = predecessor_map[current];
+ }
+ while (current != next);
+
+ /// Find beginning of common suffix
+ std::pair mismatch = detail::reverse_mismatch (
+ std::make_pair (path1.begin (), path1.end ()), std::make_pair (path2.begin (), path2.end ()));
+
+ /// Copy the odd-length cycle
+ result = std::copy (path1.begin (), mismatch.first + 1, result);
+ return std::reverse_copy (path2.begin (), mismatch.second, result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Checks a given graph for bipartiteness. If the graph is not bipartite, a
+ * sequence of vertices, producing an odd-cycle, is written to the output
+ * iterator. The final iterator value is returned. Runs in linear time in the
+ * size of the graph, if access to the property maps is in constant time.
+ *
+ * @param graph The given graph.
+ * @param index_map An index map associating vertices with an index.
+ * @param result An iterator to write the odd-cycle vertices to.
+ * @return The final iterator value after writing.
+ */
+
+ template
+ OutputIterator find_odd_cycle (const Graph& graph, const IndexMap index_map, OutputIterator result)
+ {
+ typedef one_bit_color_map partition_map_t;
+ partition_map_t partition_map (num_vertices (graph), index_map);
+
+ return find_odd_cycle (graph, index_map, partition_map, result);
+ }
+
+ /**
+ * Checks a given graph for bipartiteness. If the graph is not bipartite, a
+ * sequence of vertices, producing an odd-cycle, is written to the output
+ * iterator. The final iterator value is returned. The graph must have an
+ * internal vertex_index property. Runs in linear time in the size of the
+ * graph, if access to the property maps is in constant time.
+ *
+ * @param graph The given graph.
+ * @param result An iterator to write the odd-cycle vertices to.
+ * @return The final iterator value after writing.
+ */
+
+ template
+ OutputIterator find_odd_cycle (const Graph& graph, OutputIterator result)
+ {
+ return find_odd_cycle (graph, get (vertex_index, graph), result);
+ }
+}
+
+#endif /// BOOST_GRAPH_BIPARTITE_HPP
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 1aa5bc8d..370f1653 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -36,6 +36,7 @@ test-suite graph_test :
[ run bellman-test.cpp ]
[ run betweenness_centrality_test.cpp : 100 ]
[ run bidir_remove_edge.cpp ]
+ [ run bipartite_test.cpp ]
[ run csr_graph_test.cpp : : : : : release ]
[ run dag_longest_paths.cpp ]
[ run dfs.cpp ../../test/build//boost_test_exec_monitor ]
diff --git a/test/bipartite_test.cpp b/test/bipartite_test.cpp
new file mode 100644
index 00000000..30ab5c72
--- /dev/null
+++ b/test/bipartite_test.cpp
@@ -0,0 +1,189 @@
+/**
+ *
+ * Copyright (c) 2010 Matthias Walter (xammy@xammy.homelinux.net)
+ *
+ * Authors: Matthias Walter
+ *
+ * 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)
+ *
+ */
+
+#include
+#include
+#include
+#include
+
+/// Verifies a 2-coloring
+
+template
+void check_two_coloring (const Graph& g, const ColorMap color_map)
+{
+ typedef boost::graph_traits traits;
+ typename traits::edge_iterator edge_iter, edge_end;
+
+ for (boost::tie (edge_iter, edge_end) = boost::edges (g); edge_iter != edge_end; ++edge_iter)
+ {
+ typename traits::vertex_descriptor source, target;
+ source = boost::source (*edge_iter, g);
+ target = boost::target (*edge_iter, g);
+ BOOST_REQUIRE (boost::get(color_map, source) != boost::get(color_map, target));
+ }
+}
+
+/// Tests for a vertex sequence to define an odd cycle
+
+template
+void check_odd_cycle (const Graph& g, RandomAccessIterator first, RandomAccessIterator beyond)
+{
+ typedef boost::graph_traits traits;
+
+ typename traits::vertex_descriptor first_vertex, current_vertex, last_vertex;
+
+ BOOST_CHECK ((beyond - first) % 2 == 1);
+
+ // std::cout << "odd_cycle: " << int(*first) << std::endl;
+
+ for (first_vertex = current_vertex = *first++; first != beyond; ++first)
+ {
+ // std::cout << "odd_cycle: " << int(*first) << std::endl;
+
+ last_vertex = current_vertex;
+ current_vertex = *first;
+
+ BOOST_REQUIRE (boost::lookup_edge (current_vertex, last_vertex, g).second);
+ }
+
+ BOOST_REQUIRE (boost::lookup_edge (first_vertex, current_vertex, g).second);
+}
+
+/// Call the is_bipartite and find_odd_cycle functions and verify their results.
+
+template
+void check_bipartite (const Graph& g, IndexMap index_map, bool is_bipartite)
+{
+ typedef boost::graph_traits traits;
+ typedef std::vector partition_t;
+ typedef std::vector vertex_vector_t;
+ typedef boost::iterator_property_map partition_map_t;
+
+ partition_t partition (boost::num_vertices (g));
+ partition_map_t partition_map (partition.begin (), index_map);
+
+ vertex_vector_t odd_cycle (boost::num_vertices (g));
+
+ bool first_result = boost::is_bipartite (g, index_map, partition_map);
+
+ BOOST_REQUIRE (first_result == boost::is_bipartite(g, index_map));
+
+ if (first_result)
+ check_two_coloring (g, partition_map);
+
+ BOOST_CHECK (first_result == is_bipartite);
+
+ typename vertex_vector_t::iterator second_first = odd_cycle.begin ();
+ typename vertex_vector_t::iterator second_beyond = boost::find_odd_cycle (g, index_map, partition_map, second_first);
+
+ if (is_bipartite)
+ {
+ BOOST_CHECK (second_beyond == second_first);
+ check_two_coloring (g, partition_map);
+ }
+ else
+ {
+ check_odd_cycle (g, second_first, second_beyond);
+ }
+
+ second_beyond = boost::find_odd_cycle (g, index_map, second_first);
+ if (is_bipartite)
+ {
+ BOOST_CHECK (second_beyond == second_first);
+ }
+ else
+ {
+ check_odd_cycle (g, second_first, second_beyond);
+ }
+}
+
+int test_main (int argc, char **argv)
+{
+ typedef boost::adjacency_list vector_graph_t;
+ typedef boost::adjacency_list list_graph_t;
+ typedef std::pair E;
+
+ typedef std::map ::vertex_descriptor, size_t> index_map_t;
+ typedef boost::associative_property_map index_property_map_t;
+
+ /**
+ * Create the graph drawn below.
+ *
+ * 0 - 1 - 2
+ * | |
+ * 3 - 4 - 5 - 6
+ * / \ /
+ * | 7
+ * | |
+ * 8 - 9 - 10
+ **/
+
+ E bipartite_edges[] = { E (0, 1), E (0, 4), E (1, 2), E (2, 6), E (3, 4), E (3, 8), E (4, 5), E (4, 7), E (5, 6), E (
+ 6, 7), E (7, 10), E (8, 9), E (9, 10) };
+ vector_graph_t bipartite_vector_graph (&bipartite_edges[0],
+ &bipartite_edges[0] + sizeof(bipartite_edges) / sizeof(E), 11);
+ list_graph_t
+ bipartite_list_graph (&bipartite_edges[0], &bipartite_edges[0] + sizeof(bipartite_edges) / sizeof(E), 11);
+
+ /**
+ * Create the graph drawn below.
+ *
+ * 2 - 1 - 0
+ * | |
+ * 3 - 6 - 5 - 4
+ * / \ /
+ * | 7
+ * | /
+ * 8 ---- 9
+ *
+ **/
+
+ E non_bipartite_edges[] = { E (0, 1), E (0, 4), E (1, 2), E (2, 6), E (3, 4), E (3, 8), E (4, 5), E (4, 7), E (5, 6),
+ E (6, 7), E (7, 9), E (8, 9) };
+ vector_graph_t non_bipartite_vector_graph (&non_bipartite_edges[0], &non_bipartite_edges[0]
+ + sizeof(non_bipartite_edges) / sizeof(E), 10);
+ list_graph_t non_bipartite_list_graph (&non_bipartite_edges[0], &non_bipartite_edges[0] + sizeof(non_bipartite_edges)
+ / sizeof(E), 10);
+
+ /// Create index maps
+
+ index_map_t bipartite_index_map, non_bipartite_index_map;
+ boost::graph_traits ::vertex_iterator vertex_iter, vertex_end;
+ size_t i = 0;
+ for (boost::tie (vertex_iter, vertex_end) = boost::vertices (bipartite_list_graph); vertex_iter != vertex_end; ++vertex_iter)
+ {
+ bipartite_index_map[*vertex_iter] = i++;
+ }
+ index_property_map_t bipartite_index_property_map = index_property_map_t (bipartite_index_map);
+
+ i = 0;
+ for (boost::tie (vertex_iter, vertex_end) = boost::vertices (non_bipartite_list_graph); vertex_iter != vertex_end; ++vertex_iter)
+ {
+ non_bipartite_index_map[*vertex_iter] = i++;
+ }
+ index_property_map_t non_bipartite_index_property_map = index_property_map_t (non_bipartite_index_map);
+
+ /// Call real checks
+
+ check_bipartite (bipartite_vector_graph, boost::get (boost::vertex_index, bipartite_vector_graph), true);
+ check_bipartite (bipartite_list_graph, bipartite_index_property_map, true);
+
+ check_bipartite (non_bipartite_vector_graph, boost::get (boost::vertex_index, non_bipartite_vector_graph), false);
+ check_bipartite (non_bipartite_list_graph, non_bipartite_index_property_map, false);
+
+ /// Test some more interfaces
+
+ BOOST_REQUIRE (is_bipartite (bipartite_vector_graph));
+ BOOST_REQUIRE (!is_bipartite (non_bipartite_vector_graph));
+
+ return 0;
+}