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