Limbo
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GraphSimplification.h
Go to the documentation of this file.
1 
13 #ifndef LIMBO_ALGORITHMS_GRAPHSIMPLIFICATION_H
14 #define LIMBO_ALGORITHMS_GRAPHSIMPLIFICATION_H
15 
16 #include <iostream>
17 #include <fstream>
18 #include <vector>
19 #include <stack>
20 #include <list>
21 #include <string>
22 #include <map>
23 #include <set>
24 #include <deque>
25 #include <boost/graph/graph_concepts.hpp>
26 #include <boost/graph/graph_utility.hpp>
27 #include <boost/graph/adjacency_list.hpp>
28 #include <boost/graph/undirected_graph.hpp>
29 #include <boost/property_map/property_map.hpp>
31 #include <limbo/math/Math.h>
33 
35 namespace limbo
36 {
38 namespace algorithms
39 {
41 namespace coloring
42 {
43 
44 namespace la = ::limbo::algorithms;
45 
50 template <typename GraphType>
52 {
53  public:
55  typedef GraphType graph_type;
56  typedef typename boost::graph_traits<graph_type>::vertex_descriptor graph_vertex_type;
57  typedef typename boost::graph_traits<graph_type>::edge_descriptor graph_edge_type;
58  typedef typename boost::graph_traits<graph_type>::vertex_iterator vertex_iterator;
59  typedef typename boost::graph_traits<graph_type>::adjacency_iterator adjacency_iterator;
60  typedef typename boost::graph_traits<graph_type>::edge_iterator edge_iterator;
62 
65  GOOD,
68  };
74  NONE = 0,
78  };
82  GraphSimplification(graph_type const& g, uint32_t color_num)
83  : m_graph (g)
84  , m_color_num (color_num)
85  , m_level (NONE)
86  , m_max_merge_level(std::numeric_limits<uint32_t>::max())
87  , m_vStatus(boost::num_vertices(g), GOOD)
88  , m_vParent(boost::num_vertices(g))
89  , m_vChildren(boost::num_vertices(g))
90  , m_vHiddenVertex()
91  , m_mCompVertex()
92 // , m_vComponent(boost::num_vertices(g), std::numeric_limits<uint32_t>::max())
93 // , m_sBridgeEdge()
94  , m_mArtiPoint()
95  , m_vPrecolor(boost::num_vertices(g), -1)
96  {
97  graph_vertex_type v = 0;
98  for (typename std::vector<graph_vertex_type>::iterator it = m_vParent.begin(), ite = m_vParent.end(); it != ite; ++it, ++v)
99  (*it) = v;
100  v = 0;
101  for (typename std::vector<std::vector<graph_vertex_type> >::iterator it = m_vChildren.begin(), ite = m_vChildren.end(); it != ite; ++it, ++v)
102  it->push_back(v);
103 #ifdef DEBUG_GRAPHSIMPLIFICATION
104  assert(m_vParent.size() == boost::num_vertices(m_graph));
105  assert(m_vChildren.size() == boost::num_vertices(m_graph));
106 #endif
107  }
111 
115  template <typename Iterator>
116  void precolor(Iterator first, Iterator last)
117  {
118  m_vPrecolor.assign(first, last);
119 #ifdef DEBUG_GRAPHSIMPLIFICATION
120  assert(m_vPrecolor.size() == boost::num_vertices(m_graph));
121 #endif
122  }
123 
125  std::vector<vertex_status_type> const& status() const {return m_vStatus;}
127  std::vector<graph_vertex_type> const& parents() const {return m_vParent;}
129  std::vector<std::vector<graph_vertex_type> > const& children() const {return m_vChildren;}
131  std::stack<graph_vertex_type> const& hidden_vertices() const {return m_vHiddenVertex;}
132 
134  std::pair<graph_type, std::map<graph_vertex_type, graph_vertex_type> > simplified_graph() const;
140  bool simplified_graph_component(uint32_t comp_id, graph_type& sg, std::vector<graph_vertex_type>& vSimpl2Orig) const;
142  uint32_t num_component() const {return m_mCompVertex.size();}
143 
146  void max_merge_level(int32_t l) {m_max_merge_level = l;}
147 
150  void simplify(uint32_t level);
155  void recover(std::vector<int8_t>& vColorFlat, std::vector<std::vector<int8_t> >& mColor, std::vector<std::vector<graph_vertex_type> > const& mSimpl2Orig) const;
156 
164  void merge_subK4();
165 
167  void hide_small_degree();
168  // find all bridge edges and divided graph into components
169  //void remove_bridge();
171  void biconnected_component();
172 
175  void recover_merge_subK4(std::vector<int8_t>& vColor) const;
176  // recover color for bridges
177  // @param vColor must be partially assigned colors except simplified vertices
178  //void recover_bridge(std::vector<int8_t>& vColor) const;
179 
183  void recover_biconnected_component(std::vector<std::vector<int8_t> >& mColor, std::vector<std::vector<graph_vertex_type> > const& mSimpl2Orig) const;
188  void recover_hide_small_degree(std::vector<int8_t>& vColor);
189 
192  void write_graph_dot(std::string const& filename) const;
195  void write_simplified_graph_dot(std::string const& filename) const;
196 
197  protected:
207  void biconnected_component_recursion(graph_vertex_type v, std::deque<bool>& vVisited, std::vector<uint32_t>& vDisc,
208  std::vector<uint32_t>& vLow, std::vector<graph_vertex_type>& vParent, uint32_t& visit_time,
209  std::stack<std::pair<graph_vertex_type, graph_vertex_type> >& vEdge,
210  std::list<std::pair<graph_vertex_type, std::set<graph_vertex_type> > >& mCompVertex) const;
212  void connected_component();
216  graph_vertex_type parent(graph_vertex_type v) const
217  {
218 #ifdef DEBUG_GRAPHSIMPLIFICATION
219  assert(!this->hidden(v));
220 #endif
221  while (v != m_vParent.at(v))
222  v = m_vParent.at(v);
223  return v;
224  }
229  graph_vertex_type parent(uint32_t v, std::vector<uint32_t> const& vParent) const
230  {
231  while (v != vParent.at(v))
232  v = vParent.at(v);
233  return v;
234  }
238  bool connected_conflict(graph_vertex_type v1, graph_vertex_type v2) const
239  {
240  graph_vertex_type vp1 = this->parent(v1);
241  graph_vertex_type vp2 = this->parent(v2);
242  std::vector<graph_vertex_type> const& vChildren1 = m_vChildren.at(vp1);
243  std::vector<graph_vertex_type> const& vChildren2 = m_vChildren.at(vp2);
244  for (typename std::vector<graph_vertex_type>::const_iterator vic1 = vChildren1.begin(); vic1 != vChildren1.end(); ++vic1)
245  for (typename std::vector<graph_vertex_type>::const_iterator vic2 = vChildren2.begin(); vic2 != vChildren2.end(); ++vic2)
246  {
247  std::pair<graph_edge_type, bool> e12 = boost::edge(*vic1, *vic2, m_graph);
248  // only count conflict edge
249  if (e12.second && boost::get(boost::edge_weight, m_graph, e12.first) >= 0) return true;
250  }
251  return false;
252  }
256  bool connected_stitch(graph_vertex_type v1, graph_vertex_type v2) const
257  {
258  graph_vertex_type vp1 = this->parent(v1);
259  graph_vertex_type vp2 = this->parent(v2);
260  std::vector<graph_vertex_type> const& vChildren1 = m_vChildren.at(vp1);
261  std::vector<graph_vertex_type> const& vChildren2 = m_vChildren.at(vp2);
262  for (typename std::vector<graph_vertex_type>::const_iterator vic1 = vChildren1.begin(); vic1 != vChildren1.end(); ++vic1)
263  for (typename std::vector<graph_vertex_type>::const_iterator vic2 = vChildren2.begin(); vic2 != vChildren2.end(); ++vic2)
264  {
265  std::pair<graph_edge_type, bool> e12 = boost::edge(*vic1, *vic2, m_graph);
266  // only count conflict edge
267  if (e12.second && boost::get(boost::edge_weight, m_graph, e12.first) < 0) return true;
268  }
269  return false;
270  }
274  std::pair<graph_edge_type, bool> connected_edge(graph_vertex_type v1, graph_vertex_type v2) const
275  {
276  graph_vertex_type vp1 = this->parent(v1);
277  graph_vertex_type vp2 = this->parent(v2);
278  std::vector<graph_vertex_type> const& vChildren1 = m_vChildren.at(vp1);
279  std::vector<graph_vertex_type> const& vChildren2 = m_vChildren.at(vp2);
280  for (typename std::vector<graph_vertex_type>::const_iterator vic1 = vChildren1.begin(); vic1 != vChildren1.end(); ++vic1)
281  for (typename std::vector<graph_vertex_type>::const_iterator vic2 = vChildren2.begin(); vic2 != vChildren2.end(); ++vic2)
282  {
283  std::pair<graph_edge_type, bool> e12 = boost::edge(*vic1, *vic2, m_graph);
284  if (e12.second) return e12;
285  }
286  return std::make_pair(graph_edge_type(), false);
287  }
290  bool merged(graph_vertex_type v1) const
291  {
292  bool flag = (m_vStatus.at(v1) == MERGED);
293 #ifdef DEBUG_GRAPHSIMPLIFICATION
294  assert(flag == m_vChildren.at(v1).empty());
295  if (!flag) assert(v1 == m_vParent.at(v1));
296  else assert(v1 != m_vParent.at(v1));
297 #endif
298  return flag;
299  }
302  bool good(graph_vertex_type v1) const
303  {
304  return (m_vStatus.at(v1) == GOOD);
305  }
308  bool hidden(graph_vertex_type v1) const
309  {
310  return (m_vStatus.at(v1) == HIDDEN);
311  }
314  bool precolored(graph_vertex_type v1) const
315  {
316  return (m_vPrecolor.at(v1) >= 0);
317  }
320  bool articulation_point(graph_vertex_type v) const
321  {
322  return m_mArtiPoint.count(v);
323  }
325  bool has_precolored() const
326  {
327  for (std::vector<int8_t>::const_iterator it = m_vPrecolor.begin(); it != m_vPrecolor.end(); ++it)
328  {
329  if (*it >= 0)
330  return true;
331  }
332  return false;
333  }
336  bool check_max_merge_level(uint32_t l) const
337  {
338  return l <= m_max_merge_level;
339  }
340  graph_type const& m_graph;
341  uint32_t m_color_num;
342  uint32_t m_level;
343  uint32_t m_max_merge_level;
344  std::vector<vertex_status_type> m_vStatus;
345 
346  std::vector<graph_vertex_type> m_vParent;
347  std::vector<std::vector<graph_vertex_type> > m_vChildren;
348 
349  std::stack<graph_vertex_type> m_vHiddenVertex;
350 
351  std::vector<std::vector<graph_vertex_type> > m_mCompVertex;
352 // std::vector<uint32_t> m_vComponent; ///< component id for each vertex
353 
354 // std::set<graph_edge_type> m_sBridgeEdge; ///< bridge edges that are removed during graph division
355  std::map<graph_vertex_type, std::set<uint32_t> > m_mArtiPoint;
356 
357  std::vector<int8_t> m_vPrecolor;
358 };
359 
361 template <typename GraphType>
362 std::pair<typename GraphSimplification<GraphType>::graph_type, std::map<typename GraphSimplification<GraphType>::graph_vertex_type, typename GraphSimplification<GraphType>::graph_vertex_type> >
364 {
365  size_t vertex_cnt = 0;
366  std::map<graph_vertex_type, graph_vertex_type> mG2MG;
367  std::map<graph_vertex_type, graph_vertex_type> mMG2G;
368  vertex_iterator vi1, vie1;
369  for (boost::tie(vi1, vie1) = boost::vertices(m_graph); vi1 != vie1; ++vi1)
370  {
371  graph_vertex_type v1 = *vi1;
372  if (this->good(v1))
373  {
374  mG2MG[*vi1] = vertex_cnt;
375  mMG2G[vertex_cnt] = v1;
376  vertex_cnt += 1;
377  }
378  }
379  graph_type mg (vertex_cnt);
380 
381  edge_iterator ei, eie;
382  for (boost::tie(ei, eie) = boost::edges(m_graph); ei != eie; ++ei)
383  {
384  graph_edge_type e = *ei;
385  graph_vertex_type s = boost::source(e, m_graph);
386  graph_vertex_type t = boost::target(e, m_graph);
387  // skip edge with hidden vertices
388  if (this->hidden(s) || this->hidden(t)) continue;
389 
390  graph_vertex_type sp = this->parent(s);
391  graph_vertex_type tp = this->parent(t);
392 
393 #ifdef DEBUG_GRAPHSIMPLIFICATION
394  assert(mG2MG.count(sp));
395  assert(mG2MG.count(tp));
396 #endif
397  graph_vertex_type msp = mG2MG[sp];
398  graph_vertex_type mtp = mG2MG[tp];
399  std::pair<graph_edge_type, bool> emg = boost::edge(msp, mtp, mg);
400  if (!emg.second)
401  {
402  emg = boost::add_edge(msp, mtp, mg);
403  assert(emg.second);
404  boost::put(boost::edge_weight, mg, emg.first, boost::get(boost::edge_weight, m_graph, e));
405  }
406  else
407  {
408  // use cumulative weight
409  // this is to make sure we can still achieve small conflict number in the simplified graph
410  // no longer optimal if merge_subK4() is called
411  boost::put(
412  boost::edge_weight, mg, emg.first,
413  boost::get(boost::edge_weight, mg, emg.first) + boost::get(boost::edge_weight, m_graph, e)
414  );
415  }
416  }
417 
418  return std::make_pair(mg, mMG2G);
419 }
420 
421 template <typename GraphType>
422 bool GraphSimplification<GraphType>::simplified_graph_component(uint32_t comp_id, typename GraphSimplification<GraphType>::graph_type& simplG,
423  std::vector<typename GraphSimplification<GraphType>::graph_vertex_type>& vSimpl2Orig) const
424 {
425  if (comp_id >= m_mCompVertex.size()) return false;
426 
427  std::vector<graph_vertex_type> const& vCompVertex = m_mCompVertex[comp_id];
428 
429  graph_type sg (vCompVertex.size());
430  std::map<graph_vertex_type, graph_vertex_type> mOrig2Simpl;
431  vSimpl2Orig.assign(vCompVertex.begin(), vCompVertex.end());
432  for (uint32_t i = 0; i != vCompVertex.size(); ++i)
433  mOrig2Simpl[vCompVertex[i]] = i;
434 #ifdef DEBUG_GRAPHSIMPLIFICATION
435  std::cout << "Comp " << comp_id << ": ";
436  for (uint32_t i = 0; i != vCompVertex.size(); ++i)
437  std::cout << vCompVertex[i] << " ";
438  std::cout << std::endl;
439 #endif
440 
441  for (typename std::vector<graph_vertex_type>::const_iterator vi = vCompVertex.begin(); vi != vCompVertex.end(); ++vi)
442  {
443  graph_vertex_type v = *vi;
444  graph_vertex_type vsg = mOrig2Simpl[v];
445  assert(this->good(v));
446  bool ap = this->articulation_point(v);
447  std::vector<graph_vertex_type> const& vChildren = m_vChildren.at(v);
448  for (typename std::vector<graph_vertex_type>::const_iterator vic = vChildren.begin(); vic != vChildren.end(); ++vic)
449  {
450  graph_vertex_type vc = *vic;
451  typename boost::graph_traits<graph_type>::adjacency_iterator ui, uie;
452  for (boost::tie(ui, uie) = boost::adjacent_vertices(vc, m_graph); ui != uie; ++ui)
453  {
454  graph_vertex_type uc = *ui;
455  // skip hidden
456  if (this->hidden(uc)) continue;
457  graph_vertex_type u = this->parent(uc);
458  // skip non-good
459  if (!this->good(u)) continue;
460  else if (v >= u) continue; // avoid duplicate
461  else if (ap && !mOrig2Simpl.count(u)) continue; // skip vertex that is not in component
462  //else if (u == v) continue;
463  assert_msg(u != v, u << " == " << v);
464 
465  std::pair<graph_edge_type, bool> e = boost::edge(vc, uc, m_graph);
466  assert(e.second);
467  // skip bridge
468  //if (m_sBridgeEdge.count(e.first)) continue;
469  graph_vertex_type usg = mOrig2Simpl[u];
470  assert_msg(usg != vsg, u << "==" << v << ": " << usg << " == " << vsg);
471 
472  std::pair<graph_edge_type, bool> esg = boost::edge(vsg, usg, sg);
473  if (!esg.second)
474  {
475  esg = boost::add_edge(vsg, usg, sg);
476  assert(esg.second);
477  boost::put(boost::edge_weight, sg, esg.first, boost::get(boost::edge_weight, m_graph, e.first));
478  }
479  else
480  {
481  // use cumulative weight
482  // this is to make sure we can still achieve small conflict number in the simplified graph
483  // no longer optimal if merge_subK4() is called
484  boost::put(
485  boost::edge_weight, sg, esg.first,
486  boost::get(boost::edge_weight, sg, esg.first) + boost::get(boost::edge_weight, m_graph, e.first)
487  );
488  }
489  }
490  }
491  }
492  simplG.swap(sg);
493  return true;
494 }
495 
496 template <typename GraphType>
498 {
499  m_level = level; // record level for recover()
500  if (this->has_precolored()) // this step does not support precolored graph yet
501  m_level = m_level & (~MERGE_SUBK4) & (~BICONNECTED_COMPONENT);
502 
503  bool reconstruct = true; // whether needs to reconstruct m_mCompVertex
504 
505  if (m_level & HIDE_SMALL_DEGREE)
506  {
507  this->hide_small_degree(); // connected components are computed inside
508  reconstruct = false;
509  }
510  if (m_level & MERGE_SUBK4)
511  {
512  this->merge_subK4();
513  }
514  if (m_level & BICONNECTED_COMPONENT)
515  {
516  this->biconnected_component();
517  reconstruct = false;
518  }
519 
520  if (reconstruct) // if BICONNECTED_COMPONENT or HIDE_SMALL_DEGREE is not on, we need to construct m_mCompVertex with size 1
521  {
522  m_mCompVertex.assign(1, std::vector<graph_vertex_type>());
523  for (graph_vertex_type v = 0, ve = boost::num_vertices(m_graph); v != ve; ++v)
524  if (this->good(v))
525  m_mCompVertex[0].push_back(v);
526  }
527 }
528 
529 template <typename GraphType>
530 void GraphSimplification<GraphType>::recover(std::vector<int8_t>& vColorFlat, std::vector<std::vector<int8_t> >& mColor, std::vector<std::vector<graph_vertex_type> > const& mSimpl2Orig) const
531 {
532  // reverse order w.r.t simplify()
533  if (m_level & BICONNECTED_COMPONENT)
534  this->recover_biconnected_component(mColor, mSimpl2Orig);
535 
536  // std::map mColor to vColorFlat
537  for (uint32_t sub_comp_id = 0; sub_comp_id < mColor.size(); ++sub_comp_id)
538  {
539  std::vector<int8_t> const& vColor = mColor[sub_comp_id];
540  std::vector<graph_vertex_type> const& vSimpl2Orig = mSimpl2Orig[sub_comp_id];
541  for (uint32_t subv = 0; subv < vColor.size(); ++subv)
542  {
543  graph_vertex_type v = vSimpl2Orig[subv];
544  if (vColorFlat[v] >= 0)
545  assert(vColorFlat[v] == vColor[subv]);
546  else
547  vColorFlat[v] = vColor[subv];
548  }
549  }
550 
551  if (m_level & MERGE_SUBK4)
552  {
553  this->recover_merge_subK4(vColorFlat);
554  }
555  if (m_level & HIDE_SMALL_DEGREE)
556  {
557  // TO DO: this part has custom requirement, such as density balancing
558  // so now it is recovered manually
559  }
560 }
561 
568 template <typename GraphType>
570 {
571  // when applying this function, be aware that other merging strategies may have already been applied
572  // so m_vParent is valid
573  //
574  // merge iteratively
575  bool merge_flag; // true if merge occurs
576  do
577  {
578  merge_flag = false;
579  // traverse the neighbors of vertex 1 to find connected vertex 2 and 3
580  vertex_iterator vi1, vie1;
581  for (boost::tie(vi1, vie1) = boost::vertices(m_graph); vi1 != vie1; ++vi1)
582  {
583  graph_vertex_type v1 = *vi1;
584  // only track good vertices
585  if (!this->good(v1)) continue;
586  // find vertex 2 by searching the neighbors of vertex 1
587  std::vector<graph_vertex_type> const& vChildren1 = m_vChildren.at(v1);
588  for (typename std::vector<graph_vertex_type>::const_iterator vic1 = vChildren1.begin(); vic1 != vChildren1.end(); ++vic1)
589  {
590 #ifdef DEBUG_GRAPHSIMPLIFICATION
591  assert(vic1-vChildren1.begin() >= 0);
592 #endif
593  graph_vertex_type vc1 = *vic1;
594  adjacency_iterator vi2, vie2;
595  for (boost::tie(vi2, vie2) = boost::adjacent_vertices(vc1, m_graph); vi2 != vie2; ++vi2)
596  {
597  // skip hidden vertex
598  if (this->hidden(*vi2)) continue;
599  // skip stitch edges
600  std::pair<graph_edge_type, bool> e12 = boost::edge(vc1, *vi2, m_graph);
601  assert(e12.second);
602  if (boost::get(boost::edge_weight, m_graph, e12.first) < 0) continue;
603 
604  graph_vertex_type v2 = this->parent(*vi2);
605  // find vertex 3 by searching the neighbors of vertex 2
606  std::vector<graph_vertex_type> const& vChildren2 = m_vChildren.at(v2);
607  for (typename std::vector<graph_vertex_type>::const_iterator vic2 = vChildren2.begin(); vic2 != vChildren2.end(); ++vic2)
608  {
609  graph_vertex_type vc2 = *vic2;
610  adjacency_iterator vi3, vie3;
611  for (boost::tie(vi3, vie3) = boost::adjacent_vertices(vc2, m_graph); vi3 != vie3; ++vi3)
612  {
613  // skip hidden vertex
614  if (this->hidden(*vi3)) continue;
615  // skip stitch edges
616  std::pair<graph_edge_type, bool> e23 = boost::edge(vc2, *vi3, m_graph);
617  assert(e23.second);
618  if (boost::get(boost::edge_weight, m_graph, e23.first) < 0) continue;
619 
620  graph_vertex_type v3 = this->parent(*vi3);
621  // skip v1, v1 must be a parent
622  if (v3 == v1) continue;
623  // only connected 1 and 3 are considered
624  if (!this->connected_conflict(v1, v3)) continue;
625 
626  // find vertex 4 by searching the neighbors of vertex 3
627  std::vector<graph_vertex_type> const& vChildren3 = m_vChildren.at(v3);
628  for (typename std::vector<graph_vertex_type>::const_iterator vic3 = vChildren3.begin(); vic3 != vChildren3.end(); ++vic3)
629  {
630  graph_vertex_type vc3 = *vic3;
631  adjacency_iterator vi4, vie4;
632  for (boost::tie(vi4, vie4) = boost::adjacent_vertices(vc3, m_graph); vi4 != vie4; ++vi4)
633  {
634  // skip hidden vertex and skip precolored vertex
635  if (this->hidden(*vi4) || this->precolored(*vi4)) continue;
636  // skip stitch edges
637  std::pair<graph_edge_type, bool> e34 = boost::edge(vc3, *vi4, m_graph);
638  assert(e34.second);
639  if (boost::get(boost::edge_weight, m_graph, e34.first) < 0) continue;
640 
641  graph_vertex_type v4 = this->parent(*vi4);
642  // skip v1 or v2, v1 and v2 must be parent, and v4 must not be precolored
643  if (v4 == v1 || v4 == v2 || this->precolored(v4)) continue;
644  // vertex 2 and vertex 4 must be connected
645  // vertex 1 and vertex 4 must not be connected (K4)
646  if (!this->connected_conflict(v2, v4) || this->connected_conflict(v1, v4)) continue;
647  // check max merge level
648  if (!this->check_max_merge_level(m_vChildren[v1].size()+m_vChildren[v4].size())) continue;
649  // merge vertex 4 to vertex 1
650  m_vStatus[v4] = MERGED;
651  m_vChildren[v1].insert(m_vChildren[v1].end(), m_vChildren[v4].begin(), m_vChildren[v4].end());
652  m_vChildren[v4].resize(0); // clear and shrink to fit
653  m_vParent[v4] = v1;
654  merge_flag = true;
655 #ifdef DEBUG_GRAPHSIMPLIFICATION
656  assert(m_vStatus[v1] == GOOD);
657  //this->write_graph_dot("graph_simpl");
658 #endif
659  break;
660  }
661  if (merge_flag) break;
662  }
663  if (merge_flag) break;
664  }
665  if (merge_flag) break;
666  }
667  if (merge_flag) break;
668  }
669  if (merge_flag) break;
670  }
671  if (merge_flag) break;
672  }
673  } while (merge_flag);
674 }
675 
677 template <typename GraphType>
679 {
680  // when applying this function, be aware that other strategies may have already been applied
681  // make sure it is compatible
682 
683  bool hide_flag;
684  do
685  {
686  hide_flag = false;
687  // traverse the neighbors of vertex 1 to find connected vertex 2 and 3
688  vertex_iterator vi1, vie1;
689  for (boost::tie(vi1, vie1) = boost::vertices(m_graph); vi1 != vie1; ++vi1)
690  {
691  graph_vertex_type v1 = *vi1;
692  // only track good and uncolored vertices
693  if (!this->good(v1) || this->precolored(v1)) continue;
694  size_t conflict_degree = 0;
695  // find vertex 2 by searching the neighbors of vertex 1
696  std::vector<graph_vertex_type> const& vChildren1 = m_vChildren.at(v1);
697  for (typename std::vector<graph_vertex_type>::const_iterator vic1 = vChildren1.begin(); vic1 != vChildren1.end(); ++vic1)
698  {
699 #ifdef DEBUG_GRAPHSIMPLIFICATION
700  assert(vic1-vChildren1.begin() >= 0);
701 #endif
702  graph_vertex_type vc1 = *vic1;
703  adjacency_iterator vi2, vie2;
704  for (boost::tie(vi2, vie2) = boost::adjacent_vertices(vc1, m_graph); vi2 != vie2; ++vi2)
705  {
706  // skip hidden vertex
707  if (this->hidden(*vi2)) continue;
708  // skip stitch edges
709  std::pair<graph_edge_type, bool> e12 = boost::edge(vc1, *vi2, m_graph);
710  assert(e12.second);
711  if (boost::get(boost::edge_weight, m_graph, e12.first) < 0) continue;
712 
713  conflict_degree += 1;
714  }
715  }
716  if (conflict_degree < m_color_num) // hide v1
717  {
718  //m_vStatus[v1] = HIDDEN;
719  m_vHiddenVertex.push(v1);
720  hide_flag = true;
721  // hide all the children of v1
722  // but no need to push them to the std::stack m_vHiddenVertex
723  // v1 is also in its children
724  std::vector<graph_vertex_type> const& vChildren1 = m_vChildren.at(v1);
725  for (typename std::vector<graph_vertex_type>::const_iterator vic1 = vChildren1.begin(); vic1 != vChildren1.end(); ++vic1)
726  m_vStatus[*vic1] = HIDDEN;
727 #ifdef DEBUG_GRAPHSIMPLIFICATION
728  std::cout << "std::stack +" << v1 << std::endl;
729  assert(m_vStatus[v1] == HIDDEN);
730 #endif
731  break;
732  }
733  }
734  } while (hide_flag);
735 
736  this->connected_component();
737 }
738 
739 // refer to http://www.geeksforgeeks.org/articulation-points-or-cut-vertices-in-a-graph/
740 // for the recursive implementation
741 template <typename GraphType>
743 {
744  uint32_t vertex_num = boost::num_vertices(m_graph);
745  std::stack<graph_vertex_type> vStack; // std::stack for dfs
746  // for speed instead of memory (no bool)
747  std::deque<bool> vVisited (vertex_num, false);
748  std::vector<graph_vertex_type> vParent (vertex_num);
749  std::vector<uint32_t> vChildrenCnt (vertex_num, 0);
750  // vLow[u] = min(vDisc[u], vDisc[w]), where w is an ancestor of u
751  // there is a back edge from some descendant of u to w
752  std::vector<uint32_t> vLow (vertex_num, std::numeric_limits<uint32_t>::max()); // lowest vertex reachable from subtree under v
753  std::vector<uint32_t> vDisc(vertex_num, std::numeric_limits<uint32_t>::max()); // discovery time
754  std::deque<bool> vArtiPoint (vertex_num, false); // true if it is articulation point
755  std::stack<std::pair<graph_vertex_type, graph_vertex_type> > vEdge; // virtual edge, it can be connection between parents
756  std::list<std::pair<graph_vertex_type, std::set<graph_vertex_type> > > mCompVertex; // save bi-connected components
757  uint32_t visit_time = 0;
758 
759  // set initial parent of current vertex to itself
760  vertex_iterator vi, vie;
761  for (boost::tie(vi, vie) = boost::vertices(m_graph); vi != vie; ++vi)
762  vParent[*vi] = *vi;
763 
764  for (boost::tie(vi, vie) = boost::vertices(m_graph); vi != vie; ++vi)
765  {
766  graph_vertex_type source = *vi;
767  if (!vVisited[source])
768  {
769  biconnected_component_recursion(source, vVisited, vDisc, vLow, vParent, visit_time, vEdge, mCompVertex);
770  }
771  // if stack is not empty, pop all edges from stack
772  if (!vEdge.empty())
773  {
774  mCompVertex.push_back(std::make_pair(std::numeric_limits<graph_vertex_type>::max(), std::set<graph_vertex_type>()));
775  do
776  {
777  mCompVertex.back().second.insert(vEdge.top().first);
778  mCompVertex.back().second.insert(vEdge.top().second);
779  vEdge.pop();
780  } while (!vEdge.empty());
781  }
782  }
783  // collect articulation points
784  uint32_t comp_id = 0;
785  // reset members
786  m_mArtiPoint.clear();
787  m_mCompVertex.assign(mCompVertex.size(), std::vector<graph_vertex_type>());
788  for (typename std::list<std::pair<graph_vertex_type, std::set<graph_vertex_type> > >::const_iterator it = mCompVertex.begin(); it != mCompVertex.end(); ++it, ++comp_id)
789  {
790  graph_vertex_type vap = it->first;
791  std::set<graph_vertex_type> const& sComp = it->second;
792  if (vap < std::numeric_limits<graph_vertex_type>::max()) // valid
793  m_mArtiPoint.insert(std::make_pair(vap, std::set<uint32_t>()));
794  m_mCompVertex[comp_id].assign(sComp.begin(), sComp.end());
795  }
796  comp_id = 0;
797  for (typename std::list<std::pair<graph_vertex_type, std::set<graph_vertex_type> > >::const_iterator it = mCompVertex.begin(); it != mCompVertex.end(); ++it, ++comp_id)
798  {
799  //graph_vertex_type vap = it->first;
800  std::set<graph_vertex_type> const& sComp = it->second;
801  for (typename std::set<graph_vertex_type>::const_iterator itc = sComp.begin(); itc != sComp.end(); ++itc)
802  {
803  graph_vertex_type v = *itc;
804  if (this->articulation_point(v))
805  m_mArtiPoint[v].insert(comp_id);
806  }
807  }
808 #ifdef DEBUG_GRAPHSIMPLIFICATION
809  comp_id = 0;
810  for (typename std::list<std::pair<graph_vertex_type, std::set<graph_vertex_type> > >::const_iterator it = mCompVertex.begin(); it != mCompVertex.end(); ++it, ++comp_id)
811  {
812  graph_vertex_type vap = it->first;
813  std::set<graph_vertex_type> const& sComp = it->second;
814  std::cout << "+ articulation point " << vap << " --> comp " << comp_id << ": ";
815  for (typename std::set<graph_vertex_type>::const_iterator itc = sComp.begin(); itc != sComp.end(); ++itc)
816  std::cout << *itc << " ";
817  std::cout << std::endl;
818  }
819  for (typename std::map<graph_vertex_type, std::set<uint32_t> >::const_iterator it = m_mArtiPoint.begin(); it != m_mArtiPoint.end(); ++it)
820  {
821  graph_vertex_type vap = it->first;
822  std::set<uint32_t> const& sComp = it->second;
823  std::cout << "ap " << vap << ": ";
824  for (typename std::set<uint32_t>::const_iterator itc = sComp.begin(); itc != sComp.end(); ++itc)
825  std::cout << *itc << " ";
826  std::cout << std::endl;
827  }
828 #endif
829 }
830 
831 template <typename GraphType>
832 void GraphSimplification<GraphType>::biconnected_component_recursion(graph_vertex_type v, std::deque<bool>& vVisited, std::vector<uint32_t>& vDisc,
833  std::vector<uint32_t>& vLow, std::vector<graph_vertex_type>& vParent, uint32_t& visit_time,
834  std::stack<std::pair<graph_vertex_type, graph_vertex_type> >& vEdge,
835  std::list<std::pair<graph_vertex_type, std::set<graph_vertex_type> > >& mCompVertex) const
836 {
837  // Count of children in DFS Tree
838  uint32_t children = 0;
839 
840  // Mark the current node as visited
841  vVisited[v] = true;
842 
843  // Initialize discovery time and low value
844  vDisc[v] = vLow[v] = visit_time++;
845 
846  // Go through all vertices adjacent to this
847  if (!this->good(v)) return;
848 
849  bool isolate = true;
850  // find neighbors of all merged vertices
851  std::vector<graph_vertex_type> const& vChildren = m_vChildren.at(v);
852  for (typename std::vector<graph_vertex_type>::const_iterator vic = vChildren.begin(); vic != vChildren.end(); ++vic)
853  {
854  graph_vertex_type vc = *vic;
855  // skip hidden vertex
856  if (this->hidden(vc)) continue;
857 
858  adjacency_iterator ui, uie;
859  for (boost::tie(ui, uie) = boost::adjacent_vertices(vc, m_graph); ui != uie; ++ui)
860  {
861  graph_vertex_type uc = *ui;
862  // skip hidden vertex
863  if (this->hidden(uc)) continue;
864 
865  isolate = false;
866  graph_vertex_type u = this->parent(uc);
867  assert(this->good(u));
868 
869  // If v is not visited yet, then make it a child of u
870  // in DFS tree and recur for it
871  if (!vVisited[u])
872  {
873  ++children;
874  vParent[u] = v;
875  vEdge.push(std::make_pair(std::min(v, u), std::max(v, u)));
876  biconnected_component_recursion(u, vVisited, vDisc, vLow, vParent, visit_time, vEdge, mCompVertex);
877 
878  // Check if the subtree rooted with v has a connection to
879  // one of the ancestors of u
880  vLow[v] = std::min(vLow[v], vLow[u]);
881 
882  // u is an articulation point in following cases
883 
884  // (1) u is root of DFS tree and has two or more chilren.
885  // (2) If u is not root and low value of one of its child is more
886  // than discovery value of u.
887  if ((vParent[v] == v && children > 1)
888  || (vParent[v] != v && vLow[u] >= vDisc[v]))
889  {
890  mCompVertex.push_back(std::make_pair(v, std::set<graph_vertex_type>()));
891  while (vEdge.top().first != std::min(v, u) || vEdge.top().second != std::max(v, u))
892  {
893  mCompVertex.back().second.insert(vEdge.top().first);
894  mCompVertex.back().second.insert(vEdge.top().second);
895  vEdge.pop();
896  }
897  mCompVertex.back().second.insert(vEdge.top().first);
898  mCompVertex.back().second.insert(vEdge.top().second);
899  vEdge.pop();
900  }
901 
902  }
903  else if (u != vParent[v] && vDisc[u] < vLow[v])
904  {
905  vLow[v] = std::min(vLow[v], vDisc[u]);
906  vEdge.push(std::make_pair(std::min(v, u), std::max(v, u)));
907  }
908  }
909  }
910  // for isolated vertex, create a component
911  if (isolate)
912  {
913  mCompVertex.push_back(std::make_pair(std::numeric_limits<graph_vertex_type>::max(), std::set<graph_vertex_type>()));
914  mCompVertex.back().second.insert(v);
915  }
916 }
917 
918 template <typename GraphType>
920 {
921  // we only need to filter out hidden vertices and bridges
922  // merged vertices are not a problem because they are initially connected with their parents
923 
924  uint32_t vertex_num = boost::num_vertices(m_graph);
925  std::stack<graph_vertex_type> vStack; // std::stack for dfs
926  // for speed instead of memory (no bool)
927  std::deque<bool> vVisited (vertex_num, false);
928  uint32_t comp_id = 0;
929  std::vector<uint32_t> vComponent (vertex_num, std::numeric_limits<uint32_t>::max());
930 
931  // std::set initial parent of current vertex to itself
932  vertex_iterator vi, vie;
933  for (boost::tie(vi, vie) = boost::vertices(m_graph); vi != vie; ++vi)
934  {
935  graph_vertex_type source = *vi;
936  if (this->hidden(source)) continue;
937  if (this->articulation_point(source)) continue;
938  // skip visited vertex
939  if (vVisited[source]) continue;
940  vStack.push(source);
941  vVisited[source] = true;
942  while (!vStack.empty())
943  {
944  graph_vertex_type v = vStack.top();
945  vStack.pop();
946 #ifdef DEBUG_GRAPHSIMPLIFICATION
947  std::cout << v << " ";
948 #endif
949 
950  vComponent[v] = comp_id; // std::set component id
951 
952  // for a articulation point, do not explore the neighbors
953  if (this->articulation_point(v))
954  {
955  m_mArtiPoint[v].insert(comp_id);
956  vVisited[v] = false;
957  continue;
958  }
959 
960  adjacency_iterator ui, uie;
961  for (boost::tie(ui, uie) = boost::adjacent_vertices(v, m_graph); ui != uie; ++ui)
962  {
963  graph_vertex_type u = *ui;
964  if (this->hidden(u)) continue;
965 
966 #ifdef DEBUG_GRAPHSIMPLIFICATION
967  std::pair<graph_edge_type, bool> e = boost::edge(u, v, m_graph);
968  assert(e.second);
969 #endif
970 
971  if (!vVisited[u]) // non-visited vertex
972  {
973  vStack.push(u);
974  vVisited[u] = true;
975  }
976  }
977  }
978  comp_id += 1;
979  }
980 #ifdef DEBUG_GRAPHSIMPLIFICATION
981  std::cout << std::endl;
982 #endif
983  // explore the connection between articulation points
984  // create additional components for connected articulation pairs
985  for (typename std::map<graph_vertex_type, std::set<uint32_t> >::const_iterator vapi = m_mArtiPoint.begin(); vapi != m_mArtiPoint.end(); ++vapi)
986  {
987  graph_vertex_type v = vapi->first;
988  if (!vVisited[v])
989  {
990  adjacency_iterator ui, uie;
991  for (boost::tie(ui, uie) = boost::adjacent_vertices(v, m_graph); ui != uie; ++ui)
992  {
993  graph_vertex_type u = *ui;
994  if (this->hidden(u)) continue;
995  if (!vVisited[u] && this->articulation_point(u))
996  {
997  m_mArtiPoint[v].insert(comp_id);
998  m_mArtiPoint[u].insert(comp_id);
999 
1000 #ifdef DEBUG_GRAPHSIMPLIFICATION
1001  std::cout << "detect " << v << ", " << u << " ==> comp " << comp_id << std::endl;
1002 #endif
1003 
1004  comp_id += 1;
1005  }
1006  }
1007  vVisited[v] = true;
1008  }
1009  }
1010 
1011  // std::set m_mCompVertex
1012  m_mCompVertex.assign(comp_id, std::vector<graph_vertex_type>());
1013  for (boost::tie(vi, vie) = boost::vertices(m_graph); vi != vie; ++vi)
1014  {
1015  graph_vertex_type v = *vi;
1016  // consider good vertices only
1017  // skip articulation_point
1018  if (this->good(v) && !this->articulation_point(v))
1019  m_mCompVertex[vComponent[v]].push_back(v);
1020  }
1021  for (typename std::map<graph_vertex_type, std::set<uint32_t> >::const_iterator vapi = m_mArtiPoint.begin(); vapi != m_mArtiPoint.end(); ++vapi)
1022  {
1023  graph_vertex_type vap = vapi->first;
1024  std::set<uint32_t> const& sComp = vapi->second;
1025  for (typename std::set<uint32_t>::const_iterator itc = sComp.begin(); itc != sComp.end(); ++itc)
1026  m_mCompVertex[*itc].push_back(vap);
1027  }
1028 }
1029 
1032 template <typename GraphType>
1033 void GraphSimplification<GraphType>::recover_merge_subK4(std::vector<int8_t>& vColor) const
1034 {
1035  vertex_iterator vi, vie;
1036  for (boost::tie(vi, vie) = boost::vertices(m_graph); vi != vie; ++vi)
1037  {
1038  graph_vertex_type v = *vi;
1039  if (this->good(v))
1040  {
1041  assert(vColor[v] >= 0 && vColor[v] < (int8_t)this->m_color_num);
1042  for (uint32_t j = 0; j != m_vChildren[v].size(); ++j)
1043  {
1044  graph_vertex_type u = m_vChildren[v][j];
1045  if (v != u)
1046  vColor[u] = vColor[v];
1047  }
1048  }
1049  }
1050 }
1051 
1053 template <typename GraphType>
1054 void GraphSimplification<GraphType>::recover_biconnected_component(std::vector<std::vector<int8_t> >& mColor, std::vector<std::vector<graph_vertex_type> > const& mSimpl2Orig) const
1055 {
1056  // a single articulation point must correspond to two components
1057  // std::map<graph_vertex_type, std::pair<uint32_t, uint32_t> > m_mArtiPoint
1058  // std::vector<std::vector<graph_vertex_type> > m_mCompVertex
1059 
1060  // only contain mapping for articulation points
1061  std::vector<std::map<graph_vertex_type, graph_vertex_type> > mApOrig2Simpl (mSimpl2Orig.size());
1062  for (uint32_t i = 0; i < mSimpl2Orig.size(); ++i)
1063  {
1064  std::vector<graph_vertex_type> const& vSimpl2Orig = mSimpl2Orig[i];
1065  std::map<graph_vertex_type, graph_vertex_type>& vApOrig2Simpl = mApOrig2Simpl[i];
1066 
1067  for (uint32_t j = 0; j < vSimpl2Orig.size(); ++j)
1068  {
1069  if (m_mArtiPoint.count(vSimpl2Orig[j]))
1070  vApOrig2Simpl[vSimpl2Orig[j]] = j;
1071  }
1072  }
1073 
1074  std::vector<int32_t> vRotation (m_mCompVertex.size(), 0); // rotation amount for each component
1075  std::deque<bool> vVisited (m_mCompVertex.size(), false); // visited flag
1076  std::vector<std::set<graph_vertex_type> > vCompAp (m_mCompVertex.size()); // articulation points for each component
1077 
1078  for (typename std::map<graph_vertex_type, std::set<uint32_t> >::const_iterator vapi = m_mArtiPoint.begin(); vapi != m_mArtiPoint.end(); ++vapi)
1079  {
1080  graph_vertex_type vap = vapi->first;
1081  std::set<uint32_t> const& sComp = vapi->second;
1082  for (typename std::set<uint32_t>::const_iterator itc = sComp.begin(); itc != sComp.end(); ++itc)
1083  {
1084  uint32_t comp = *itc;
1085  vCompAp[comp].insert(vap);
1086  //assert(vCompAp[comp].size() < 3);
1087  }
1088  }
1089 
1090  // dfs based approach to propagate rotation
1091  for (uint32_t comp_id = 0; comp_id < vCompAp.size(); ++comp_id)
1092  {
1093  if (!vVisited[comp_id])
1094  {
1095  std::stack<uint32_t> vStack;
1096  vStack.push(comp_id);
1097  vVisited[comp_id] = true;
1098  while (!vStack.empty())
1099  {
1100  uint32_t c = vStack.top(); // current component
1101  vStack.pop();
1102 
1103  for (typename std::set<graph_vertex_type>::const_iterator vapi = vCompAp[c].begin(); vapi != vCompAp[c].end(); ++vapi)
1104  {
1105  graph_vertex_type vap = *vapi;
1106  std::set<uint32_t> const& sComp = m_mArtiPoint.at(vap);
1107 
1108  for (typename std::set<uint32_t>::const_iterator itcc = sComp.begin(); itcc != sComp.end(); ++itcc)
1109  {
1110  uint32_t cc = *itcc; // child component
1111  if (!vVisited[cc])
1112  {
1113  vStack.push(cc);
1114  vVisited[cc] = true;
1115  int8_t color_c = mColor[c][mApOrig2Simpl[c][vap]];
1116  int8_t color_cc = mColor[cc][mApOrig2Simpl[cc][vap]];
1117  vRotation[cc] += vRotation[c] + color_c - color_cc;
1118  }
1119  }
1120  }
1121  }
1122  }
1123  }
1124 
1125  // apply color rotation
1126  for (uint32_t comp_id = 0; comp_id < mColor.size(); ++comp_id)
1127  {
1128  std::vector<int8_t>& vColor = mColor[comp_id];
1129  int32_t rotation = vRotation[comp_id];
1130  if (rotation < 0) // add a large enough K*m to achieve positive value
1131  rotation += (limbo::abs(rotation)/m_color_num+1)*m_color_num;
1132  assert(rotation >= 0);
1133  rotation %= (int32_t)m_color_num;
1134  for (uint32_t v = 0; v < vColor.size(); ++v)
1135  {
1136  assert(vColor[v] >= 0);
1137  vColor[v] = (vColor[v] + rotation) % (int32_t)m_color_num;
1138  }
1139  }
1140 
1141 #ifdef DEBUG_GRAPHSIMPLIFICATION
1142  for (typename std::map<graph_vertex_type, std::set<uint32_t> >::const_iterator vapi = m_mArtiPoint.begin(); vapi != m_mArtiPoint.end(); ++vapi)
1143  {
1144  graph_vertex_type vap = vapi->first;
1145  std::set<uint32_t> const& sComp = vapi->second;
1146 
1147  int8_t prev_color = -1;
1148  for (typename std::set<uint32_t>::const_iterator itc = sComp.begin(); itc != sComp.end(); ++itc)
1149  {
1150  uint32_t comp = *itc;
1151  int8_t color = mColor[comp][mApOrig2Simpl[comp][vap]];
1152  if (itc == sComp.begin())
1153  prev_color = color;
1154  else assert_msg(prev_color == color,
1155  vap << ": " << "comp " << comp << ", c[" << mApOrig2Simpl[comp][vap] << "] = " << color << "; "
1156  << "prev_color = " << prev_color);
1157  }
1158  }
1159 #endif
1160 }
1161 
1162 template <typename GraphType>
1164 {
1165  while (!m_vHiddenVertex.empty())
1166  {
1167  graph_vertex_type v = m_vHiddenVertex.top();
1168  m_vHiddenVertex.pop();
1169 
1170  // find available colors
1171  std::vector<char> vUnusedColor (m_color_num, true);
1172  typename boost::graph_traits<graph_type>::adjacency_iterator vi, vie;
1173  for (boost::tie(vi, vie) = boost::adjacent_vertices(v, this->m_graph); vi != vie; ++vi)
1174  {
1175  graph_vertex_type u = *vi;
1176  if (vColor[u] >= 0)
1177  vUnusedColor[vColor[u]] = false;
1178  }
1179 
1180  // choose the first available color
1181  for (int8_t i = 0; i != (int8_t)m_color_num; ++i)
1182  {
1183  if (vUnusedColor[i])
1184  {
1185  vColor[v] = i;
1186  break;
1187  }
1188  }
1189  assert(vColor[v] >= 0 && vColor[v] < (int8_t)m_color_num);
1190  }
1191 }
1192 
1193 template <typename GraphType>
1194 void GraphSimplification<GraphType>::write_graph_dot(std::string const& filename) const
1195 {
1196  std::ofstream out((filename+".gv").c_str());
1197  out << "graph D { \n"
1198  << " randir = LR\n"
1199  << " size=\"4, 3\"\n"
1200  << " ratio=\"fill\"\n"
1201  << " edge[style=\"bold\",fontsize=200]\n"
1202  << " node[shape=\"circle\",fontsize=200]\n";
1203 
1204  //output nodes
1205  vertex_iterator vi1, vie1;
1206  for (boost::tie(vi1, vie1) = boost::vertices(m_graph); vi1 != vie1; ++vi1)
1207  {
1208  graph_vertex_type v1 = *vi1;
1209  if (!this->good(v1)) continue;
1210 
1211  out << " " << v1 << "[shape=\"circle\"";
1212  //output coloring label
1213  out << ",label=\"" << v1 << ":(";
1214  for (typename std::vector<graph_vertex_type>::const_iterator it1 = m_vChildren[v1].begin(); it1 != m_vChildren[v1].end(); ++it1)
1215  {
1216  if (it1 != m_vChildren[v1].begin())
1217  out << ",";
1218  out << *it1;
1219  }
1220  out << ")\"]\n";
1221  }
1222 
1223  //output edges
1224  for (boost::tie(vi1, vie1) = boost::vertices(m_graph); vi1 != vie1; ++vi1)
1225  {
1226  graph_vertex_type v1 = *vi1;
1227  if (!this->good(v1)) continue;
1228 
1229  vertex_iterator vi2, vie2;
1230  for (boost::tie(vi2, vie2) = boost::vertices(m_graph); vi2 != vie2; ++vi2)
1231  {
1232  graph_vertex_type v2 = *vi2;
1233  if (!this->good(v2)) continue;
1234  if (v1 >= v2) continue;
1235 
1236  std::pair<graph_edge_type, bool> e = this->connected_edge(v1, v2);
1237  if (e.second)
1238  {
1239  // if two hyper vertices are connected by conflict edges,
1240  // there is no need to consider stitch edges
1241  if (this->connected_conflict(v1, v2))
1242  out << " " << v1 << "--" << v2 << "[color=\"black\",style=\"solid\",penwidth=3]\n";
1243  else if (this->connected_stitch(v1, v2))
1244  out << " " << v1 << "--" << v2 << "[color=\"black\",style=\"dashed\",penwidth=3]\n";
1245  // virtual connection showing that a bridge exists
1246  out << " " << v1 << "--" << v2 << "[color=\"black\",style=\"dotted\",penwidth=1]\n";
1247  }
1248  }
1249  }
1250  out << "}";
1251  out.close();
1252 
1253  la::graphviz2pdf(filename);
1254 }
1255 template <typename GraphType>
1256 void GraphSimplification<GraphType>::write_simplified_graph_dot(std::string const& filename) const
1257 {
1258  std::ofstream out((filename+".gv").c_str());
1259  out << "graph D { \n"
1260  << " randir = LR\n"
1261  << " size=\"4, 3\"\n"
1262  << " ratio=\"fill\"\n"
1263  << " edge[style=\"bold\",fontsize=200]\n"
1264  << " node[shape=\"circle\",fontsize=200]\n";
1265 
1266  uint32_t offset = 0;
1267  // component by component
1268  for (uint32_t comp_id = 0; comp_id != m_mCompVertex.size(); ++comp_id)
1269  {
1270  graph_type sg;
1271  std::vector<graph_vertex_type> vSimpl2Orig;
1272  bool flag = this->simplified_graph_component(comp_id, sg, vSimpl2Orig);
1273  if (flag)
1274  {
1275  //output nodes
1276  vertex_iterator vi1, vie1;
1277  for (boost::tie(vi1, vie1) = boost::vertices(sg); vi1 != vie1; ++vi1)
1278  {
1279  graph_vertex_type mv1 = *vi1;
1280  graph_vertex_type v1 = vSimpl2Orig[mv1];
1281  if (m_vChildren[v1].empty()) continue;
1282 
1283  out << " " << offset+mv1 << "[shape=\"circle\"";
1284  //output coloring label
1285  out << ",label=\"" << mv1 << ":(";
1286  for (typename std::vector<graph_vertex_type>::const_iterator it1 = m_vChildren[v1].begin(); it1 != m_vChildren[v1].end(); ++it1)
1287  {
1288  if (it1 != m_vChildren[v1].begin())
1289  out << ",";
1290  out << *it1;
1291  }
1292  out << "):" << comp_id << "\"]\n";
1293  }
1294  //output edges
1295  edge_iterator ei, eie;
1296  for (boost::tie(ei, eie) = boost::edges(sg); ei != eie; ++ei)
1297  {
1298  graph_edge_type e = *ei;
1299  graph_vertex_type mv1 = boost::source(e, sg);
1300  graph_vertex_type mv2 = boost::target(e, sg);
1301  int32_t w = boost::get(boost::edge_weight, sg, e);
1302  assert_msg(mv1 != mv2, mv1 << " == " << mv2);
1303 
1304  char buf[256];
1305  if (w >= 0)
1306  sprintf(buf, " %lu--%lu[label=%d,color=\"black\",style=\"solid\",penwidth=3]", offset+mv1, offset+mv2, w);
1307  else
1308  sprintf(buf, " %lu--%lu[label=%d,color=\"black\",style=\"dashed\",penwidth=3]", offset+mv1, offset+mv2, w);
1309  out << buf << std::endl;
1310  }
1311  offset += boost::num_vertices(sg);
1312  }
1313  }
1314 
1315  out << "}";
1316  out.close();
1317 
1318  la::graphviz2pdf(filename);
1319 }
1320 
1321 } // namespace coloring
1322 } // namespace algorithms
1323 } // namespace limbo
1324 
1325 #endif
1326 
std::vector< std::vector< graph_vertex_type > > m_vChildren
children verices of current vertex, a vertex is the child of itself if it is not merged ...
uint32_t m_max_merge_level
in MERGE_SUBK4, any merge that results in the children number of a vertex larger than m_max_merge_lev...
Boost.Geometry.
Definition: GdsObjects.h:724
std::map< graph_vertex_type, std::set< uint32_t > > m_mArtiPoint
map of (vertex of articulation point, set of components split by the vertex)
void biconnected_component()
find all articulation points and biconnected components
strategy_type
simplification strategies available. These strategies are order-sensitive. It is recommended to call ...
GraphSimplification(graph_type const &g, uint32_t color_num)
T abs(T const &t)
generalized api can handle both integer and floating points
Definition: Math.h:21
void write_simplified_graph_dot(std::string const &filename) const
std::vector< std::vector< graph_vertex_type > > m_mCompVertex
group vertices by components
std::stack< graph_vertex_type > const & hidden_vertices() const
std::vector< graph_vertex_type > const & parents() const
graph_vertex_type parent(uint32_t v, std::vector< uint32_t > const &vParent) const
void recover_merge_subK4(std::vector< int8_t > &vColor) const
void recover(std::vector< int8_t > &vColorFlat, std::vector< std::vector< int8_t > > &mColor, std::vector< std::vector< graph_vertex_type > > const &mSimpl2Orig) const
std::vector< vertex_status_type > const & status() const
assertion with message
void connected_component()
compute connected components
void biconnected_component_recursion(graph_vertex_type v, std::deque< bool > &vVisited, std::vector< uint32_t > &vDisc, std::vector< uint32_t > &vLow, std::vector< graph_vertex_type > &vParent, uint32_t &visit_time, std::stack< std::pair< graph_vertex_type, graph_vertex_type > > &vEdge, std::list< std::pair< graph_vertex_type, std::set< graph_vertex_type > > > &mCompVertex) const
std::pair< graph_type, std::map< graph_vertex_type, graph_vertex_type > > simplified_graph() const
void hide_small_degree()
hide vertices whose degree is no larger than number of colors - 1
std::vector< vertex_status_type > m_vStatus
status of each vertex
void precolor(Iterator first, Iterator last)
some graph utilities such as compute complement graph and graphviz writer.
std::vector< graph_vertex_type > m_vParent
parent vertex of current vertex
graph_vertex_type parent(graph_vertex_type v) const
std::pair< graph_edge_type, bool > connected_edge(graph_vertex_type v1, graph_vertex_type v2) const
hide vertices whose degree is smaller than number of colors available
bool connected_conflict(graph_vertex_type v1, graph_vertex_type v2) const
mathematical utilities such as abs
void recover_biconnected_component(std::vector< std::vector< int8_t > > &mColor, std::vector< std::vector< graph_vertex_type > > const &mSimpl2Orig) const
recover color for biconnected components
bool connected_stitch(graph_vertex_type v1, graph_vertex_type v2) const
bool articulation_point(graph_vertex_type v) const
namespace for Limbo
Definition: GraphUtility.h:22
void recover_hide_small_degree(std::vector< int8_t > &vColor)
std::iterator_traits< Iterator >::value_type max(Iterator first, Iterator last)
get max of an array
Definition: Math.h:61
bool simplified_graph_component(uint32_t comp_id, graph_type &sg, std::vector< graph_vertex_type > &vSimpl2Orig) const
namespace for Limbo.algorithms
Definition: GraphUtility.h:25
std::stack< graph_vertex_type > m_vHiddenVertex
a std::stack that keeps a reverse order of vertices hidden, useful for color recovery ...
merge 4-clique structures, no longer optimal
std::vector< int8_t > m_vPrecolor
precolor information, if uncolored, std::set to -1
void write_graph_dot(std::string const &filename) const
std::iterator_traits< Iterator >::value_type min(Iterator first, Iterator last)
get min of an array
Definition: Math.h:77
void graphviz2pdf(std::string const &filename, const char *suffix=".gv")
convert graphviz format to pdf. The input filename should be filename+suffix
Definition: GraphUtility.h:150
std::vector< std::vector< graph_vertex_type > > const & children() const
#define assert_msg(condition, message)
assertion with message
Definition: AssertMsg.h:34