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 @@
  1. metric_tsp_approx
  2. sequential_vertex_coloring +
  3. is_bipartite (including two-coloring of bipartite graphs) +
  4. 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; +}