Aleph-w  1.9
General library for algorithms and data structures
random_graph.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 RANDOM_GRAPH_H
28 # define RANDOM_GRAPH_H
29 
30 # include <gsl/gsl_rng.h>
31 # include <memory>
32 # include <tpl_indexArc.H>
33 # include <tpl_graph_utils.H>
34 # include <tpl_components.H>
35 # include <single_graph.H>
36 # include <Tarjan.H>
37 
38 namespace Aleph
39 {
40 
41  template <class GT>
42 struct Dft_Init_Rand_Node
43 {
44  void operator () (GT &, typename GT::Node *) const noexcept
45  {
46  // empty
47  }
48 };
49 
50 
51  template <class GT>
52 struct Dft_Init_Rand_Arc
53 {
54  void operator () (GT &, typename GT::Arc *) const noexcept
55  {
56  // empty
57  }
58 };
59 
60  // TODO: eliminar clases Init_Node e Init_Arc y en su lugar usar lambdas
61 
62  template <class GT, class Init_Node, class Init_Arc>
63 class Random_Graph_Base
64 {
65 protected:
66 
67  typedef typename GT::Node GT_Node;
68  typedef typename GT::Arc GT_Arc;
69 
70  gsl_rng * r;
71 
72  Init_Node & init_node;
73  Init_Arc & init_arc;
74 
75  unique_ptr<DynArray<GT_Node*>> nodes; // puntero para ahorrar
76  // directorio en caso de que no
77  // se utilice
78 
79  unique_ptr<IndexArc<GT>> idx_arc; // puntero porque el constructor
80  // requiere el grafo.
81  mutable size_t num_nodes;
82  mutable size_t num_arcs;
83  mutable unsigned long rand_max;
84 
85  GT g;
86 
87  bool save_parity; // indica si se debe o no guardar relaciones de
88  // paridad entre los nodos. Sólo para construir
89  // eulerianos y hamiltonianos
90 
91  virtual void
92  update_parity_after_arc_insertion(GT_Node * src, GT_Node * tgt) = 0;
93 
94  GT_Arc * insert_arc(GT_Node * src, GT_Node * tgt)
95  {
96  auto a = idx_arc->insert(g.insert_arc(src, tgt));
97  init_arc (g, a);
98  update_parity_after_arc_insertion(src, tgt);
99  return a;
100  }
101 
102  // selecciona un nodo azar distinto a excluded
103  GT_Node * select_random_node(GT_Node * excluded = nullptr) noexcept
104  {
105  assert(nodes.get() != nullptr);
106 
107  unsigned long idx;
108  GT_Node * ret_val = nullptr;
109  while (true)
110  {
111  idx = gsl_rng_uniform_int(r, num_nodes);
112  ret_val = nodes->access(idx);
113  if (excluded == nullptr or ret_val != excluded)
114  break;
115  }
116 
117  return ret_val;
118  }
119 
120  // selecciona un nodo azar entre los contenidos en la lista list
121  GT_Node * select_random_node(DynList<GT_Node*> & list) noexcept
122  {
123  const unsigned long k = gsl_rng_uniform_int(r, list.size());
124  typename DynList<GT_Node*>::Iterator it(list);
125  for (int i = 0; i < k; ++i, it.next_ne()) ;
126 
127  return it.get_curr_ne();
128  }
129 
130  virtual void create_nodes_and_initialize_arc_index() = 0;
131 
132  virtual void connect() = 0;
133 
134  void initialize_and_create_nodes(const size_t & __num_nodes,
135  const size_t & __num_arcs)
136  {
137  num_nodes = __num_nodes;
138 
139  const size_t num_nodes_2 = num_nodes*num_nodes;
140  if (g.is_digraph())
141  num_arcs = std::min(__num_arcs, num_nodes_2 - num_nodes);
142  else
143  num_arcs = std::min(__num_arcs, (num_nodes_2 - num_nodes)/2);
144 
145  create_nodes_and_initialize_arc_index();
146  }
147 
148  Random_Graph_Base(unsigned long seed,
149  const Init_Node & __init_node,
150  const Init_Arc & __init_arc)
151  : r(gsl_rng_alloc (gsl_rng_mt19937)),
152  init_node(const_cast<Init_Node&>(__init_node)),
153  init_arc(const_cast<Init_Arc&>(__init_arc)),
154  num_nodes(0), num_arcs(0),
155  rand_max(gsl_rng_max(r)), save_parity(false)
156  {
157  if (r == nullptr)
158  throw std::bad_alloc();
159 
160  gsl_rng_set(r, seed % rand_max);
161  }
162 
163  ~Random_Graph_Base()
164  {
165  if (r != nullptr)
166  gsl_rng_free(r);
167  }
168 
169  // Crea un grafo aleatorio esparcido.
170  GT create(const size_t & __num_nodes, const size_t & __num_arcs,
171  bool connected)
172  {
173  initialize_and_create_nodes(__num_nodes, __num_arcs);
174 
175  // inserta al azar los arcos seleccionando al azar pares de nodos
176  for (int i = 0; i < num_arcs; ++i)
177  {
178  auto src = select_random_node();
179  auto tgt = select_random_node(src);
180  if (idx_arc->search(src, tgt) == nullptr) // se repite el arco?
181  insert_arc(src, tgt);
182  }
183 
184  if (connected)
185  connect();
186 
187  return move(g);
188  }
189 
190  virtual GT create_p(const size_t & __num_nodes, const double & p,
191  bool connected) = 0;
192 
193  virtual void make_eulerian() = 0;
194 
195  virtual void make_hamiltonian () = 0;
196 
197 public:
198 
215  GT eulerian(const size_t & __num_nodes, const size_t & __num_arcs)
216  {
217  save_parity = true;
218  g = this->create(__num_nodes, __num_arcs, true);
219  make_eulerian();
220 
221  return std::move(g);
222  }
223 
243  GT eulerian (const size_t & __num_nodes, const double & p)
244  {
245  save_parity = true;
246  g = this->create_p(__num_nodes, p, true);
247  make_eulerian();
248 
249  return std::move(g);
250  }
251 
279  GT sufficient_hamiltonian (const size_t & __num_nodes,
280  const double & p = 0.5)
281  {
282  g = this->create_p(__num_nodes, p, true);
283  make_hamiltonian();
284 
285  return std::move(g);
286  }
287 };
288 
289 
332  template <class GT,
333  class Init_Node = Dft_Init_Rand_Node<GT>,
334  class Init_Arc = Dft_Init_Rand_Arc<GT> >
335 class Random_Graph : public Random_Graph_Base<GT, Init_Node, Init_Arc>
336 {
337  typedef typename GT::Node GT_Node;
338  typedef typename GT::Arc GT_Arc;
339 
340  DynSetRandTree<GT_Node*> odd_nodes; // nodos con grado impar
341  DynSetRandTree<GT_Node*> even_nodes; // nodos con grado par
342 
343  virtual void update_parity_after_arc_insertion(GT_Node * src, GT_Node * tgt)
344  {
345  if (not this->save_parity)
346  return;
347 
348  if (is_even(this->g.get_num_arcs(src)))
349  { // era impar antes de la inserción
350  this->odd_nodes.remove(src);
351  this->even_nodes.insert(src);
352  }
353  else
354  {
355  this->even_nodes.remove(src);
356  this->odd_nodes.insert(src);
357  }
358 
359  if (is_even(this->g.get_num_arcs(tgt)))
360  { // era impar antes de la inserción
361  this->odd_nodes.remove(tgt);
362  this->even_nodes.insert(tgt);
363  }
364  else
365  {
366  this->even_nodes.remove(tgt);
367  this->odd_nodes.insert(tgt);
368  }
369  }
370 
371  virtual void create_nodes_and_initialize_arc_index()
372  {
373  this->nodes = unique_ptr<DynArray<GT_Node*>>
374  (new DynArray<GT_Node*>(this->num_nodes));
375 
376  this->nodes->reserve(this->num_nodes);
377 
378  for (int i = 0; i < this->num_nodes; ++i)
379  {
380  auto p = this->g.insert_node(new GT_Node);
381  this->nodes->access(i) = p;
382  this->init_node(this->g, p);
383  if (this->save_parity)
384  {
385  this->even_nodes.insert(p);
386  NODE_COUNTER(p) = 0;
387  }
388  }
389 
390  this->idx_arc = unique_ptr<IndexArc<GT>> (new IndexArc<GT>(this->g) );
391  }
392 
393  virtual void connect()
394  {
395  DynList<DynList<GT_Node*>> subgraphs; // lista sufgrafos
396 
397  Inconnected_Components <GT> () (this->g, subgraphs);
398 
399  const size_t & num_subs = subgraphs.size();
400 
401  if (num_subs == 1)
402  return;
403 
404  DynArray<GT_Node*> block_nodes;
405 
406  for (typename DynList<DynList<GT_Node*>>::Iterator it(subgraphs);
407  it.has_curr(); it.next_ne())
408  block_nodes.append(this->select_random_node(it.get_curr_ne()));
409 
410  for (int i = 1; i < num_subs; ++i)
411  {
412  auto src = block_nodes.access(i - 1);
413  auto tgt = block_nodes.access(i);
414  this->insert_arc(src, tgt);
415  }
416  }
417 
418  // crea un grafo aleatorio en el cual la probabilida por arco entre un
419  // par de nodos es p
420  virtual GT create_p (const size_t & __num_nodes, const double & p,
421  bool connected)
422  {
423  if (p > 1.0 or p <= 0.0)
424  throw std::domain_error("Invalid value for p");
425 
426  this->initialize_and_create_nodes(__num_nodes, __num_nodes);
427 
428  for (int i = 0; i < this->num_nodes - 1; ++i)
429  {
430  auto src = this->nodes->access(i);
431  for (int j = i + 1; j < this->num_nodes; ++j)
432  if (gsl_rng_uniform(this->r) <= p) // sorteo
433  {
434  auto tgt = this->nodes->access(j);
435  assert(src != tgt);
436  this->insert_arc(src, tgt);
437  }
438  }
439 
440  if (connected)
441  connect();
442 
443  return move(this->g);
444  }
445 
446 public:
447 
454  Random_Graph(unsigned long seed,
455  const Init_Node & __init_node,
456  const Init_Arc & __init_arc)
457  : Random_Graph_Base<GT, Init_Node, Init_Arc>(seed, __init_node, __init_arc)
458  {
459  if (this->g.is_digraph())
460  throw std::domain_error("Building of random digraph through a graph");
461  }
462 
463  Random_Graph(unsigned long seed = time(nullptr),
464  const Init_Node && __init_node = Init_Node(),
465  const Init_Arc && __init_arc = Init_Arc())
466  : Random_Graph_Base<GT, Init_Node, Init_Arc>(seed, __init_node, __init_arc)
467  {
468  if (this->g.is_digraph())
469  throw std::domain_error("Building of random digraph through a graph");
470  }
471 
472 
489  GT operator () (const size_t & __num_nodes, const size_t & __num_arcs,
490  bool connected = true)
491  {
492  return this->create(__num_nodes, __num_arcs, connected);
493  }
494 
495 public:
496 
521  GT operator () (const size_t & __num_nodes, const double & p,
522  bool connected = true)
523  {
524  return create_p(__num_nodes, p, connected);
525  }
526 
527 private:
528 
529  virtual void make_eulerian()
530  {
531  while (this->odd_nodes.size() > 1)
532  {
533  GT_Node * src = nullptr;
534  GT_Node * tgt = nullptr;
535 
536  while (true)
537  {
538  src = this->odd_nodes.select
539  (gsl_rng_uniform_int(this->r, this->odd_nodes.size()));
540  do
541  tgt = this->odd_nodes.select
542  (gsl_rng_uniform_int(this->r, this->odd_nodes.size()));
543  while (tgt == src);
544 
545  if (this->idx_arc->search(src, tgt) == nullptr)
546  break;
547  else if (this->odd_nodes.size() == 2)
548  { // seleccionar nodo al azar que no tenga arco hacia src o tgt
549  GT_Node * p = nullptr;
550  do
551  p = this->even_nodes.select
552  (gsl_rng_uniform_int(this->r, this->even_nodes.size()));
553  while (this->idx_arc->search(src, p) != nullptr or
554  this->idx_arc->search(tgt, p) != nullptr);
555  this->insert_arc(src, p);
556  this->insert_arc(p, tgt);
557 
558  return;
559  }
560  }
561 
562  this->insert_arc(src, tgt);
563  }
564 
565  assert(this->odd_nodes.size() == 0);
566  }
567 
568  void balance_graph_nodes_degree(GT_Node * src, GT_Node * tgt)
569  {
570  if (this->idx_arc->search(src, tgt) == nullptr)
571  this->insert_arc(src, tgt);
572 
573  const size_t & n = this->g.get_num_nodes();
574 
575  while (this->g.get_num_arcs(src) + this->g.get_num_arcs(tgt) < n)
576  {
577  auto p = this->nodes->access(gsl_rng_uniform_int(this->r, n));
578  if (p == src or p == tgt)
579  continue;
580 
581  if (this->idx_arc->search(src, p) == nullptr)
582  this->insert_arc(src, p);
583 
584  if (this->g.get_num_arcs(src) + this->g.get_num_arcs(tgt) == n)
585  break;
586 
587  if (this->idx_arc->search(tgt, p) == nullptr)
588  this->insert_arc(tgt, p);
589  }
590  }
591 
592  virtual void make_hamiltonian ()
593  {
594  const size_t & n = this->g.get_num_nodes();
595  for (int i = 0; i < n - 1; ++i)
596  {
597  auto src = this->nodes->access(i);
598  for (int j = i + 1; j < n; ++j)
599  balance_graph_nodes_degree(src, this->nodes->access(j));
600  }
601  }
602 
603 public:
604 
621  GT eulerian (const size_t & __num_nodes, const size_t & __num_arcs)
622  {
623  this->save_parity = true;
624  this->g = this->create(__num_nodes, __num_arcs, true);
625  make_eulerian();
626 
627  return std::move(this->g);
628  }
629 
649  GT eulerian (const size_t & __num_nodes, const double & p)
650  {
651  this->save_parity = true;
652  this->g = this->create_p(__num_nodes, p, true);
653  make_eulerian();
654 
655  return std::move(this->g);
656  }
657 
685  GT sufficient_hamiltonian (const size_t & __num_nodes,
686  const double & p = 0.5)
687  {
688  this->g = this->create_p(__num_nodes, p, true);
689  make_hamiltonian();
690 
691  return std::move(this->g);
692  }
693 };
694 
695 
696  template <class GT,
697  class Init_Node = Dft_Init_Rand_Node<GT>,
698  class Init_Arc = Dft_Init_Rand_Arc<GT>>
699 class Random_Digraph : public Random_Graph_Base<GT, Init_Node, Init_Arc>
700 {
701  typedef typename GT::Node GT_Node;
702  typedef typename GT::Arc GT_Arc;
703 
704  DynSetRandTree<GT_Node*> greater; // nodos con grado out mayor que in
705  DynSetRandTree<GT_Node*> smaller; // nodos con grado out menor que in
706  DynSetRandTree<GT_Node*> equal; // nodos con grado out igual a in
707 
708  bool verify_tables()
709  {
710  const size_t & n = this->nodes->size();
711 
712  if (n != this->g.get_num_nodes())
713  cout << "Warning num of nodes of graph does not match with array "
714  << this->g.get_num_nodes() << "!=" << n << endl;
715 
716  size_t total = greater.size() + smaller.size() + equal.size();
717  if (total != this->g.get_num_nodes())
718  cout << "Inconsistency with nodes parity" << endl
719  << "greater = " << greater.size() << endl
720  << "smaller = " << smaller.size() << endl
721  << "equal = " << equal.size() << endl
722  << "total = " << total << endl
723  << "|V| = " << this->g.get_num_nodes();
724 
725  for (int i = 0; i < n; ++i)
726  {
727  auto p = this->nodes->access(i);
728 
729  const long & in_sz = NODE_COUNTER(p);
730  const size_t & out_sz = this->g.get_num_arcs(p);
731 
732  if (in_sz == out_sz)
733  {
734  if (smaller.search(p) != nullptr)
735  cout << "Inconsistency " << in_sz << "/" << out_sz << " found "
736  << " in smaller table" << endl;
737 
738  if (greater.search(p) != nullptr)
739  cout << "Inconsistency " << in_sz << "/" << out_sz << " found "
740  << " in greater table" << endl;
741 
742  if (equal.search(p) == nullptr)
743  {
744  cout << "node of same in/out degree is not in equal table"
745  << endl;
746 
747  return false;
748  }
749  }
750  else if (in_sz > out_sz)
751  {
752  if (greater.search(p) != nullptr)
753  cout << "Inconsistency " << in_sz << "/" << out_sz << " found "
754  << " in greater table" << endl;
755 
756  if (equal.search(p) != nullptr)
757  cout << "Inconsistency " << in_sz << "/" << out_sz << " found "
758  << endl;
759 
760  if (smaller.search(p) == nullptr)
761  {
762  cout << "node with " << in_sz << "/" << out_sz << " not found "
763  << "smaller table" << endl;
764 
765  return false;
766  }
767  }
768  else
769  {
770  if (smaller.search(p) != nullptr)
771  cout << "Inconsistency " << in_sz << "/" << out_sz << " found "
772  << " in smaller table" << endl;
773 
774  if (equal.search(p) != nullptr)
775  cout << "Inconsistency " << in_sz << "/" << out_sz << " found "
776  << endl;
777 
778  if (greater.search(p) == nullptr)
779  {
780  cout << "node with " << in_sz << "/" << out_sz << " not found "
781  << "greater table" << endl;
782 
783  return false;
784  }
785  }
786  }
787 
788  return true;
789  }
790 
791  // Esta llamada se efectúa justo después de insertar un nuevo
792  // arco src-->tgt. Esto implica que out(src) está actualizado, pero
793  // in(tgt) no
794  virtual void update_parity_after_arc_insertion(GT_Node * src, GT_Node * tgt)
795  {
796  if (not this->save_parity)
797  return;
798 
799  const size_t & src_out_degree = this->g.get_num_arcs(src);
800  const long & src_in_degree = NODE_COUNTER(src);
801 
802  if (src_out_degree == src_in_degree)
803  { // src está en greater ==> sacarlo y meterlo en equal
804  assert(this->smaller.search(src) != nullptr);
805  this->smaller.remove(src);
806  this->equal.insert(src);
807  }
808  else if (src_out_degree > src_in_degree)
809  if (src_out_degree == src_in_degree + 1)
810  {
811  assert(this->equal.search(src) != nullptr);
812  this->equal.remove(src);
813  this->greater.insert(src);
814  }
815  else
816  assert(this->greater.search(src) != nullptr);
817  else // src_out_degree < src_in_degree
818  assert(this->smaller.search(src) != nullptr);
819 
820  const size_t & tgt_out_degree = this->g.get_num_arcs(tgt);
821  const long tgt_in_degree = ++NODE_COUNTER(tgt);
822 
823  if (tgt_out_degree == tgt_in_degree)
824  {
825  assert(this->greater.search(tgt));
826  this->greater.remove(tgt);
827  this->equal.insert(tgt);
828  }
829  else if (tgt_out_degree > tgt_in_degree)
830  assert(this->greater.search(tgt));
831  else // (tgt_out_degree < tgt_in_degree)
832  {
833  if (tgt_in_degree - 1 == tgt_out_degree)
834  { // tgt está en equal ==> sacarlo
835  assert(this->equal.search(tgt) != nullptr);
836  this->smaller.insert(tgt);
837  this->equal.remove(tgt);
838  }
839  else
840  assert(this->smaller.search(tgt) != nullptr);
841  }
842  }
843 
844  virtual void create_nodes_and_initialize_arc_index()
845  {
846  this->nodes = unique_ptr<DynArray<GT_Node*>>
847  (new DynArray<GT_Node*>(this->num_nodes));
848 
849  this->nodes->reserve(this->num_nodes);
850 
851  for (int i = 0; i < this->num_nodes; ++i)
852  {
853  typename GT::Node * p = this->g.insert_node(new GT_Node);
854  this->nodes->access(i) = p;
855  this->init_node(this->g, p);
856 
857  if (this->save_parity)
858  {
859  NODE_COUNTER(p) = 0;
860  this->equal.insert(p);
861  }
862  }
863 
864  this->idx_arc = unique_ptr<IndexArc<GT>> (new IndexArc<GT>(this->g) );
865  }
866 
867  virtual void connect()
868  {
869  DynList<DynList<typename GT::Node*>> blk_list; // subgrafos inconexos
870 
871  { // guarda los grados de entrada puesto que el algoritmo de Tarjan
872  // los va a modificar
874  in_degree.reserve(this->g.get_num_nodes());
875 
876  typename GT::Node_Iterator it(this->g);
877  for (int i = 0; it.has_curr(); it.next_ne(), ++i)
878  in_degree.access(i) = NODE_COUNTER(it.get_curr_ne());
879 
880  Tarjan_Connected_Components <GT> () (this->g, blk_list);
881 
882  it.reset_first(); // restaurar los grados de entrada
883  for (int i = 0; it.has_curr(); it.next_ne(), ++i)
884  NODE_COUNTER(it.get_curr_ne()) = in_degree.access(i);
885  }
886 
887  const size_t & num_blocks = blk_list.size();
888 
889  if (num_blocks == 1)
890  return;
891 
892  // cada nodo de esta lista es un nodo del bloque i seleccionado
893  // aleatoriamente
894  DynArray<typename GT::Node*> b1; b1.reserve(num_blocks);
895  DynArray<typename GT::Node*> b2; b2.reserve(num_blocks);
896  {
897  typename DynList<DynList<GT_Node*>>::Iterator it(blk_list);
898  for (int i = 0; it.has_curr(); it.next_ne(), ++i)
899  { // seleccione dos nodos al azar del componente actual
900  DynList<typename GT::Node*> & list = it.get_curr_ne();
901  b1.access(i) = this->select_random_node(list);
902  b2.access(i) = this->select_random_node(list);
903  }
904  }
905 
906  for (int i = 0; i < num_blocks - 1; ++i)
907  {
908  auto src = b1.access(i); // nodo en bloque i
909  auto tgt = b1.access((i + 1) % num_blocks); // nodo en bloque i + 1
910 
911  if (this->idx_arc->search_directed(src, tgt) == nullptr)
912  this->insert_arc(src, tgt);
913 
914  src = b2.access(i); // nodo en bloque i
915  tgt = b2.access((i + 1) % num_blocks); // nodo en bloque i + 1
916 
917  if (this->idx_arc->search_directed(tgt, src) == nullptr)
918  this->insert_arc(tgt, src);
919  }
920  }
921 
922  // crea un grafo aleatorio en el cual la probabilidad por arco entre un
923  // par de nodos es p
924  virtual GT create_p(const size_t & __num_nodes, const double & p,
925  bool connected)
926  {
927  if (p > 1.0 or p <= 0.0)
928  throw std::domain_error("Invalid value for p");
929 
930  this->initialize_and_create_nodes(__num_nodes, __num_nodes);
931 
932  for (int i = 0; i < this->num_nodes; ++i)
933  {
934  auto src = this->nodes->access(i);
935  for (int j = 0; j < this->num_nodes; ++j)
936  if (i != j and gsl_rng_uniform(this->r) <= p)
937  {
938  auto tgt = this->nodes->access(j);
939  assert(this->idx_arc->search_directed(src, tgt) == nullptr);
940  this->insert_arc(src, tgt);
941  }
942  }
943 
944  if (connected)
945  connect();
946 
947  return move(this->g);
948  }
949 
950 public:
951 
958  Random_Digraph(unsigned long seed,
959  const Init_Node & __init_node,
960  const Init_Arc & __init_arc)
961  : Random_Graph_Base<GT, Init_Node, Init_Arc>(seed, __init_node, __init_arc)
962  {
963  this->g.set_digraph(true);
964  }
965 
966  Random_Digraph(unsigned long seed = time(nullptr),
967  const Init_Node && __init_node = Init_Node(),
968  const Init_Arc && __init_arc = Init_Arc())
969  : Random_Digraph(seed, __init_node, __init_arc)
970  {
971  // empty
972  }
973 
974  Random_Digraph(const Init_Node & __init_node,
975  const Init_Arc & __init_arc)
976  : Random_Digraph(time(nullptr), __init_node, __init_arc)
977  {
978  // empty
979  }
980 
981  ~Random_Digraph()
982  {
983  this->g.set_digraph(false);
984  }
985 
1002  GT operator () (const size_t & __num_nodes, const size_t & __num_arcs,
1003  bool connected = true)
1004  {
1005  return this->create(__num_nodes, __num_arcs, connected);
1006  }
1007 
1008 public:
1009 
1034  GT operator () (const size_t & __num_nodes, const double & p,
1035  bool connected = true)
1036  {
1037  return this->create_p(__num_nodes, p, connected);
1038  }
1039 
1040 private:
1041 
1042  virtual void make_eulerian()
1043  {
1044  GT_Node * src = nullptr;
1045  GT_Node * tgt = nullptr;
1046 
1047  while (this->greater.size() > 0 and this->smaller.size() > 0)
1048  {
1049  do
1050  {
1051  tgt = this->greater.select
1052  (gsl_rng_uniform_int(this->r, this->greater.size()));
1053  src = this->smaller.select
1054  (gsl_rng_uniform_int(this->r, this->smaller.size()));
1055  }
1056  while (src == tgt);
1057 
1058  if (this->idx_arc->search_directed(src, tgt) == nullptr)
1059  this->insert_arc(src, tgt);
1060  else
1061  {
1062  auto mid =
1063  this->equal.select(gsl_rng_uniform_int(this->r,
1064  this->equal.size()));
1065 
1066  while (this->idx_arc->search_directed(src, mid) != nullptr or
1067  this->idx_arc->search_directed(mid, tgt) != nullptr)
1068  mid = this->equal.select
1069  (gsl_rng_uniform_int(this->r, this->equal.size()));
1070 
1071  this->insert_arc(src, mid);
1072  this->insert_arc(mid, tgt);
1073  }
1074  }
1075  }
1076 
1077  void balance_digraph_node(GT_Node * p)
1078  {
1079  const size_t & n = this->g.get_num_nodes();
1080  const size_t n2 = n/2;
1081 
1082  while (not (this->g.get_num_arcs(p) >= n2 and NODE_COUNTER(p) >= n2))
1083  {
1084  auto q = this->nodes->access(gsl_rng_uniform_int(this->r, n));
1085  if (q == p)
1086  continue;
1087 
1088  if (this->idx_arc->search_directed(p, q) == nullptr)
1089  {
1090  this->insert_arc(p, q);
1091  NODE_COUNTER(q)++;
1092  }
1093 
1094  if (this->idx_arc->search_directed(q, p) == nullptr)
1095  {
1096  this->insert_arc(q, p);
1097  NODE_COUNTER(p)++;
1098  }
1099  }
1100  }
1101 
1102  // balancea los dos nodos para que satisfagan la condición de
1103  // hamiltoniano. Si existe arco src-->tgt
1104  void balance_digraph_nodes_degree(GT_Node * src, GT_Node * tgt)
1105  {
1106  if (this->idx_arc->search_directed(src, tgt) != nullptr)
1107  {
1108  balance_digraph_node(src);
1109  balance_digraph_node(tgt);
1110 
1111  return;
1112  }
1113 
1114  const size_t & n = this->g.get_num_nodes();
1115 
1116  while (this->g.get_num_arcs(src) + NODE_COUNTER(tgt) < n)
1117  {
1118  auto p = this->nodes->access(gsl_rng_uniform_int(this->r, n));
1119  if (p == src or p == tgt)
1120  continue;
1121 
1122  if (this->idx_arc->search_directed(src, p) == nullptr)
1123  {
1124  this->insert_arc(src, p);
1125  NODE_COUNTER(p)++;
1126 
1127  if (this->g.get_num_arcs(src) + NODE_COUNTER(tgt) == n)
1128  break;
1129  }
1130 
1131  if (this->idx_arc->search_directed(p, tgt) == nullptr)
1132  {
1133  this->insert_arc(p, tgt);
1134  NODE_COUNTER(tgt)++;
1135  }
1136  }
1137 
1138  assert(this->g.get_num_arcs(src) + NODE_COUNTER(tgt) >= n);
1139  }
1140 
1141  virtual void make_hamiltonian ()
1142  {
1143  this->g.reset_counter_nodes();
1144 
1145  // contabiliza el grado de entrada por cada nodo
1146  for (typename GT::Arc_Iterator it(this->g); it.has_curr(); it.next_ne())
1147  NODE_COUNTER(it.get_tgt_node_ne())++;
1148 
1149  const size_t & n = this->g.get_num_nodes();
1150 
1151  for (int i = 0; i < n; ++i)
1152  {
1153  auto src = this->nodes->access(i);
1154  for (int j = 0; j < n; ++j)
1155  {
1156  if (i == j)
1157  continue;
1158 
1159  auto tgt = this->nodes->access(j);
1160  balance_digraph_nodes_degree(src, tgt);
1161  }
1162  }
1163  }
1164 };
1165 
1166 }
1167 
1168 # endif // RANDOM_GRAPH_H
void reserve(const size_t l, const size_t r)
Definition: tpl_dynArray.H:998
size_t size() const noexcept
Definition: htlist.H:1240
Random_Graph(unsigned long seed, const Init_Node &__init_node, const Init_Arc &__init_arc)
Definition: random_graph.H:454
GT eulerian(const size_t &__num_nodes, const double &p)
Definition: random_graph.H:649
GT sufficient_hamiltonian(const size_t &__num_nodes, const double &p=0.5)
Definition: random_graph.H:685
size_t remove(const Key &key)
Definition: tpl_dynSetTree.H:327
size_type size()
Retorna la cantidad de elementos que tiene la lista.
Definition: List.H:366
T & access(const size_t i) const noexcept
Definition: tpl_dynArray.H:874
Key & select(const size_t &i)
Definition: tpl_dynSetTree.H:561
size_t in_degree(typename GT::Node *p, SA sa=SA())
Definition: tpl_graph.H:1948
#define NODE_COUNTER(p)
Definition: aleph-graph.H:311
GT eulerian(const size_t &__num_nodes, const size_t &__num_arcs)
Definition: random_graph.H:621
GT sufficient_hamiltonian(const size_t &__num_nodes, const double &p=0.5)
Definition: random_graph.H:279
Definition: ah-comb.H:35
Definition: tpl_dynSetTree.H:991
Definition: random_graph.H:335
const size_t & size() const
Retorna la cardinalidad del conjunto.
Definition: tpl_dynSetTree.H:502
Definition: tpl_indexArc.H:67
T & append()
Definition: tpl_dynArray.H:1149
Definition: tpl_dynArray.H:159
Definition: tpl_components.H:207
Definition: ahDry.H:41
Definition: List.H:49
Key * insert(const Key &key)
Definition: tpl_dynSetTree.H:195
Key * search(const Key &key) const
Definition: tpl_dynSetTree.H:462
Definition: Tarjan.H:52

Leandro Rabindranath León