Aleph-w  1.5a.2
Biblioteca general de algoritmos y estructuras de datos
 Todo Clases Archivos Funciones Variables 'typedefs' Enumeraciones Amigas Grupos Páginas
Tarjan.H
1 # ifndef TARJAN_H
2 # define TARJAN_H
3 
4 # include <tpl_dynListStack.H>
5 # include <tpl_dynSetTree.H>
6 # include <htlist.H>
7 # include <tpl_graph_utils.H>
8 # include <tpl_find_path.H>
9 
10 namespace Aleph {
11 
12 
23  template <class GT, class SA = Dft_Show_Arc<GT>>
25 {
26  SA & sa;
27 
29 
30  long df_count;
31  mutable size_t n; // número de nodos del grafo
32 
33  // lista de listas; cada lista almacena los nodos de los bloques
34  DynList<DynList<typename GT::Node*>> * list_list_ptr;
35 
36  DynList <GT> * block_list_ptr; // lista de bloques fuertemente
37  // conexos
38 
39  DynList<size_t> * list_len_ptr; // lista de tamaños de componentes
40 
41  Path<GT> * path_ptr;
42 
43 public:
44 
45  Tarjan_Connected_Components(SA && __sa = SA()) : sa(__sa) { /* empty */ }
46 
47  Tarjan_Connected_Components(SA & __sa) : sa(__sa) { /* empty */ }
48 
49 private:
50 
51  struct Init_Tarjan_Node
52  {
53  void operator () (GT & g, typename GT::Node * p)
54  {
55  g.reset_bits(p);
56  g.reset_counter(p); // inicializa df
57  low <GT> (p) = -1; // inicializa low
58  }
59  };
60 
61  bool is_node_in_stack(typename GT::Node * p)
62  {
63  return IS_NODE_VISITED(p, Aleph::Min);
64  }
65 
66  void init_node_and_push_in_stack(typename GT::Node * p)
67  {
68  I(not is_node_in_stack(p));
69 
70  stack.push(p);
71  NODE_BITS(p).set_bit(Aleph::Min, true);
72  NODE_BITS(p).set_bit(Aleph::Depth_First, true);
73  df<GT>(p) = low<GT>(p) = df_count++;
74  }
75 
76  typename GT::Node * pop_from_stack()
77  {
78  typename GT::Node * ret = stack.pop();
79  NODE_BITS(ret).set_bit(Aleph::Min, false);
80 
81  return ret;
82  }
83 
84  void scc_by_blocks(typename GT::Node * v)
85  {
86  init_node_and_push_in_stack(v);
87 
88  // recorrer en profundidad todos los nodos conectados a v
89  for (Out_Iterator<GT, SA> it(v, sa); it.has_curr(); it.next())
90  {
91  typename GT::Node * w = it.get_tgt_node();
92  if (not IS_NODE_VISITED(w, Aleph::Depth_First))
93  {
94  scc_by_blocks(w);
95  low <GT> (v) = std::min(low <GT> (v), low <GT> (w));
96  }
97  else if (is_node_in_stack(w))
98  // si está en pila ==> v fue visitado antes que p
99  low <GT> (v) = std::min(low <GT> (v), df <GT> (w));
100  }
101 
102  if (low <GT> (v) == df <GT> (v)) // ¿primer nodo visitado del bloque?
103  { // sí ==> saque los nodos del bloque que están en pila
104  const size_t & blk_idx = block_list_ptr->size();
105  GT & blk = block_list_ptr->append(GT());
106 
107  while (true) // sacar el bloque de la pila hasta sacar a v
108  {
109  typename GT::Node * p = pop_from_stack();
110  typename GT::Node * q = blk.insert_node(p->get_info());
111  NODE_COOKIE(p) = NODE_COOKIE(q) = NULL;
112  GT::map_nodes(p, q);
113  NODE_COUNTER(p) = NODE_COUNTER(q) = blk_idx;
114  if (p == v)
115  break;
116  }
117  }
118  }
119 
120  void scc_by_lists(typename GT::Node * v)
121  {
122  init_node_and_push_in_stack(v);
123 
124  // recorrer en profundidad todos los nodos conectados a v
125  for (Out_Iterator<GT, SA> it(v, sa); it.has_curr(); it.next())
126  {
127  typename GT::Node * w = it.get_tgt_node();
128  if (not IS_NODE_VISITED(w, Aleph::Depth_First))
129  {
130  scc_by_lists(w);
131  low <GT> (v) = std::min(low <GT> (v), low <GT> (w));
132  }
133  else if (is_node_in_stack(w))
134  // si está en pila ==> v fue visitado antes que p
135  low <GT> (v) = std::min(low <GT> (v), df <GT> (w));
136  }
137 
138  if (low<GT>(v) == df<GT>(v)) // ¿primer nodo visitado del bloque?
139  { // sí ==> saque los nodos del bloque que están en pila
141  list_list_ptr->append(DynList<typename GT::Node*>());
142 
143  while (true) // sacar bloque de pila hasta llegar a v
144  {
145  typename GT::Node * p = pop_from_stack();
146  l.append(p);
147 
148  if (p == v)
149  break;
150  }
151  }
152  }
153 
154  void scc_by_len(typename GT::Node * v)
155  {
156  init_node_and_push_in_stack(v);
157 
158  // recorrer en profundidad todos los nodos conectados a v
159  for (Out_Iterator<GT, SA> it(v, sa); it.has_curr(); it.next())
160  {
161  typename GT::Node * w = it.get_tgt_node();
162  if (not IS_NODE_VISITED(w, Aleph::Depth_First))
163  {
164  scc_by_len(w);
165  low <GT> (v) = std::min(low <GT> (v), low <GT> (w));
166  }
167  else if (is_node_in_stack(w))
168  // si está en pila ==> v fue visitado antes que p
169  low <GT> (v) = std::min(low <GT> (v), df <GT> (w));
170  }
171 
172  if (low<GT>(v) == df<GT>(v)) // ¿primer nodo visitado del bloque?
173  { // sí ==> saque los nodos del bloque que están en pila
174  size_t count = 0;
175 
176  while (true) // sacar bloque de pila hasta llegar a v
177  {
178  typename GT::Node * p = pop_from_stack();
179  ++count;
180 
181  if (p == v)
182  break;
183  }
184  list_len_ptr->append(count);
185  }
186  }
187 
188  void init_tarjan(GT & g)
189  {
190  if (not g.is_digraph())
191  throw std::domain_error("g is not a digraph");
192 
193  Operate_On_Nodes <GT, Init_Tarjan_Node> () (g); // inicia bits, df y low
194 
195  df_count = 0; // contador de visitas
196 
197  stack.empty();
198 
199  n = g.get_num_nodes();
200  }
201 
202  // retorna true si se encuentra un ciclo desde v
203  bool has_cycle(typename GT::Node * v)
204  {
205  init_node_and_push_in_stack(v);
206 
207  // recorrer en profundidad todos los nodos conectados a v
208  for (Out_Iterator <GT, SA> it(v, sa); it.has_curr(); it.next())
209  {
210  typename GT::Node * w = it.get_tgt_node();
211  if (not IS_NODE_VISITED(w, Aleph::Depth_First))
212  {
213  if (has_cycle(w))
214  return true;
215 
216  low<GT>(v) = std::min(low<GT>(v), low<GT>(w));
217  }
218  else if (is_node_in_stack(w))
219  // si está en pila ==> v fue visitado antes que p
220  low<GT>(v) = std::min(low<GT>(v), df<GT>(w));
221  }
222 
223  if (low<GT>(v) == df<GT>(v)) // ¿primer nodo visitado de bloque?
224  { // sí ==> verifique si tiene dos o más nodos
225  int i = 0;
226  for (; i < 2; ++i) // sacar bloque de la pila hasta sacar a v
227  if (pop_from_stack() == v)
228  break;
229 
230  return i >= 2; // si i>= 2 ==> hay un ciclo
231  }
232 
233  return false; // se recorrió todo v sin encontrar ciclo
234  }
235 
236  // construye en el miembro path un ciclo sobre block. Se asume que
237  // block es un componente mapeado del grafo.
238  void
239  build_path(GT & block,
241  {
242  // buscar ciclo en blk.
243  typename GT::Arc * a = block.get_first_arc();
244  Path<GT> aux_path(block);
245 
246  Find_Path_Depth_First<GT>() (block, block.get_tgt_node(a),
247  block.get_src_node(a), aux_path);
248 
249  path_ptr->clear_path();
250  for (typename Path<GT>::Iterator i(aux_path); i.has_curr(); i.next())
251  path_ptr->append(table.find(i.get_current_node()));
252 
253  path_ptr->append(table.find(block.get_tgt_node(a)));
254  }
255 
256  // retorna true si encuentra un ciclo, en cuyo caso lo pone en
257  // path. De lo contrario, retorna false y path queda intacto
258  bool build_cycle(typename GT::Node * v)
259  {
260  init_node_and_push_in_stack(v);
261 
262  // recorrer en profundidad todos los nodos conectados a v
263  for (Out_Iterator <GT, SA> it(v, sa); it.has_curr(); it.next())
264  {
265  typename GT::Node * w = it.get_tgt_node();
266  if (not IS_NODE_VISITED(w, Aleph::Depth_First))
267  {
268  if (build_cycle(w))
269  return true;
270 
271  low<GT>(v) = std::min(low<GT>(v), low<GT>(w));
272  }
273  else if (is_node_in_stack(w))
274  // si está en pila ==> v fue visitado antes que p
275  low<GT>(v) = std::min(low<GT>(v), df<GT>(w));
276  }
277 
278  if (low<GT>(v) == df<GT>(v)) // ¿primer nodo visitado del bloque?
279  {
280  GT blk; // grafo auxiliar
281 
282  // mapeo de nodos de g con blk (los cookies están ocupados)
284 
285  // saque nodos de pila e insertelos en bloque auxiliar
286  while (true) // saca el componente y lo inserta en blk
287  {
288  typename GT::Node * p = pop_from_stack();
289  typename GT::Node * q = blk.insert_node(p->get_info());
290  table.insert(q, p);
291  table.insert(p, q);
292  if (p == v)
293  break;
294  }
295 
296  if (blk.get_num_nodes() == 1)
297  return false; // si blk sólo tiene un nodo no hay ciclo
298 
299  // terminanos de construir el bloque con los arcos
300  for (typename GT::Node_Iterator j(blk); j.has_curr(); j.next())
301  {
302  typename GT::Node * bsrc = j.get_curr();
303  typename GT::Node * gsrc = table.find(bsrc);
304 
305  // recorrer los arcos de gsrc
306  for (Out_Iterator <GT, SA> k(gsrc, sa); k.has_curr(); k.next())
307  {
308  typename GT::Node * gtgt = k.get_tgt_node();
309  typename GT::Node ** btgt_ptr = table.test(gtgt);
310  if (btgt_ptr == NULL) // ¿arco del bloque?
311  continue;
312 
313  typename GT::Arc * ga = k.get_current_arc();
314  blk.insert_arc(bsrc, *btgt_ptr, ga->get_info());
315  }
316  }
317 
318  build_path(blk, table);
319 
320  return true;
321  }
322 
323  return false;
324  }
325 
326  bool is_connected(typename GT::Node * v)
327  {
328  init_node_and_push_in_stack(v);
329 
330  // recorrer en profundidad todos los nodos conectados a v
331  for (Out_Iterator <GT, SA> it(v, sa); it.has_curr(); it.next())
332  {
333  typename GT::Node * w = it.get_tgt_node();
334  if (not IS_NODE_VISITED(w, Aleph::Depth_First))
335  {
336  if (not is_connected(w))
337  return false;
338 
339  low <GT> (v) = std::min(low <GT> (v), low <GT> (w));
340  }
341  else if (is_node_in_stack(w))
342  low <GT> (v) = std::min(low <GT> (v), df <GT> (w));
343  }
344 
345  if (low<GT>(v) == df<GT>(v)) // ¿primer nodo visitado de bloque?
346  { // saque nodos de pila hasta encontrar a v
347  while (pop_from_stack() != v);
348 
349  return stack.is_empty();
350  }
351 
352  return true;
353  }
354 
355 public:
356 
385  void connected_components(GT & g, DynList <GT> & blk_list,
386  DynList<typename GT::Arc*> & arc_list)
387  {
388  init_tarjan(g);
389 
390  block_list_ptr = &blk_list;
391 
392  for (typename GT::Node_Iterator it(g); df_count < n; it.next())
393  {
394  typename GT::Node * v = it.get_curr();
395  if (not IS_NODE_VISITED(v, Aleph::Depth_First))
396  scc_by_blocks(v);
397  }
398 
399  I(stack.is_empty());
400 
401  // recorrer cada uno de subgrafos parciales y añadir sus arcos
402  for (typename DynList<GT>::Iterator i(blk_list); i.has_curr(); i.next())
403  { // recorrer todos los nodos del bloque
404  GT & blk = i.get_curr();
405  for (typename GT::Node_Iterator j(blk); j.has_curr(); j.next())
406  {
407  typename GT::Node * bsrc = j.get_curr();
408  typename GT::Node * gsrc = mapped_node<GT>(bsrc);
409 
410  // recorrer arcos de gsrc
411  for (Out_Iterator<GT, SA> k(gsrc, sa); k.has_curr(); k.next())
412  {
413  typename GT::Node * gtgt = k.get_tgt_node();
414  typename GT::Arc * ga = k.get_current_arc();
415  if (NODE_COUNTER(gsrc) != NODE_COUNTER(gtgt))
416  { // arco inter-bloque ==> añádalo a arc_list
417  arc_list.append(ga);
418  continue;
419  }
420 
421  // insertar y mapear el arco en el sub-bloque
422  typename GT::Node * btgt = mapped_node<GT>(gtgt);
423  typename GT::Arc * ba =
424  blk.insert_arc(bsrc, btgt, ga->get_info());
425 
426  GT::map_arcs(ga, ba);
427  }
428  }
429  }
430  }
431 
465  void connected_components(GT & g,
467  {
468  init_tarjan(g);
469 
470  list_list_ptr = &blks;
471 
472  for (typename GT::Node_Iterator it(g); df_count < n; it.next())
473  {
474  typename GT::Node * v = it.get_curr();
475  if (not IS_NODE_VISITED(v, Aleph::Depth_First))
476  scc_by_lists(v);
477  }
478  }
479 
503  {
504  init_tarjan(g);
505 
506  list_len_ptr = &blks;
507 
508  for (typename GT::Node_Iterator it(g); df_count < n; it.next())
509  {
510  typename GT::Node * v = it.get_curr();
511  if (not IS_NODE_VISITED(v, Aleph::Depth_First))
512  scc_by_len(v);
513  }
514  }
515 
517  void operator () (GT & g,
518  DynList <GT> & blk_list,
519  DynList<typename GT::Arc*> & arc_list)
520  {
521  connected_components(g, blk_list, arc_list);
522  }
523 
525  void operator () (GT & g,
527  {
528  connected_components(g, blks);
529  }
530 
532  void operator () (GT & g,
533  DynDlist <GT> & blk_list,
534  DynDlist<typename GT::Arc*> & arc_list)
535  {
536  DynList<GT> blist;
538  connected_components(g, blist, alist);
539 
540  for (typename DynList<GT>::Iterator it(blist); it.has_curr(); it.next())
541  {
542  GT & curr = it.get_curr();
543  GT & block = blk_list.append(GT());
544  curr.swap(block);
545  }
546 
547  for (typename DynList<typename GT::Arc*>::Iterator it(alist);
548  it.has_curr(); it.next())
549  arc_list.append(it.get_curr());
550  }
551 
553  void operator () (GT & g,
555  {
557  connected_components(g, b);
558 
559  for (typename DynList<DynList<typename GT::Node*>>::Iterator it(b);
560  it.has_curr(); it.next())
561  {
562  DynDlist<typename GT::Node*> & tgt_list =
564 
565  DynList<typename GT::Node*> & blk = it.get_curr();
566  while (not blk.is_empty())
567  tgt_list.append(blk.remove_first());
568  }
569  }
570 
572  bool has_cycle(GT & g)
573  {
574  init_tarjan(g);
575 
576  for (typename GT::Node_Iterator it(g); df_count < n; it.next())
577  {
578  typename GT::Node * v = it.get_curr();
579  if (not IS_NODE_VISITED(v, Aleph::Depth_First))
580  if (has_cycle(v))
581  return true;
582  }
583 
584  return false;
585  }
586 
588  bool is_dag(GT & g)
589  {
590  return not has_cycle(g);
591  }
592 
593  bool compute_cycle(GT & g, Path<GT> & path)
594  {
595  init_tarjan(g);
596  path_ptr = &path;
597  path_ptr->set_graph(g);
598 
599  for (Node_Iterator<GT> it(g); df_count < n; it.next())
600  {
601  typename GT::Node * v = it.get_curr();
602  if (not IS_NODE_VISITED(v, Aleph::Depth_First)) // ¿p visitado?
603  if (build_cycle(v))
604  return true;
605  }
606 
607  return false;
608  }
609 
610  bool test_connectivity(GT & g)
611  {
612  init_tarjan(g);
613 
614  for (typename GT::Node_Iterator it(g); df_count < n; it.next())
615  {
616  typename GT::Node * v = it.get_curr();
617  if (not IS_NODE_VISITED(v, Aleph::Depth_First))
618  if (not is_connected(v))
619  return false;
620  }
621 
622  I(stack.is_empty());
623 
624  return true;
625  }
626 };
627 
628 
629 
648  template <class GT, class SA = Dft_Show_Arc<GT>>
650 {
651  SA & sa;
652 
653 public:
654 
655  Compute_Cycle_In_Digraph(SA && __sa = SA()) : sa(__sa) { /* empty */ }
656 
657  Compute_Cycle_In_Digraph(SA & __sa) : sa(__sa) { /* empty */ }
658 
667  bool operator () (GT & g, Path<GT> & path) const
668  {
670 
671  return tarjan.compute_cycle(g, path);
672  }
673 };
674 
675 } // end namespace Aleph
676 
677 # endif // TARJAN_H
void connected_components(GT &g, DynList< DynList< typename GT::Node * >> &blks)
Definition: Tarjan.H:465
Type * test(const Key &key)
Definition: tpl_dynMapTree.H:191
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Definition: ahAlgo.H:127
T remove_first()
Definition: htlist.H:719
bool operator()(GT &g, Path< GT > &path) const
Definition: Tarjan.H:667
#define NODE_COOKIE(p)
Definition: aleph-graph.H:248
Definition: Stack.H:19
Definition: tpl_dynMapTree.H:260
Definition: tpl_dynDlist.H:26
Definition: tpl_graph.H:1389
void operator()(GT &g, DynList< GT > &blk_list, DynList< typename GT::Arc * > &arc_list)
Definition: Tarjan.H:517
#define IS_NODE_VISITED(p, bit)
Definition: aleph-graph.H:242
bool is_empty() const
Retorna true si la lista está vacía.
Definition: htlist.H:248
bool is_dag(GT &g)
Retorna true si el grafo dirigido es acíclico.
Definition: Tarjan.H:588
#define NODE_COUNTER(p)
Definition: aleph-graph.H:226
void connected_components(GT &g, DynList< GT > &blk_list, DynList< typename GT::Arc * > &arc_list)
Definition: Tarjan.H:385
bool empty() const
Retorna true si la pila está vacía.
Definition: Stack.H:42
Definition: tpl_graph.H:1186
Definition: tpl_graph.H:26
Definition: tpl_find_path.H:33
void next()
Adelanta el iterador una posición.
Definition: filter_iterator.H:143
#define NODE_BITS(p)
Definition: aleph-graph.H:221
Definition: tpl_graph.H:814
T pop()
Definition: tpl_dynListStack.H:122
Definition: htlist.H:769
Definition: ahDry.H:13
T & push(const T &item)
Definition: tpl_dynListStack.H:93
void connected_components(GT &g, DynList< size_t > &blks)
Definition: Tarjan.H:502
T & append(const T &item)
Inserta un item como último elemento.
Definition: htlist.H:685
bool has_cycle(GT &g)
Retorna true si el digrafo g contiene al menos un ciclo.
Definition: Tarjan.H:572
Definition: Tarjan.H:649
Key * insert(const Key &key, const Type &data)
Definition: tpl_dynMapTree.H:74
Definition: tpl_graph.H:1868
T & append(const T &item)
Definition: tpl_dynDlist.H:106
Definition: Tarjan.H:24
Type & find(const Key &key)
Definition: tpl_dynMapTree.H:223

Leandro Rabindranath León