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