aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
MCBayesNetGenerator_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /** @file
23  * @brief Source implementation of MCBayesNetGenerator
24  *
25  * @author Pierre-Henri WUILLEMIN(@LIP6) and Ariele-Paolo MAESANO
26  *
27  */
28 
29 #include <agrum/BN/generator/MCBayesNetGenerator.h>
30 
31 namespace gum {
32 
33 #ifdef _MSC_VER
34 # define IBNG IBayesNetGenerator
35 #else
36 # define IBNG IBayesNetGenerator< GUM_SCALAR, ICPTGenerator >
37 #endif
38 
39  template < typename GUM_SCALAR >
41  gum::Size maxMod = 0;
42 
43  for (auto node: bayesNet.nodes())
46 
47  return maxMod;
48  }
49 
50  // Default constructor.
51  // Use the SimpleCPTGenerator for generating the BNs CPT.
52  template < typename GUM_SCALAR,
53  template < typename >
54  class ICPTGenerator,
55  template < typename >
56  class ICPTDisturber >
57  MCBayesNetGenerator< GUM_SCALAR, ICPTGenerator, ICPTDisturber >::
58  MCBayesNetGenerator(Size nbrNodes,
59  Size maxArcs,
60  Idx maxModality,
61  Size iteration,
62  Idx p,
63  Idx q) :
64  IBNG(nbrNodes, maxArcs, maxModality),
65  bayesNettemp_(), hashMarginal_() {
66  if (p + q > 100)
67  GUM_ERROR(
68  OperationNotAllowed,
69  "the sum of the probabilities p and q must be at most equal to 100");
70 
71  iteration_ = iteration;
72  p_ = p;
73  q_ = q;
74  disturbing_ = false;
75 
76  GUM_CONSTRUCTOR(MCBayesNetGenerator);
77  }
78 
79  template < typename GUM_SCALAR,
80  template < typename >
81  class ICPTGenerator,
82  template < typename >
83  class ICPTDisturber >
87  Idx p,
88  Idx q) :
90  (Size)(bayesNet.sizeArcs() * 1.1),
93  p_ = p;
94  q_ = q;
95  disturbing_ = false;
96  }
97 
98  // Destructor.
99  template < typename GUM_SCALAR,
100  template < typename >
101  class ICPTGenerator,
102  template < typename >
103  class ICPTDisturber >
107  }
108 
109  template < typename GUM_SCALAR,
110  template < typename >
111  class ICPTGenerator,
112  template < typename >
113  class ICPTDisturber >
117 
118  // this->bayesNet_ = bayesNet;
119  createTree__(this->nbrNodes_);
120  transformPoly__(this->nbrNodes_ / 2);
121  bayesNettemp_ = this->bayesNet_;
122  PMMx_poly__();
123 
124  this->fillCPT();
126 
127  bayesNet = this->bayesNet_;
128  }
129 
130  // density represent de
131  template < typename GUM_SCALAR,
132  template < typename >
133  class ICPTGenerator,
134  template < typename >
135  class ICPTDisturber >
138  Size iteration) { // insert option for the variation
139  disturbing_ = true;
140  Size iter = iteration_;
141 
143 
144  this->bayesNet_ = bayesNetinit;
145 
146  if (checkConditions__()) {
148  inf.makeInference();
149 
150  for (auto node: bayesNetinit.nodes()) {
151  auto pottemp = new Potential< GUM_SCALAR >();
154  }
155 
156  bayesNettemp_ = this->bayesNet_;
157 
158  if (isPolytree__())
159  PMMx_poly__();
160  else
161  PMMx_multi__();
162 
163  bayesNetinit = (this->bayesNet_);
164 
165  while (hashMarginal_.size()) {
166  delete (hashMarginal_.begin().val());
168  hashMarginal_.beginSafe()); // safe iterator needed here.
169  }
170 
171  } else {
172  std::cout << this->bayesNet_.toDot() << std::endl;
174  "BN is not valid cause it does not respect constraint ");
175  }
176 
177  iteration_ = iter;
178  disturbing_ = false;
179  }
180 
181  template < typename GUM_SCALAR,
182  template < typename >
183  class ICPTGenerator,
184  template < typename >
185  class ICPTDisturber >
188  return this->maxArcs_ >= this->bayesNet_.sizeArcs();
189  }
190 
191  // main algorithme for moving between state of the IBayesNet according on the
192  // nature of the topology polytree or multi-connected
193 
194  template < typename GUM_SCALAR,
195  template < typename >
196  class ICPTGenerator,
197  template < typename >
198  class ICPTDisturber >
201  if (!iteration_--) return;
202 
203  Idx per = randomValue(100);
204 
205  if (per < p_) {
206  AorR__();
207 
208  if (checkConditions__()) {
209  bayesNettemp_ = this->bayesNet_;
210  PMMx_multi__();
211  } else {
212  this->bayesNet_ = bayesNettemp_;
213  PMMx_poly__();
214  }
215  } else {
216  if (per < p_ + q_) {
217  AR__();
218 
219  if (!checkConditions__()) {
220  this->bayesNet_ = bayesNettemp_;
221  } else
222  bayesNettemp_ = this->bayesNet_;
223 
224  PMMx_poly__();
225  } else {
226  jump_poly__();
227 
228  if (checkConditions__()) {
229  bayesNettemp_ = this->bayesNet_;
230  PMMx_multi__();
231 
232  } else {
233  this->bayesNet_ = bayesNettemp_;
234  PMMx_poly__();
235  }
236  }
237  }
238  }
239 
240  template < typename GUM_SCALAR,
241  template < typename >
242  class ICPTGenerator,
243  template < typename >
244  class ICPTDisturber >
247  if (!iteration_--) return;
248 
249  Idx per = randomValue(100);
250 
251  if (per < p_ + q_) {
252  AorR__();
253 
254  if (checkConditions__()) {
255  if (isPolytree__()) {
256  if (per < p_) {
257  bayesNettemp_ = this->bayesNet_;
258  PMMx_poly__();
259  } else {
260  this->bayesNet_ = bayesNettemp_;
261  PMMx_multi__();
262  }
263  } else {
264  bayesNettemp_ = this->bayesNet_;
265  PMMx_multi__();
266  }
267  } else {
268  this->bayesNet_ = bayesNettemp_;
269  PMMx_multi__();
270  }
271  } else {
272  jump_multi__();
273 
274  if (checkConditions__()) {
275  bayesNettemp_ = this->bayesNet_;
276 
277  if (isPolytree__())
278  PMMx_poly__();
279  else
280  PMMx_multi__();
281 
282  } else {
283  this->bayesNet_ = bayesNettemp_;
284  PMMx_multi__();
285  }
286  }
287  }
288 
289  template < typename GUM_SCALAR,
290  template < typename >
291  class ICPTGenerator,
292  template < typename >
293  class ICPTDisturber >
295  NodeId i, j;
296  chooseNodes__(i, j);
297  const DAG dag__ = this->bayesNet_.dag();
298 
299  if (dag__.existsArc(i, j)) {
300  eraseArc__(i, j);
301 
302  return;
303  } else
304  insertArc__(i, j);
305  }
306 
307  template < typename GUM_SCALAR,
308  template < typename >
309  class ICPTGenerator,
310  template < typename >
311  class ICPTDisturber >
313  NodeId i, j, head, tail;
314  chooseNodes__(i, j);
315  const DAG dag__ = this->bayesNet_.dag();
316 
317  if (dag__.existsArc(i, j) || dag__.existsArc(j, i)) {
318  return;
319  } else {
320  Idx per = randomValue(100);
321 
322  if (per < 50) {
323  head = i;
324  tail = j;
325  } else {
326  head = j;
327  tail = i;
328  }
329 
330  for (auto node: dag__.parents(j)) {
332  excluded.insert(j);
333 
334  if (connect__(node, i, excluded)) {
335  this->bayesNet_.eraseArc(node, j);
336  this->bayesNet_.addArc(head, tail);
337  return;
338  }
339  }
340 
341  for (auto node: dag__.children(j)) {
343  excluded.insert(j);
344 
345  if (connect__(node, i, excluded)) {
346  this->bayesNet_.eraseArc(j, node);
347  this->bayesNet_.addArc(head, tail);
348  return;
349  }
350  }
351  }
352  }
353 
354  template < typename GUM_SCALAR,
355  template < typename >
356  class ICPTGenerator,
357  template < typename >
358  class ICPTDisturber >
361  NodeId i, j;
362  chooseNodes__(i, j);
363  const DAG dag__ = this->bayesNet_.dag();
364 
365  if (!dag__.existsArc(i, j)) insertArc__(i, j);
366  }
367 
368  template < typename GUM_SCALAR,
369  template < typename >
370  class ICPTGenerator,
371  template < typename >
372  class ICPTDisturber >
375  NodeId i, j;
376  chooseNodes__(i, j);
377  const DAG dag__ = this->bayesNet_.dag();
378 
379  if (dag__.existsArc(i, j)) { eraseArc__(i, j); }
380  }
381 
382  template < typename GUM_SCALAR,
383  template < typename >
384  class ICPTGenerator,
385  template < typename >
386  class ICPTDisturber >
387  INLINE void
389  NodeId i,
390  NodeId j) {
391  if (directedPath__(j, i)) return;
392 
393  if (disturbing_) {
394  auto potj = this->bayesNet_.cpt(j);
395  this->bayesNet_.addArc(i, j);
396 
397  this->disturbAugmCPT(j, this->bayesNet_, potj, (GUM_SCALAR)0.5);
398  } else
399  this->bayesNet_.addArc(i, j);
400  }
401 
402  template < typename GUM_SCALAR,
403  template < typename >
404  class ICPTGenerator,
405  template < typename >
406  class ICPTDisturber >
407  INLINE void
409  NodeId i,
410  NodeId j,
411  bool mustbeconnex) {
412  if (disturbing_) {
413  const BayesNet< GUM_SCALAR > bayesNet(this->bayesNet_);
415  potj.copy(this->bayesNet_.cpt(j));
416  this->bayesNet_.eraseArc(i, j);
417 
418  if (connect__(i, j) || !mustbeconnex) {
419  auto marg = *hashMarginal_[i];
420 
421  this->disturbReducCPT(j, this->bayesNet_, potj, marg);
422  } else
423  this->bayesNet_.addArc(i, j);
424  } else {
425  this->bayesNet_.eraseArc(i, j);
426 
427  if (!connect__(i, j) && mustbeconnex) { this->bayesNet_.addArc(i, j); }
428  }
429  }
430 
431  template < typename GUM_SCALAR,
432  template < typename >
433  class ICPTGenerator,
434  template < typename >
435  class ICPTDisturber >
438  i = randomValue(this->bayesNet_.size());
439  j = randomValue(this->bayesNet_.size());
440 
441  while (i == j)
442  j = randomValue(this->bayesNet_.size());
443  }
444 
445  template < typename GUM_SCALAR,
446  template < typename >
447  class ICPTGenerator,
448  template < typename >
449  class ICPTDisturber >
452  NodeId temp = randomValue(this->bayesNet_.size());
453  Size co = 0;
454 
455  if (this->bayesNet_.parents(temp).size()) {
456  j = temp;
457  auto it = this->bayesNet_.parents(j).begin();
458  co = randomValue(this->bayesNet_.parents(j).size());
459 
460  while (co--) {
461  ++it;
462  }
463 
464  i = *it;
465  } else if (this->bayesNet_.children(temp).size()) {
466  i = temp;
467  auto it = this->bayesNet_.children(i).begin();
468  co = randomValue(this->bayesNet_.children(i).size());
469 
470  while (co--) {
471  ++it;
472  }
473 
474  j = *it;
475  } else {
476  GUM_ERROR(FatalError, "Sorry Misconstructed BN because of isolated node.");
477  }
478  }
479 
480  template < typename GUM_SCALAR,
481  template < typename >
482  class ICPTGenerator,
483  template < typename >
484  class ICPTDisturber >
485  void
487  Size BNSize) {
488  Idx n = 0;
489  Size nb_mod = 2 + randomValue(this->maxModality_ - 1);
491  strBuff << "n_" << n++;
492  NodeId root
493  = this->bayesNet_.add(LabelizedVariable(strBuff.str(), "", nb_mod));
494  Size maxNodes = BNSize - 1;
495  Size SubG = 0;
496 
497  while (maxNodes) {
498  SubG = randomValue(maxNodes) + 1;
499  maxNodes = maxNodes - SubG;
501  this->bayesNet_.addArc(root, rootS);
502  }
503  }
504 
505  template < typename GUM_SCALAR,
506  template < typename >
507  class ICPTGenerator,
508  template < typename >
509  class ICPTDisturber >
512  Size nb_mod = 2 + randomValue(this->maxModality_ - 1);
514  strBuff << "n_" << n++;
515  NodeId root
516  = this->bayesNet_.add(LabelizedVariable(strBuff.str(), "", nb_mod));
517  Size maxNodes = BNSize - 1;
518  Size SubG = 0;
519 
520  while (maxNodes) {
521  SubG = randomValue(maxNodes) + 1;
522  maxNodes = maxNodes - SubG;
524  this->bayesNet_.addArc(root, rootS);
525  }
526 
527  return root;
528  }
529 
530  // Allow to invert maximum nbiter arc to use from polytree only
531  template < typename GUM_SCALAR,
532  template < typename >
533  class ICPTGenerator,
534  template < typename >
535  class ICPTDisturber >
538  while (nbiter--) {
539  NodeId i, j;
541  bayesNettemp_ = this->bayesNet_;
542  eraseArc__(i, j, false);
543  this->bayesNet_.addArc(j, i);
544 
545  if (!checkConditions__()) this->bayesNet_ = bayesNettemp_;
546  }
547  }
548 
549  template < typename GUM_SCALAR,
550  template < typename >
551  class ICPTGenerator,
552  template < typename >
553  class ICPTDisturber >
556  const DAG dag__ = this->bayesNet_.dag();
557  return this->bayesNet_.size() - 1 == this->bayesNet_.sizeArcs();
558  }
559 
560  template < typename GUM_SCALAR,
561  template < typename >
562  class ICPTGenerator,
563  template < typename >
564  class ICPTDisturber >
566  const NodeId i,
567  const NodeId j) {
568  const DAG dag__ = this->bayesNet_.dag();
569 
570  if (dag__.existsArc(i, j) || dag__.existsArc(j, i))
571  return true;
572  else {
574  excluded.insert(i);
575 
576  for (auto par: dag__.parents(i)) {
577  if (!excluded.exists(par) && connect__(par, j, excluded)) return true;
578  }
579 
580  for (auto chi: dag__.children(i)) {
581  if (!excluded.exists(chi) && connect__(chi, j, excluded)) return true;
582  }
583 
584  return false;
585  }
586  }
587 
588  template < typename GUM_SCALAR,
589  template < typename >
590  class ICPTGenerator,
591  template < typename >
592  class ICPTDisturber >
594  const NodeId i,
595  const NodeId j,
596  NodeSet& excluded) {
597  const DAG dag__ = this->bayesNet_.dag();
598 
599  if (dag__.existsArc(i, j) || dag__.existsArc(j, i))
600  return true;
601  else {
602  excluded.insert(i);
603 
604  for (auto par: dag__.parents(i)) {
605  if (!excluded.exists(par) && connect__(par, j, excluded)) return true;
606  }
607 
608  for (auto chi: dag__.children(i)) {
609  if (!excluded.exists(chi) && connect__(chi, j, excluded)) return true;
610  }
611 
612  return false;
613  }
614  }
615 
616  template < typename GUM_SCALAR,
617  template < typename >
618  class ICPTGenerator,
619  template < typename >
620  class ICPTDisturber >
623  const DAG dag__ = this->bayesNet_.dag();
624 
625  if (dag__.existsArc(tail, head))
626  return true;
627  else {
630 
631  for (auto node: dag__.children(tail)) {
632  if (directedPath__(node, head, excluded)) return true;
633  }
634 
635  return false;
636  }
637  }
638 
639  template < typename GUM_SCALAR,
640  template < typename >
641  class ICPTGenerator,
642  template < typename >
643  class ICPTDisturber >
646  const DAG dag__ = this->bayesNet_.dag();
647 
648  if (dag__.existsArc(tail, head))
649  return true;
650  else {
652 
653  for (auto node: dag__.children(tail)) {
655  return true;
656  }
657 
658  return false;
659  }
660  }
661 
662  template < typename GUM_SCALAR,
663  template < typename >
664  class ICPTGenerator,
665  template < typename >
666  class ICPTDisturber >
667  INLINE Size
669  const {
670  return iteration_;
671  }
672 
673  template < typename GUM_SCALAR,
674  template < typename >
675  class ICPTGenerator,
676  template < typename >
677  class ICPTDisturber >
678  INLINE Idx
680  return p_;
681  }
682 
683  template < typename GUM_SCALAR,
684  template < typename >
685  class ICPTGenerator,
686  template < typename >
687  class ICPTDisturber >
688  INLINE Idx
690  return q_;
691  }
692 
693  template < typename GUM_SCALAR,
694  template < typename >
695  class ICPTGenerator,
696  template < typename >
697  class ICPTDisturber >
698  INLINE void
700  Size iteration) {
702  }
703  template < typename GUM_SCALAR,
704  template < typename >
705  class ICPTGenerator,
706  template < typename >
707  class ICPTDisturber >
708  INLINE void
710  p_ = p;
711 
712  if (p + q_ > 100)
713  GUM_ERROR(
715  "the sum of the probabilities p and q must be at most equal to 100");
716  }
717  template < typename GUM_SCALAR,
718  template < typename >
719  class ICPTGenerator,
720  template < typename >
721  class ICPTDisturber >
722  INLINE void
724  q_ = q;
725 
726  if (p_ + q > 100)
727  GUM_ERROR(
729  "the sum of the probabilities p and q must be at most equal to 100");
730  }
731 
732 } /* namespace gum */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669
gum::Size getMaxModality(gum::BayesNet< GUM_SCALAR > &bayesNet)