• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *
3  * Copyright (c) 2010 Matthias Walter (xammy@xammy.homelinux.net)
4  *
5  * Authors: Matthias Walter
6  *
7  * Distributed under the Boost Software License, Version 1.0. (See
8  * accompanying file LICENSE_1_0.txt or copy at
9  * http://www.boost.org/LICENSE_1_0.txt)
10  *
11  */
12 
13 #ifndef BOOST_GRAPH_BIPARTITE_HPP
14 #define BOOST_GRAPH_BIPARTITE_HPP
15 
16 #include <utility>
17 #include <vector>
18 #include <exception>
19 #include <boost/graph/properties.hpp>
20 #include <boost/graph/adjacency_list.hpp>
21 #include <boost/graph/depth_first_search.hpp>
22 #include <boost/graph/one_bit_color_map.hpp>
23 #include <boost/bind.hpp>
24 
25 namespace boost
26 {
27 
28 namespace detail
29 {
30 
31     /**
32      * The bipartite_visitor_error is thrown if an edge cannot be colored.
33      * The witnesses are the edges incident vertices.
34      */
35 
36     template < typename Vertex >
37     struct BOOST_SYMBOL_VISIBLE bipartite_visitor_error : std::exception
38     {
39         std::pair< Vertex, Vertex > witnesses;
40 
bipartite_visitor_errorboost::detail::bipartite_visitor_error41         bipartite_visitor_error(Vertex a, Vertex b) : witnesses(a, b) {}
42 
whatboost::detail::bipartite_visitor_error43         const char* what() const throw() { return "Graph is not bipartite."; }
44     };
45 
46     /**
47      * Functor which colors edges to be non-monochromatic.
48      */
49 
50     template < typename PartitionMap > struct bipartition_colorize
51     {
52         typedef on_tree_edge event_filter;
53 
bipartition_colorizeboost::detail::bipartition_colorize54         bipartition_colorize(PartitionMap partition_map)
55         : partition_map_(partition_map)
56         {
57         }
58 
59         template < typename Edge, typename Graph >
operator ()boost::detail::bipartition_colorize60         void operator()(Edge e, const Graph& g)
61         {
62             typedef typename graph_traits< Graph >::vertex_descriptor
63                 vertex_descriptor_t;
64             typedef color_traits<
65                 typename property_traits< PartitionMap >::value_type >
66                 color_traits;
67 
68             vertex_descriptor_t source_vertex = source(e, g);
69             vertex_descriptor_t target_vertex = target(e, g);
70             if (get(partition_map_, source_vertex) == color_traits::white())
71                 put(partition_map_, target_vertex, color_traits::black());
72             else
73                 put(partition_map_, target_vertex, color_traits::white());
74         }
75 
76     private:
77         PartitionMap partition_map_;
78     };
79 
80     /**
81      * Creates a bipartition_colorize functor which colors edges
82      * to be non-monochromatic.
83      *
84      * @param partition_map Color map for the bipartition
85      * @return The functor.
86      */
87 
88     template < typename PartitionMap >
colorize_bipartition(PartitionMap partition_map)89     inline bipartition_colorize< PartitionMap > colorize_bipartition(
90         PartitionMap partition_map)
91     {
92         return bipartition_colorize< PartitionMap >(partition_map);
93     }
94 
95     /**
96      * Functor which tests an edge to be monochromatic.
97      */
98 
99     template < typename PartitionMap > struct bipartition_check
100     {
101         typedef on_back_edge event_filter;
102 
bipartition_checkboost::detail::bipartition_check103         bipartition_check(PartitionMap partition_map)
104         : partition_map_(partition_map)
105         {
106         }
107 
108         template < typename Edge, typename Graph >
operator ()boost::detail::bipartition_check109         void operator()(Edge e, const Graph& g)
110         {
111             typedef typename graph_traits< Graph >::vertex_descriptor
112                 vertex_descriptor_t;
113 
114             vertex_descriptor_t source_vertex = source(e, g);
115             vertex_descriptor_t target_vertex = target(e, g);
116             if (get(partition_map_, source_vertex)
117                 == get(partition_map_, target_vertex))
118                 throw bipartite_visitor_error< vertex_descriptor_t >(
119                     source_vertex, target_vertex);
120         }
121 
122     private:
123         PartitionMap partition_map_;
124     };
125 
126     /**
127      * Creates a bipartition_check functor which raises an error if a
128      * monochromatic edge is found.
129      *
130      * @param partition_map The map for a bipartition.
131      * @return The functor.
132      */
133 
134     template < typename PartitionMap >
check_bipartition(PartitionMap partition_map)135     inline bipartition_check< PartitionMap > check_bipartition(
136         PartitionMap partition_map)
137     {
138         return bipartition_check< PartitionMap >(partition_map);
139     }
140 
141     /**
142      * Find the beginning of a common suffix of two sequences
143      *
144      * @param sequence1 Pair of bidirectional iterators defining the first
145      * sequence.
146      * @param sequence2 Pair of bidirectional iterators defining the second
147      * sequence.
148      * @return Pair of iterators pointing to the beginning of the common suffix.
149      */
150 
151     template < typename BiDirectionalIterator1,
152         typename BiDirectionalIterator2 >
153     inline std::pair< BiDirectionalIterator1, BiDirectionalIterator2 >
reverse_mismatch(std::pair<BiDirectionalIterator1,BiDirectionalIterator1> sequence1,std::pair<BiDirectionalIterator2,BiDirectionalIterator2> sequence2)154     reverse_mismatch(
155         std::pair< BiDirectionalIterator1, BiDirectionalIterator1 > sequence1,
156         std::pair< BiDirectionalIterator2, BiDirectionalIterator2 > sequence2)
157     {
158         if (sequence1.first == sequence1.second
159             || sequence2.first == sequence2.second)
160             return std::make_pair(sequence1.first, sequence2.first);
161 
162         BiDirectionalIterator1 iter1 = sequence1.second;
163         BiDirectionalIterator2 iter2 = sequence2.second;
164 
165         while (true)
166         {
167             --iter1;
168             --iter2;
169             if (*iter1 != *iter2)
170             {
171                 ++iter1;
172                 ++iter2;
173                 break;
174             }
175             if (iter1 == sequence1.first)
176                 break;
177             if (iter2 == sequence2.first)
178                 break;
179         }
180 
181         return std::make_pair(iter1, iter2);
182     }
183 
184 }
185 
186 /**
187  * Checks a given graph for bipartiteness and fills the given color map with
188  * white and black according to the bipartition. If the graph is not
189  * bipartite, the contents of the color map are undefined. Runs in linear
190  * time in the size of the graph, if access to the property maps is in
191  * constant time.
192  *
193  * @param graph The given graph.
194  * @param index_map An index map associating vertices with an index.
195  * @param partition_map A color map to fill with the bipartition.
196  * @return true if and only if the given graph is bipartite.
197  */
198 
199 template < typename Graph, typename IndexMap, typename PartitionMap >
is_bipartite(const Graph & graph,const IndexMap index_map,PartitionMap partition_map)200 bool is_bipartite(
201     const Graph& graph, const IndexMap index_map, PartitionMap partition_map)
202 {
203     /// General types and variables
204     typedef
205         typename property_traits< PartitionMap >::value_type partition_color_t;
206     typedef
207         typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t;
208 
209     /// Declare dfs visitor
210     //    detail::empty_recorder recorder;
211     //    typedef detail::bipartite_visitor <PartitionMap,
212     //    detail::empty_recorder> dfs_visitor_t; dfs_visitor_t dfs_visitor
213     //    (partition_map, recorder);
214 
215     /// Call dfs
216     try
217     {
218         depth_first_search(graph,
219             vertex_index_map(index_map).visitor(make_dfs_visitor(
220                 std::make_pair(detail::colorize_bipartition(partition_map),
221                     std::make_pair(detail::check_bipartition(partition_map),
222                         put_property(partition_map,
223                             color_traits< partition_color_t >::white(),
224                             on_start_vertex()))))));
225     }
226     catch (const detail::bipartite_visitor_error< vertex_descriptor_t >&)
227     {
228         return false;
229     }
230 
231     return true;
232 }
233 
234 /**
235  * Checks a given graph for bipartiteness.
236  *
237  * @param graph The given graph.
238  * @param index_map An index map associating vertices with an index.
239  * @return true if and only if the given graph is bipartite.
240  */
241 
242 template < typename Graph, typename IndexMap >
is_bipartite(const Graph & graph,const IndexMap index_map)243 bool is_bipartite(const Graph& graph, const IndexMap index_map)
244 {
245     typedef one_bit_color_map< IndexMap > partition_map_t;
246     partition_map_t partition_map(num_vertices(graph), index_map);
247 
248     return is_bipartite(graph, index_map, partition_map);
249 }
250 
251 /**
252  * Checks a given graph for bipartiteness. The graph must
253  * have an internal vertex_index property. Runs in linear time in the
254  * size of the graph, if access to the property maps is in constant time.
255  *
256  * @param graph The given graph.
257  * @return true if and only if the given graph is bipartite.
258  */
259 
is_bipartite(const Graph & graph)260 template < typename Graph > bool is_bipartite(const Graph& graph)
261 {
262     return is_bipartite(graph, get(vertex_index, graph));
263 }
264 
265 /**
266  * Checks a given graph for bipartiteness and fills a given color map with
267  * white and black according to the bipartition. If the graph is not
268  * bipartite, a sequence of vertices, producing an odd-cycle, is written to
269  * the output iterator. The final iterator value is returned. Runs in linear
270  * time in the size of the graph, if access to the property maps is in
271  * constant time.
272  *
273  * @param graph The given graph.
274  * @param index_map An index map associating vertices with an index.
275  * @param partition_map A color map to fill with the bipartition.
276  * @param result An iterator to write the odd-cycle vertices to.
277  * @return The final iterator value after writing.
278  */
279 
280 template < typename Graph, typename IndexMap, typename PartitionMap,
281     typename OutputIterator >
find_odd_cycle(const Graph & graph,const IndexMap index_map,PartitionMap partition_map,OutputIterator result)282 OutputIterator find_odd_cycle(const Graph& graph, const IndexMap index_map,
283     PartitionMap partition_map, OutputIterator result)
284 {
285     /// General types and variables
286     typedef
287         typename property_traits< PartitionMap >::value_type partition_color_t;
288     typedef
289         typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t;
290     typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
291     vertex_iterator_t vertex_iter, vertex_end;
292 
293     /// Declare predecessor map
294     typedef std::vector< vertex_descriptor_t > predecessors_t;
295     typedef iterator_property_map< typename predecessors_t::iterator, IndexMap,
296         vertex_descriptor_t, vertex_descriptor_t& >
297         predecessor_map_t;
298 
299     predecessors_t predecessors(
300         num_vertices(graph), graph_traits< Graph >::null_vertex());
301     predecessor_map_t predecessor_map(predecessors.begin(), index_map);
302 
303     /// Initialize predecessor map
304     for (boost::tie(vertex_iter, vertex_end) = vertices(graph);
305          vertex_iter != vertex_end; ++vertex_iter)
306     {
307         put(predecessor_map, *vertex_iter, *vertex_iter);
308     }
309 
310     /// Call dfs
311     try
312     {
313         depth_first_search(graph,
314             vertex_index_map(index_map).visitor(make_dfs_visitor(
315                 std::make_pair(detail::colorize_bipartition(partition_map),
316                     std::make_pair(detail::check_bipartition(partition_map),
317                         std::make_pair(
318                             put_property(partition_map,
319                                 color_traits< partition_color_t >::white(),
320                                 on_start_vertex()),
321                             record_predecessors(
322                                 predecessor_map, on_tree_edge())))))));
323     }
324     catch (const detail::bipartite_visitor_error< vertex_descriptor_t >& error)
325     {
326         typedef std::vector< vertex_descriptor_t > path_t;
327 
328         path_t path1, path2;
329         vertex_descriptor_t next, current;
330 
331         /// First path
332         next = error.witnesses.first;
333         do
334         {
335             current = next;
336             path1.push_back(current);
337             next = predecessor_map[current];
338         } while (current != next);
339 
340         /// Second path
341         next = error.witnesses.second;
342         do
343         {
344             current = next;
345             path2.push_back(current);
346             next = predecessor_map[current];
347         } while (current != next);
348 
349         /// Find beginning of common suffix
350         std::pair< typename path_t::iterator, typename path_t::iterator >
351             mismatch = detail::reverse_mismatch(
352                 std::make_pair(path1.begin(), path1.end()),
353                 std::make_pair(path2.begin(), path2.end()));
354 
355         /// Copy the odd-length cycle
356         result = std::copy(path1.begin(), mismatch.first + 1, result);
357         return std::reverse_copy(path2.begin(), mismatch.second, result);
358     }
359 
360     return result;
361 }
362 
363 /**
364  * Checks a given graph for bipartiteness. If the graph is not bipartite, a
365  * sequence of vertices, producing an odd-cycle, is written to the output
366  * iterator. The final iterator value is returned. Runs in linear time in the
367  * size of the graph, if access to the property maps is in constant time.
368  *
369  * @param graph The given graph.
370  * @param index_map An index map associating vertices with an index.
371  * @param result An iterator to write the odd-cycle vertices to.
372  * @return The final iterator value after writing.
373  */
374 
375 template < typename Graph, typename IndexMap, typename OutputIterator >
find_odd_cycle(const Graph & graph,const IndexMap index_map,OutputIterator result)376 OutputIterator find_odd_cycle(
377     const Graph& graph, const IndexMap index_map, OutputIterator result)
378 {
379     typedef one_bit_color_map< IndexMap > partition_map_t;
380     partition_map_t partition_map(num_vertices(graph), index_map);
381 
382     return find_odd_cycle(graph, index_map, partition_map, result);
383 }
384 
385 /**
386  * Checks a given graph for bipartiteness. If the graph is not bipartite, a
387  * sequence of vertices, producing an odd-cycle, is written to the output
388  * iterator. The final iterator value is returned. The graph must have an
389  * internal vertex_index property. Runs in linear time in the size of the
390  * graph, if access to the property maps is in constant time.
391  *
392  * @param graph The given graph.
393  * @param result An iterator to write the odd-cycle vertices to.
394  * @return The final iterator value after writing.
395  */
396 
397 template < typename Graph, typename OutputIterator >
find_odd_cycle(const Graph & graph,OutputIterator result)398 OutputIterator find_odd_cycle(const Graph& graph, OutputIterator result)
399 {
400     return find_odd_cycle(graph, get(vertex_index, graph), result);
401 }
402 }
403 
404 #endif /// BOOST_GRAPH_BIPARTITE_HPP
405