CMR  1.3.0
graphicness.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <boost/graph/bipartite.hpp>
4 #include <boost/graph/detail/set_adaptor.hpp>
5 #include <boost/graph/filtered_graph.hpp>
6 #include <boost/graph/connected_components.hpp>
7 #include <boost/graph/biconnected_components.hpp>
8 #include <boost/property_map/property_map.hpp>
9 #include <vector>
10 
11 #include "matroid_graph.hpp"
12 #include "graph_utils.hpp"
13 
14 #include <boost/graph/adjacency_list_io.hpp>
15 
16 namespace tu
17 {
18 
31  template <typename MatroidType, typename MatrixType>
32  int find_parallel_to_row(const MatroidType& matroid, const MatrixType& matrix, const size_t minor_height,
33  const size_t minor_width, const size_t row)
34  {
36  size_t last = 0;
37  size_t count = 0;
38  for (size_t c = 0; c < minor_width; ++c)
39  {
40  if (matrix(row, c) != 0)
41  {
42  last = c;
43  ++count;
44  }
45  }
46  if (count == 1)
47  return matroid.name2(last);
48 
50  for (size_t r = 0; r < minor_height; ++r)
51  {
52  bool same = true;
53  for (size_t c = 0; c < minor_width; ++c)
54  {
55  if (matrix(r, c) != matrix(row, c))
56  {
57  same = false;
58  break;
59  }
60  }
61  if (same)
62  {
63  return matroid.name1(r);
64  }
65  }
66 
67  throw std::logic_error("find_parallel_to_row did not find any parallel / unit vector!");
68  }
69 
74  template <typename Graph>
76  {
77  typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
78  typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
79  typedef std::set<edge_descriptor> edge_set;
80 
86  graph_(NULL), articulation_vertex_(NULL), evil_edges_(NULL)
87  {
88  }
89 
98  articulation_edge_filter(const Graph* graph, const vertex_descriptor* articulation_vertex,
99  const edge_set* evil_edges) :
100  graph_(graph), articulation_vertex_(articulation_vertex), evil_edges_(evil_edges)
101  {
102  }
103 
111  template <typename Edge>
112  bool operator()(const Edge& e) const
113  {
114  if (evil_edges_->find(e) != evil_edges_->end())
115  return false;
116 
117  if (boost::source(e, *graph_) == *articulation_vertex_)
118  return false;
119 
120  if (boost::target(e, *graph_) == *articulation_vertex_)
121  return false;
122 
123  return true;
124  }
125 
126  private:
127  const Graph* graph_;
128  const vertex_descriptor* articulation_vertex_;
129  const edge_set* evil_edges_;
130  };
131 
141  template <typename Graph, typename Vertex, typename EdgeSet>
142  inline struct articulation_edge_filter<Graph> make_articulation_edge_filter(const Graph* graph,
143  const Vertex* articulation_vertex, const EdgeSet* evil_edges)
144  {
145  return articulation_edge_filter<Graph> (graph, articulation_vertex, evil_edges);
146  }
147 
161  template <typename MatroidType, typename MatrixType>
162  bool extend_graph(matroid_graph& graph, const MatroidType& matroid, const MatrixType& matrix,
163  const size_t minor_height, const size_t minor_width, const nested_minor_sequence::extension_type extension_type)
164  {
165  typedef boost::graph_traits<matroid_graph> traits;
166 
167  matroid_element_map element_map = boost::get(edge_matroid_element, graph);
168  std::map<int, traits::edge_descriptor> reverse_element_map;
169 
170  typename traits::edge_iterator edge_iter, edge_end;
171  for (boost::tie(edge_iter, edge_end) = boost::edges(graph); edge_iter != edge_end; ++edge_iter)
172  {
173  reverse_element_map[element_map[*edge_iter]] = *edge_iter;
174  }
175 
177  switch (extension_type)
178  {
180  {
181  int first_edge_element = find_parallel_to_row(matroid, matrix, minor_height, minor_width, minor_height);
182  int second_edge_element = find_parallel_to_row(matroid, matrix, minor_height, minor_width, minor_height + 1);
183 
185 
186  traits::vertex_descriptor first_vertex1 = boost::source(reverse_element_map[first_edge_element], graph);
187  traits::vertex_descriptor first_vertex2 = boost::target(reverse_element_map[first_edge_element], graph);
188  traits::vertex_descriptor second_vertex1 = boost::source(reverse_element_map[second_edge_element], graph);
189  traits::vertex_descriptor second_vertex2 = boost::target(reverse_element_map[second_edge_element], graph);
190 
191  if (first_vertex1 == second_vertex2)
192  std::swap(second_vertex1, second_vertex2);
193  if (first_vertex2 == second_vertex1)
194  std::swap(first_vertex1, first_vertex2);
195  if (first_vertex2 == second_vertex2)
196  {
197  std::swap(first_vertex1, first_vertex2);
198  std::swap(second_vertex1, second_vertex2);
199  }
200  if (first_vertex1 != second_vertex1)
201  return false;
202 
204 
205  boost::remove_edge(reverse_element_map[first_edge_element], graph);
206  boost::remove_edge(reverse_element_map[second_edge_element], graph);
207 
209 
210  traits::vertex_descriptor first_breaker = boost::add_vertex(graph);
211  traits::vertex_descriptor second_breaker = boost::add_vertex(graph);
212 
214 
215  boost::add_edge(first_vertex2, first_breaker, first_edge_element, graph);
216  boost::add_edge(first_breaker, first_vertex1, matroid.name1(minor_height), graph);
217  boost::add_edge(second_vertex2, second_breaker, second_edge_element, graph);
218  boost::add_edge(second_breaker, second_vertex1, matroid.name1(minor_height + 1), graph);
219  boost::add_edge(first_breaker, second_breaker, matroid.name2(minor_width), graph);
220 
221  return true;
222  }
223  break;
225  {
227  minor_width, minor_height, minor_width);
229  minor_width, minor_height, minor_width + 1);
230 
232 
233  traits::vertex_descriptor first_vertex1 = boost::source(reverse_element_map[first_edge_element], graph);
234  traits::vertex_descriptor first_vertex2 = boost::target(reverse_element_map[first_edge_element], graph);
235  traits::vertex_descriptor second_vertex1 = boost::source(reverse_element_map[second_edge_element], graph);
236  traits::vertex_descriptor second_vertex2 = boost::target(reverse_element_map[second_edge_element], graph);
237 
238  if (first_vertex1 == second_vertex2)
239  std::swap(second_vertex1, second_vertex2);
240  if (first_vertex2 == second_vertex1)
241  std::swap(first_vertex1, first_vertex2);
242  if (first_vertex2 == second_vertex2)
243  {
244  std::swap(first_vertex1, first_vertex2);
245  std::swap(second_vertex1, second_vertex2);
246  }
247  if (first_vertex1 != second_vertex1)
248  return false;
249 
251 
252  traits::vertex_descriptor additional_vertex = boost::add_vertex(graph);
253 
255 
256  boost::add_edge(first_vertex2, additional_vertex, matroid.name2(minor_width), graph);
257  boost::add_edge(second_vertex2, additional_vertex, matroid.name2(minor_width + 1), graph);
258  boost::add_edge(first_vertex1, additional_vertex, matroid.name1(minor_height), graph);
259 
260  return true;
261  }
262  break;
264  {
265  int row_edge_element = find_parallel_to_row(matroid, matrix, minor_height, minor_width, minor_height);
267  minor_width, minor_height, minor_width);
268 
270 
271  traits::vertex_descriptor row_vertex1 = boost::source(reverse_element_map[row_edge_element], graph);
272  traits::vertex_descriptor row_vertex2 = boost::target(reverse_element_map[row_edge_element], graph);
273  traits::vertex_descriptor column_vertex1 = boost::source(reverse_element_map[column_edge_element], graph);
274  traits::vertex_descriptor column_vertex2 = boost::target(reverse_element_map[column_edge_element], graph);
275 
276  if (row_vertex1 == column_vertex2)
277  std::swap(column_vertex1, column_vertex2);
278  if (row_vertex2 == column_vertex1)
279  std::swap(row_vertex1, row_vertex2);
280  if (row_vertex2 == column_vertex2)
281  {
282  std::swap(row_vertex1, row_vertex2);
283  std::swap(column_vertex1, column_vertex2);
284  }
285  if (row_vertex1 != column_vertex1)
286  return false;
287 
289 
290  boost::remove_edge(reverse_element_map[row_edge_element], graph);
291 
293 
294  traits::vertex_descriptor row_breaker = boost::add_vertex(graph);
295 
297 
298  boost::add_edge(row_vertex2, row_breaker, row_edge_element, graph);
299  boost::add_edge(row_breaker, row_vertex1, matroid.name1(minor_height), graph);
300  boost::add_edge(row_breaker, column_vertex2, matroid.name2(minor_width), graph);
301 
302  return true;
303  }
304  break;
306  {
307  typedef std::set<traits::edge_descriptor> edge_set_t;
308  typedef boost::filtered_graph<matroid_graph, boost::is_in_subset<edge_set_t> > edge_subset_graph_t;
309 
310  edge_set_t edge_set;
311 
312  for (size_t r = 0; r < minor_height; ++r)
313  {
314  if (matrix(r, minor_width) == 1)
315  edge_set.insert(reverse_element_map[matroid.name1(r)]);
316  }
317 
319  std::vector<traits::vertex_descriptor> path;
320 
321  edge_subset_graph_t edge_subset_graph(graph, boost::is_in_subset<edge_set_t>(edge_set));
322  if (!tu::util::is_path(edge_subset_graph, boost::get(boost::vertex_index, edge_subset_graph), path))
323  {
324  return false;
325  }
326 
327  boost::add_edge(path[0], path[path.size() - 1], matroid.name2(minor_width), graph);
328  return true;
329  }
330  break;
332  {
333  typedef traits::edge_descriptor edge_t;
334  typedef traits::vertex_descriptor vertex_t;
335  typedef std::set<vertex_t> vertex_set;
336  typedef std::set<edge_t> edge_set;
337  typedef std::vector<vertex_t> vertex_vector_t;
338  typedef std::vector<edge_t> edge_vector_t;
339 
340  typedef boost::vec_adj_list_vertex_id_map<boost::no_property, traits::vertices_size_type> IndexMap;
341  IndexMap index_map = boost::get(boost::vertex_index, graph);
342 
344 
345  edge_set one_edges;
346  for (size_t c = 0; c < minor_width; ++c)
347  {
348  if (matrix(minor_height, c) != 0)
349  one_edges.insert(reverse_element_map[matroid.name2(c)]);
350  }
351 
352  traits::vertex_descriptor the_vertex = traits::null_vertex();
353  if (tu::util::find_star_vertex(boost::make_filtered_graph(graph, boost::is_in_subset<edge_set>(one_edges)),
354  the_vertex))
355  {
357 
358  traits::vertex_descriptor new_vertex = boost::add_vertex(graph);
359  boost::add_edge(the_vertex, new_vertex, matroid.name1(minor_height), graph);
360 
362 
363  for (edge_set::const_iterator edge_iter = one_edges.begin(); edge_iter != one_edges.end(); ++edge_iter)
364  {
365  traits::edge_descriptor edge = *edge_iter;
366  traits::vertex_descriptor other_vertex = boost::source(edge, graph);
367  if (other_vertex == the_vertex)
368  other_vertex = boost::target(edge, graph);
369  int name = element_map[edge];
370  boost::remove_edge(the_vertex, other_vertex, graph);
371  boost::add_edge(new_vertex, other_vertex, name, graph);
372  }
373 
374  return true;
375  }
376 
378 
379  std::vector<size_t> common_vertex_count(boost::num_vertices(graph), 0);
380  for (size_t c = 0; c < minor_width; ++c)
381  {
382  if (matrix(minor_height, c) == 0)
383  continue;
384 
385  edge_set edges;
386  for (size_t r = 0; r < minor_height; ++r)
387  {
388  if (matrix(r, c) == 1)
389  edges.insert(reverse_element_map[matroid.name1(r)]);
390  }
391 
392  vertex_set vertices;
393  tu::util::used_vertices(boost::make_filtered_graph(graph, boost::is_in_subset<edge_set>(edges)), vertices);
394 
395  for (typename vertex_set::const_iterator iter = vertices.begin(); iter != vertices.end(); ++iter)
396  {
397  common_vertex_count[boost::get(index_map, *iter)]++;
398  }
399  }
400 
402 
403  vertex_vector_t articulation_points;
404  boost::articulation_points(boost::make_filtered_graph(graph, boost::is_not_in_subset<edge_set>(one_edges)),
405  std::back_inserter(articulation_points));
406 
407  std::vector<traits::vertex_descriptor> the_vertex_candidates;
408  the_vertex = traits::null_vertex();
409  for (vertex_vector_t::const_iterator iter = articulation_points.begin(); iter != articulation_points.end();
410  ++iter)
411  {
412  if (common_vertex_count[boost::get(index_map, *iter)] == one_edges.size())
413  {
414  the_vertex_candidates.push_back(*iter);
415  }
416  }
417 
418  if (the_vertex_candidates.empty() || the_vertex_candidates.size() > 2)
419  return false;
420 
421  for (vertex_vector_t::const_iterator iter = the_vertex_candidates.begin(); iter != the_vertex_candidates.end();
422  ++iter)
423  {
424  the_vertex = *iter;
425 
427 
428  vertex_set articulation_set;
429  articulation_set.insert(the_vertex);
430  std::vector<size_t> component_vector(boost::num_vertices(graph));
431 
432  size_t num_components = boost::connected_components(
433  boost::make_filtered_graph(graph, make_articulation_edge_filter(&graph, &the_vertex, &one_edges),
434  boost::is_not_in_subset<vertex_set>(articulation_set)),
435  boost::make_iterator_property_map(component_vector.begin(), index_map));
436 
438  assert(num_components >= 2);
439 
440  typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> component_graph_t;
441  component_graph_t component_graph(num_components);
442 
443  bool abort = false;
444  for (typename edge_set::const_iterator iter = one_edges.begin(); iter != one_edges.end(); ++iter)
445  {
446  typename boost::graph_traits<component_graph_t>::vertex_descriptor source, target;
447  source = boost::source(*iter, graph);
448  target = boost::target(*iter, graph);
449  if (source == the_vertex || target == the_vertex)
450  continue;
451 
452  size_t source_component = component_vector[boost::get(index_map, source)];
453  size_t target_component = component_vector[boost::get(index_map, target)];
454 
455  if (source_component == target_component)
456  {
458  abort = true;
459  break;
460  }
461 
462  boost::add_edge(boost::vertex(source_component, component_graph),
463  boost::vertex(target_component, component_graph), component_graph);
464  }
465 
466  if (abort)
467  continue;
468 
469  boost::one_bit_color_map<boost::vec_adj_list_vertex_id_map<boost::no_property, traits::vertices_size_type> > bipartition(
470  num_components, boost::get(boost::vertex_index, component_graph));
471 
472  if (!boost::is_bipartite(component_graph, boost::get(boost::vertex_index, component_graph), bipartition))
473  {
474  continue;
475  }
476 
477  for (size_t i = 0; i < component_vector.size(); ++i)
478  {
479  if (boost::vertex(i, graph) == the_vertex)
480  continue;
481  }
482 
483  vertex_t new_vertex = boost::add_vertex(graph);
484 
485  edge_vector_t reconnect_edges;
486  typename traits::out_edge_iterator out_edge_iter, out_edge_end;
487  for (boost::tie(out_edge_iter, out_edge_end) = boost::incident_edges(the_vertex, graph);
488  out_edge_iter != out_edge_end; ++out_edge_iter)
489  {
490  vertex_t incident_vertex = boost::target(*out_edge_iter, graph);
491 
492  bool reconnect = boost::get(bipartition,
493  boost::vertex(component_vector[boost::get(index_map, incident_vertex)], component_graph))
494  != boost::one_bit_white;
495 
496  if (one_edges.find(*out_edge_iter) != one_edges.end())
497  reconnect = !reconnect;
498 
499  if (reconnect)
500  reconnect_edges.push_back(*out_edge_iter);
501  }
502 
503  for (typename edge_vector_t::const_iterator iter = reconnect_edges.begin(); iter != reconnect_edges.end();
504  ++iter)
505  {
506  util::reconnect_edge(graph, *iter, the_vertex, new_vertex);
507  }
508 
509  boost::add_edge(the_vertex, new_vertex, matroid.name1(minor_height), graph);
510 
511  return true;
512  }
513 
514  return false;
515  }
516  break;
517  default:
518  throw std::logic_error("Unknown extension in graphicness test.");
519  }
520  }
521 
532  template <typename MatroidType, typename MatrixType, typename NestedMinorSequenceType>
533  matroid_graph* construct_matroid_graph(const MatroidType& matroid, const MatrixType& matrix,
534  const NestedMinorSequenceType& nested_minors, size_t& largest_graphic_minor)
535  {
536  typedef boost::graph_traits<matroid_graph>::vertex_descriptor vertex_descriptor;
537 
539 
540  largest_graphic_minor = 0;
541  matroid_graph* graph = new matroid_graph(4);
542 
543  vertex_descriptor center_vertex = boost::vertex(0, *graph);
544  vertex_descriptor border_vertex1 = boost::vertex(1, *graph);
545  vertex_descriptor border_vertex2 = boost::vertex(2, *graph);
546  vertex_descriptor border_vertex3 = boost::vertex(3, *graph);
547 
548  boost::add_edge(center_vertex, border_vertex1, matroid.name1(0), *graph);
549  boost::add_edge(center_vertex, border_vertex2, matroid.name1(1), *graph);
550  boost::add_edge(center_vertex, border_vertex3, matroid.name2(2), *graph);
551  boost::add_edge(border_vertex1, border_vertex2, matroid.name2(0), *graph);
552  boost::add_edge(border_vertex1, border_vertex3, matroid.name2(1), *graph);
553  boost::add_edge(border_vertex2, border_vertex3, matroid.name1(2), *graph);
554 
555  size_t minor_height = 3;
556  size_t minor_width = 3;
557 
558  for (size_t i = 0; i < nested_minors.size(); ++i)
559  {
560  if (!extend_graph(*graph, matroid, matrix, minor_height, minor_width, nested_minors.get_extension(i)))
561  {
562  delete graph;
563  return NULL;
564  }
565 
566  minor_height += nested_minors.get_extension_height(i);
567  minor_width += nested_minors.get_extension_width(i);
568  largest_graphic_minor++;
569  }
570 
571  return graph;
572  }
573 
574 } /* namespace tu */
Definition: matroid.hpp:22
name_type & name2(size_t index)
Definition: matroid.hpp:116
name_type & name1(size_t index)
Definition: matroid.hpp:96
extension_type
Definition: nested_minor_sequence.hpp:24
@ ONE_ROW_ONE_COLUMN
Definition: nested_minor_sequence.hpp:28
@ ONE_ROW
Definition: nested_minor_sequence.hpp:26
@ TWO_ROWS_ONE_COLUMN
Definition: nested_minor_sequence.hpp:29
@ ONE_COLUMN
Definition: nested_minor_sequence.hpp:30
@ ONE_ROW_TWO_COLUMNS
Definition: nested_minor_sequence.hpp:27
bool find_star_vertex(const Graph &graph, const IndexMap index_map, Vertex &vertex)
Definition: graph_utils.hpp:220
bool is_path(const Graph &graph, const IndexMap index_map, VertexSequence &path)
Definition: graph_utils.hpp:151
void used_vertices(const Graph &graph, VertexSet &vertex_set)
Definition: graph_utils.hpp:296
void reconnect_edge(Graph &graph, typename boost::graph_traits< Graph >::edge_descriptor edge, typename boost::graph_traits< Graph >::vertex_descriptor old_vertex, typename boost::graph_traits< Graph >::vertex_descriptor new_vertex)
Definition: graph_utils.hpp:63
Definition: algorithm.hpp:14
matroid_graph * construct_matroid_graph(const MatroidType &matroid, const MatrixType &matrix, const NestedMinorSequenceType &nested_minors, size_t &largest_graphic_minor)
Definition: graphicness.hpp:533
boost::property_map< matroid_graph, edge_matroid_element_t >::type matroid_element_map
Definition: matroid_graph.hpp:45
bool extend_graph(matroid_graph &graph, const MatroidType &matroid, const MatrixType &matrix, const size_t minor_height, const size_t minor_width, const nested_minor_sequence::extension_type extension_type)
Definition: graphicness.hpp:162
matroid_transposed< MatroidType > make_transposed_matroid(MatroidType &matroid)
Definition: matroid_transposed.hpp:117
struct articulation_edge_filter< Graph > make_articulation_edge_filter(const Graph *graph, const Vertex *articulation_vertex, const EdgeSet *evil_edges)
Definition: graphicness.hpp:142
int find_parallel_to_row(const MatroidType &matroid, const MatrixType &matrix, const size_t minor_height, const size_t minor_width, const size_t row)
Definition: graphicness.hpp:32
matrix_transposed< MatrixType > make_transposed_matrix(MatrixType &matrix)
Definition: matrix_transposed.hpp:148
@ edge_matroid_element
Definition: matroid_graph.hpp:17
boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, boost::no_property, matroid_element_property > matroid_graph
Definition: matroid_graph.hpp:21
Definition: graphicness.hpp:76
articulation_edge_filter(const Graph *graph, const vertex_descriptor *articulation_vertex, const edge_set *evil_edges)
Definition: graphicness.hpp:98
articulation_edge_filter()
Definition: graphicness.hpp:85
boost::graph_traits< Graph >::vertex_descriptor vertex_descriptor
Definition: graphicness.hpp:77
std::set< edge_descriptor > edge_set
Definition: graphicness.hpp:79
boost::graph_traits< Graph >::edge_descriptor edge_descriptor
Definition: graphicness.hpp:78
bool operator()(const Edge &e) const
Definition: graphicness.hpp:112