Aleph-w  1.9
General library for algorithms and data structures
tpl_cut_nodes.H
1 
2 /* Aleph-w
3 
4  / \ | | ___ _ __ | |__ __ __
5  / _ \ | |/ _ \ '_ \| '_ \ ____\ \ /\ / / Data structures & Algorithms
6  / ___ \| | __/ |_) | | | |_____\ V V / version 1.9b
7  /_/ \_\_|\___| .__/|_| |_| \_/\_/ https://github.com/lrleon/Aleph-w
8  |_|
9 
10  This file is part of Aleph-w library
11 
12  Copyright (c) 2002-2018 Leandro Rabindranath Leon & Alejandro Mujica
13 
14  This program is free software: you can redistribute it and/or modify
15  it under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  This program is distributed in the hope that it will be useful, but
20  WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27 # ifndef TPL_CUT_NODES_H
28 # define TPL_CUT_NODES_H
29 
30 # include <tpl_graph_utils.H>
31 
32 namespace Aleph {
33 
34 
93  template <class GT, class SA = Dft_Show_Arc<GT> >
95 {
96  SA sa;
97  GT * gptr = nullptr;
98  DynDlist<typename GT::Node *> * list_ptr = nullptr;
99  long curr_df = 0;
100  long curr_color = 1;
101 
102  enum State { Init, Cut_Nodes_Computed, Painted } state;
103 
104  void cut_nodes(typename GT::Node * p, typename GT::Arc * a)
105  {
106  NODE_BITS(p).set_bit(Depth_First, true); // pinte p visitado
107  low <GT> (p) = df <GT> (p) = curr_df++; // asígnele df
108 
109  // recorrer arcos de p mientras no se abarque a g
110  bool p_is_cut_node = false;
111  for (Node_Arc_Iterator <GT, SA> i(p, sa); i.has_curr(); i.next_ne())
112  {
113  auto arc = i.get_curr_ne();
114  if (arc == a)
115  continue; // a es el padre de arc ==> ignorarlo
116 
117  auto tgt = i.get_tgt_node();
118  if (IS_NODE_VISITED(tgt, Depth_First))
119  {
120  if (not IS_ARC_VISITED(arc, Depth_First)) // no abarcador?
121  low<GT>(p) = std::min(df<GT>(tgt), low<GT>(p));
122  continue;
123  }
124 
125  if (IS_ARC_VISITED(arc, Depth_First))
126  continue;
127 
128  ARC_BITS(arc).set_bit(Depth_First, true); // marque arco
129 
130  cut_nodes(tgt, arc);
131  low<GT>(p) = std::min(low<GT>(tgt), low<GT>(p));
132  if (low<GT>(tgt) >= df<GT>(p) and df<GT>(tgt) != 0) // ¿de corte?
133  p_is_cut_node = true;
134  }
135 
136  // aquí, p ya fue explorado recursivamente
137  if (p_is_cut_node)
138  {
139  NODE_BITS(p).set_bit(Cut, true);
140  list_ptr->append(p);
141  }
142  }
143 
144 public:
145 
159  void cut_nodes(typename GT::Node * start,
161  {
162  curr_df = 0; // contador global de visitas
163  list_ptr = &list;
164 
165  list_ptr->empty();
166 
167  gptr->for_each_node([] (auto p) // init the nodes
168  {
169  NODE_COUNTER(p) = 0;
170  NODE_BITS(p).reset();
171  low<GT>(p) = -1;
172  });
173  gptr->reset_arcs();
174 
175  NODE_BITS(start).set_bit(Depth_First, true); // marcar start
176  df <GT> (start) = curr_df++;
177 
178  int call_counter = 0; // contador de llamadas recursivas
179 
180  // Recorra los arcos de start mientras g no haya sido abarcado
181  for (Node_Arc_Iterator<GT, SA> it(start, sa);
182  it.has_curr() and curr_df < gptr->get_num_nodes(); it.next_ne())
183  {
184  auto tgt = it.get_tgt_node();
185  if (IS_NODE_VISITED(tgt, Depth_First))
186  continue;
187 
188  auto arc = it.get_curr_ne();
189  if (IS_ARC_VISITED(arc, Depth_First))
190  continue;
191 
192  ARC_BITS(arc).set_bit(Depth_First, true);
193  cut_nodes(tgt, arc);
194  ++call_counter;
195  }
196 
197  if (call_counter > 1) // ¿es la raíz un punto de articulación?
198  { // sí == métala en la lista
199  NODE_BITS(start).set_bit(Cut, true);
200  list_ptr->append(start);
201  }
202 
203  state = Cut_Nodes_Computed;
204  }
205 
206 private:
207 
208  void paint_subgraph(typename GT::Node * p)
209  {
210  assert(not is_a_cut_node <GT> (p));
211 
212  if (is_node_painted <GT> (p))
213  return;
214 
215  paint_node <GT> (p, curr_color);
216 
217  for (Node_Arc_Iterator<GT, SA> it(p, sa); it.has_curr(); it.next_ne())
218  {
219  auto arc = it.get_curr_ne();
220  if (is_arc_painted <GT> (arc))
221  continue;
222 
223  auto tgt = it.get_tgt_node();
224  if (is_a_cut_node <GT> (tgt))
225  continue;
226 
227  paint_arc<GT>(arc, curr_color);
228  paint_subgraph(tgt);
229  }
230  }
231 
232  void paint_from_cut_node(typename GT::Node * p)
233  {
234  assert(is_a_cut_node <GT> (p));
235 
236  // pintar recursivamente con dif colores bloques conectados a p
237  for (Node_Arc_Iterator<GT, SA> it(p, sa); it.has_curr(); it.next_ne())
238  {
239  auto arc = it.get_curr_ne();
240 
241  assert(not is_arc_painted <GT> (arc));
242 
243  auto tgt_node = it.get_tgt_node();
244  if (is_a_cut_node <GT> (tgt_node)) // ¿ es un arco de corte?
245  {
246  ARC_BITS(arc).set_bit(Cut, true); // marque como de corte
247  continue; // avance a próximo arco
248  }
249  else
250  {
251  paint_arc <GT> (arc, Cross_Arc); // marque como de cruce
252  if (is_node_painted <GT> (tgt_node))
253  continue;
254  }
255 
256  // pintar recursivamente nodo conectado a arc
257  paint_subgraph(tgt_node);
258 
259  curr_color++; // cambiar color (sig arco en otro bloque)
260 
261  assert(not is_arc_painted <GT> (arc));
262  }
263  }
264 
265  typename GT::Node * create_and_map_node(typename GT::Node * gp,
266  const long & color,
267  GT & sg)
268  {
269  assert(get_color<GT>(gp) == color);
270  assert(not IS_NODE_VISITED(gp, Build_Subtree));
271 
272  unique_ptr<typename GT::Node> tp_auto(new typename GT::Node(gp));
273  sg.insert_node(tp_auto.get());
274  GT::map_nodes(gp, tp_auto.get());
275  NODE_BITS(gp).set_bit(Build_Subtree, true);
276 
277  return tp_auto.release();
278  }
279 
280  void map_subgraph(GT & sg, typename GT::Node * gsrc, const long & color)
281  {
282  assert(get_color <GT> (gsrc) == color);
283 
284  auto tsrc = mapped_node<GT>(gsrc); // gsrc en sg
285 
286  // recorrer arcos de gsrc y añadir a sg los del color de interés
287  for (Node_Arc_Iterator <GT, SA> i(gsrc, sa); i.has_curr(); i.next_ne())
288  {
289  auto garc = i.get_curr_ne();
290  if (get_color<GT>(garc) != color or IS_ARC_VISITED(garc, Build_Subtree))
291  continue; // arco es de otro color o ya está visitado
292 
293  ARC_BITS(garc).set_bit(Build_Subtree, true);
294 
295  auto gtgt = i.get_tgt_node();
296 
297  assert(get_color <GT> (gtgt) == color);
298 
299  typename GT::Node * ttgt = nullptr; // imagen gtgt en sg
300  if (IS_NODE_VISITED(gtgt, Build_Subtree)) // ¿gtgt en sg?
301  ttgt = mapped_node<GT> (gtgt);
302  else
303  ttgt = create_and_map_node(gtgt, color, sg);
304 
305  auto tarc = sg.insert_arc(tsrc, ttgt, garc->get_info());
306  GT::map_arcs(garc, tarc);
307 
308  map_subgraph(sg, gtgt, color);
309  }
310  }
311 
312 public:
313 
321  Compute_Cut_Nodes(const GT & g, SA __sa = SA())
322  : sa(__sa), gptr(&const_cast<GT&>(g)), state(Init)
323  {
324  /* empty */
325  }
326 
329  {
330  cut_nodes(gptr->get_first_node(), list);
331  }
332 
334  void operator () (typename GT::Node * start,
336  {
337  cut_nodes(start, list);
338  }
339 
361  {
362  if (state != Cut_Nodes_Computed)
363  throw std::logic_error("Cut nodos has not been computed or the class is"
364  " another phase");
365 
366  gptr->reset_counter_nodes();
367  gptr->reset_counter_arcs();
368  curr_color = 1;
369 
370  // Recorrer cada nodo de corte y pintar sus bloques
371  for (typename DynDlist<typename GT::Node*>::Iterator i(*list_ptr);
372  i.has_curr(); i.next_ne())
373  paint_from_cut_node(i.get_curr_ne());
374 
375  state = Painted;
376 
377  return curr_color;
378  }
379 
391  void map_subgraph(GT & sg, const long & color)
392  {
393  if (state != Painted)
394  throw std::logic_error("Graph is not painted");
395 
396  clear_graph(sg);
397 
398  typename GT::Node * first = nullptr; // busque primer nodo con color
399 
400  for (typename GT::Node_Iterator it(*gptr); it.has_curr(); it.next_ne())
401  if (get_color <GT> (it.get_curr_ne()) == color)
402  first = it.get_curr_ne();
403 
404  if (first == nullptr) // Encontró el color?
405  throw std::domain_error("Color does not exist in the graph");
406 
407  // cree first, insértelo en sg y mapéelo
408  create_and_map_node(first, color, sg);
409  try
410  {
411  map_subgraph (sg, first, color); // mapee first
412  }
413  catch (...)
414  {
415  clear_graph(sg);
416  }
417  }
418 
438  void map_cut_graph(GT & cut_graph,
439  DynDlist<typename GT::Arc*> & cross_arc_list)
440  {
441  if (state != Painted)
442  throw std::logic_error("Graph is not painted");
443 
444  clear_graph(cut_graph);
445 
446  // recorra lista de nodos de corte e insértelos en cut_graph
447  for (typename DynDlist<typename GT::Node*>::Iterator it(*list_ptr);
448  it.has_curr(); it.next_ne())
449  {
450  auto gp = it.get_curr_ne();
451 
452  assert(is_a_cut_node <GT> (gp));
453 
454  unique_ptr<typename GT::Node> tp_auto(new typename GT::Node(gp));
455  cut_graph.insert_node(tp_auto.get());
456  GT::map_nodes(gp, tp_auto.release());
457  }
458 
459  // recorra arcos de g ==> cut_graph = {arcos no corte} U
460  // cross_arc_list = {arcos de cruce}
461  for (Arc_Iterator <GT, SA> it(*gptr, sa); it.has_curr(); it.next_ne())
462  {
463  auto garc = it.get_curr_ne();
464  if (is_a_cross_arc <GT> (garc))
465  {
466  cross_arc_list.append(garc);
467  continue;
468  }
469 
470  if (not is_an_cut_arc <GT> (garc))
471  continue;
472 
473  typename GT::Node * src = mapped_node<GT>(gptr->get_src_node(garc));
474  typename GT::Node * tgt = mapped_node<GT>(gptr->get_tgt_node(garc));
475 
476  assert(src != nullptr and tgt != nullptr);
477 
478  typename GT::Arc * arc =
479  cut_graph.insert_arc(src, tgt, garc->get_info());
480  GT::map_arcs(garc, arc);
481  }
482  }
483 
506  void compute_blocks(DynDlist<GT> & block_list,
507  GT & cut_graph,
508  DynDlist<typename GT::Arc*> & cross_arc_list)
509  {
510  if (state < Cut_Nodes_Computed)
511  throw std::logic_error("Cut nodes have not been computed");
512 
513  if (state == Cut_Nodes_Computed)
514  paint_subgraphs();
515 
516  const long & num_colors = curr_color;
517 
518  DynArray<GT*> blocks; // bloques en un arreglo para rápido
519  // acceso. Que esté o no vacío indica si ha
520  // sido o no procesado.
521  blocks.reserve(num_colors);
522 
523  // crear lista de componentes vacíos ordenador por color i
524  for (int i = 0; i < num_colors; ++i)
525  blocks.access(i) = &block_list.append(GT());
526 
527  // Recorrer los nodos y copiar y mapear según color
528  for (typename GT::Node_Iterator it(*gptr); it.has_curr(); it.next_ne())
529  {
530  auto p = it.get_curr_ne();
531  if (IS_NODE_VISITED(p, Build_Subtree))
532  continue;
533 
534  if (is_a_cut_node <GT> (p))
535  continue;
536 
537  const long color = get_color<GT>(p);
538 
539  GT & sg = *blocks.access(color - 1);
540 
541  create_and_map_node(p, color, sg);
542 
543  map_subgraph(sg, p, color);
544  }
545 
546  map_cut_graph(cut_graph, cross_arc_list);
547  }
548 };
549 
550 } // end namespace Aleph
551 
552 # endif // TPL_CUT_NODES_H
long paint_subgraphs()
Definition: tpl_cut_nodes.H:360
void reserve(const size_t l, const size_t r)
Definition: tpl_dynArray.H:998
void clear_graph(GT &g) noexcept
Definition: tpl_graph.H:3463
Definition: tpl_graph.H:1225
Definition: tpl_dynDlist.H:51
T & access(const size_t i) const noexcept
Definition: tpl_dynArray.H:874
#define IS_NODE_VISITED(p, bit)
Definition: aleph-graph.H:327
void map_subgraph(GT &sg, const long &color)
Definition: tpl_cut_nodes.H:391
void map_cut_graph(GT &cut_graph, DynDlist< typename GT::Arc *> &cross_arc_list)
Definition: tpl_cut_nodes.H:438
void cut_nodes(typename GT::Node *start, DynDlist< typename GT::Node *> &list)
Definition: tpl_cut_nodes.H:159
void operator()(DynDlist< typename GT::Node *> &list)
Definition: tpl_cut_nodes.H:328
#define NODE_COUNTER(p)
Definition: aleph-graph.H:311
Compute_Cut_Nodes(const GT &g, SA __sa=SA())
Definition: tpl_cut_nodes.H:321
void map_arcs(typename GTS::Arc *p, typename GTT::Arc *q) noexcept
Definition: tpl_graph.H:3445
Definition: tpl_dynDlist.H:413
#define IS_ARC_VISITED(p, bit)
Definition: aleph-graph.H:360
void map_nodes(typename GTS::Node *p, typename GTT::Node *q) noexcept
Definition: tpl_graph.H:3419
Definition: ah-comb.H:35
Definition: tpl_cut_nodes.H:94
#define NODE_BITS(p)
Definition: aleph-graph.H:305
void empty() noexcept
Empty the list.
Definition: tpl_dynDlist.H:90
#define ARC_BITS(p)
Definition: aleph-graph.H:351
Definition: tpl_dynArray.H:159
void compute_blocks(DynDlist< GT > &block_list, GT &cut_graph, DynDlist< typename GT::Arc *> &cross_arc_list)
Definition: tpl_cut_nodes.H:506
Definition: tpl_graph.H:1177
Definition: List.H:49
T & append(const T &item)
Definition: tpl_dynDlist.H:149

Leandro Rabindranath León