aGrUM  0.21.0
a C++ library for (probabilistic) graphical models
MCBayesNetGenerator_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by 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 >::MCBayesNetGenerator(
58  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(OperationNotAllowed,
68  "the sum of the probabilities p and q must be at most equal to 100");
69 
70  iteration_ = iteration;
71  p_ = p;
72  q_ = q;
73  disturbing_ = false;
74 
75  GUM_CONSTRUCTOR(MCBayesNetGenerator);
76  }
77 
78  template < typename GUM_SCALAR,
79  template < typename >
80  class ICPTGenerator,
81  template < typename >
82  class ICPTDisturber >
86  Idx p,
87  Idx q) :
89  (Size)(bayesNet.sizeArcs() * 1.1),
92  p_ = p;
93  q_ = q;
94  disturbing_ = false;
95  }
96 
97  // Destructor.
98  template < typename GUM_SCALAR,
99  template < typename >
100  class ICPTGenerator,
101  template < typename >
102  class ICPTDisturber >
105  }
106 
107  template < typename GUM_SCALAR,
108  template < typename >
109  class ICPTGenerator,
110  template < typename >
111  class ICPTDisturber >
115 
116  // this->bayesNet_ = bayesNet;
117  _createTree_(this->nbrNodes_);
118  _transformPoly_(this->nbrNodes_ / 2);
119  bayesNettemp_ = this->bayesNet_;
120  _PMMx_poly_();
121 
122  this->fillCPT();
124 
125  bayesNet = this->bayesNet_;
126  }
127 
128  // density represent de
129  template < typename GUM_SCALAR,
130  template < typename >
131  class ICPTGenerator,
132  template < typename >
133  class ICPTDisturber >
136  Size iteration) { // insert option for the variation
137  disturbing_ = true;
138  Size iter = iteration_;
139 
141 
142  this->bayesNet_ = bayesNetinit;
143 
144  if (_checkConditions_()) {
146  inf.makeInference();
147 
148  for (auto node: bayesNetinit.nodes()) {
149  auto pottemp = new Potential< GUM_SCALAR >();
152  }
153 
154  bayesNettemp_ = this->bayesNet_;
155 
156  if (_isPolytree_())
157  _PMMx_poly_();
158  else
159  _PMMx_multi_();
160 
161  bayesNetinit = (this->bayesNet_);
162 
163  while (hashMarginal_.size()) {
164  delete (hashMarginal_.begin().val());
165  hashMarginal_.erase(hashMarginal_.beginSafe()); // safe iterator needed here.
166  }
167 
168  } else {
169  std::cout << this->bayesNet_.toDot() << std::endl;
170  GUM_ERROR(OperationNotAllowed, "BN is not valid cause it does not respect constraint ")
171  }
172 
173  iteration_ = iter;
174  disturbing_ = false;
175  }
176 
177  template < typename GUM_SCALAR,
178  template < typename >
179  class ICPTGenerator,
180  template < typename >
181  class ICPTDisturber >
183  return this->maxArcs_ >= this->bayesNet_.sizeArcs();
184  }
185 
186  // main algorithme for moving between state of the IBayesNet according on the
187  // nature of the topology polytree or multi-connected
188 
189  template < typename GUM_SCALAR,
190  template < typename >
191  class ICPTGenerator,
192  template < typename >
193  class ICPTDisturber >
195  if (!iteration_--) return;
196 
197  Idx per = randomValue(100);
198 
199  if (per < p_) {
200  _AorR_();
201 
202  if (_checkConditions_()) {
203  bayesNettemp_ = this->bayesNet_;
204  _PMMx_multi_();
205  } else {
206  this->bayesNet_ = bayesNettemp_;
207  _PMMx_poly_();
208  }
209  } else {
210  if (per < p_ + q_) {
211  _AR_();
212 
213  if (!_checkConditions_()) {
214  this->bayesNet_ = bayesNettemp_;
215  } else
216  bayesNettemp_ = this->bayesNet_;
217 
218  _PMMx_poly_();
219  } else {
220  _jump_poly_();
221 
222  if (_checkConditions_()) {
223  bayesNettemp_ = this->bayesNet_;
224  _PMMx_multi_();
225 
226  } else {
227  this->bayesNet_ = bayesNettemp_;
228  _PMMx_poly_();
229  }
230  }
231  }
232  }
233 
234  template < typename GUM_SCALAR,
235  template < typename >
236  class ICPTGenerator,
237  template < typename >
238  class ICPTDisturber >
240  if (!iteration_--) return;
241 
242  Idx per = randomValue(100);
243 
244  if (per < p_ + q_) {
245  _AorR_();
246 
247  if (_checkConditions_()) {
248  if (_isPolytree_()) {
249  if (per < p_) {
250  bayesNettemp_ = this->bayesNet_;
251  _PMMx_poly_();
252  } else {
253  this->bayesNet_ = bayesNettemp_;
254  _PMMx_multi_();
255  }
256  } else {
257  bayesNettemp_ = this->bayesNet_;
258  _PMMx_multi_();
259  }
260  } else {
261  this->bayesNet_ = bayesNettemp_;
262  _PMMx_multi_();
263  }
264  } else {
265  _jump_multi_();
266 
267  if (_checkConditions_()) {
268  bayesNettemp_ = this->bayesNet_;
269 
270  if (_isPolytree_())
271  _PMMx_poly_();
272  else
273  _PMMx_multi_();
274 
275  } else {
276  this->bayesNet_ = bayesNettemp_;
277  _PMMx_multi_();
278  }
279  }
280  }
281 
282  template < typename GUM_SCALAR,
283  template < typename >
284  class ICPTGenerator,
285  template < typename >
286  class ICPTDisturber >
288  NodeId i, j;
289  _chooseNodes_(i, j);
290  const DAG _dag_ = this->bayesNet_.dag();
291 
292  if (_dag_.existsArc(i, j)) {
293  _eraseArc_(i, j);
294 
295  return;
296  } else
297  _insertArc_(i, j);
298  }
299 
300  template < typename GUM_SCALAR,
301  template < typename >
302  class ICPTGenerator,
303  template < typename >
304  class ICPTDisturber >
306  NodeId i, j, head, tail;
307  _chooseNodes_(i, j);
308  const DAG _dag_ = this->bayesNet_.dag();
309 
310  if (_dag_.existsArc(i, j) || _dag_.existsArc(j, i)) {
311  return;
312  } else {
313  Idx per = randomValue(100);
314 
315  if (per < 50) {
316  head = i;
317  tail = j;
318  } else {
319  head = j;
320  tail = i;
321  }
322 
323  for (auto node: _dag_.parents(j)) {
325  excluded.insert(j);
326 
327  if (_connect_(node, i, excluded)) {
328  this->bayesNet_.eraseArc(node, j);
329  this->bayesNet_.addArc(head, tail);
330  return;
331  }
332  }
333 
334  for (auto node: _dag_.children(j)) {
336  excluded.insert(j);
337 
338  if (_connect_(node, i, excluded)) {
339  this->bayesNet_.eraseArc(j, node);
340  this->bayesNet_.addArc(head, tail);
341  return;
342  }
343  }
344  }
345  }
346 
347  template < typename GUM_SCALAR,
348  template < typename >
349  class ICPTGenerator,
350  template < typename >
351  class ICPTDisturber >
353  NodeId i, j;
354  _chooseNodes_(i, j);
355  const DAG _dag_ = this->bayesNet_.dag();
356 
357  if (!_dag_.existsArc(i, j)) _insertArc_(i, j);
358  }
359 
360  template < typename GUM_SCALAR,
361  template < typename >
362  class ICPTGenerator,
363  template < typename >
364  class ICPTDisturber >
366  NodeId i, j;
367  _chooseNodes_(i, j);
368  const DAG _dag_ = this->bayesNet_.dag();
369 
370  if (_dag_.existsArc(i, j)) { _eraseArc_(i, j); }
371  }
372 
373  template < typename GUM_SCALAR,
374  template < typename >
375  class ICPTGenerator,
376  template < typename >
377  class ICPTDisturber >
378  INLINE void
380  NodeId j) {
381  if (_directedPath_(j, i)) return;
382 
383  if (disturbing_) {
384  auto potj = this->bayesNet_.cpt(j);
385  this->bayesNet_.addArc(i, j);
386 
387  this->disturbAugmCPT(j, this->bayesNet_, potj, (GUM_SCALAR)0.5);
388  } else
389  this->bayesNet_.addArc(i, j);
390  }
391 
392  template < typename GUM_SCALAR,
393  template < typename >
394  class ICPTGenerator,
395  template < typename >
396  class ICPTDisturber >
398  NodeId i,
399  NodeId j,
400  bool mustbeconnex) {
401  if (disturbing_) {
402  const BayesNet< GUM_SCALAR > bayesNet(this->bayesNet_);
404  potj.copy(this->bayesNet_.cpt(j));
405  this->bayesNet_.eraseArc(i, j);
406 
407  if (_connect_(i, j) || !mustbeconnex) {
408  auto marg = *hashMarginal_[i];
409 
410  this->disturbReducCPT(j, this->bayesNet_, potj, marg);
411  } else
412  this->bayesNet_.addArc(i, j);
413  } else {
414  this->bayesNet_.eraseArc(i, j);
415 
416  if (!_connect_(i, j) && mustbeconnex) { this->bayesNet_.addArc(i, j); }
417  }
418  }
419 
420  template < typename GUM_SCALAR,
421  template < typename >
422  class ICPTGenerator,
423  template < typename >
424  class ICPTDisturber >
425  INLINE void
427  NodeId& j) {
428  i = randomValue(this->bayesNet_.size());
429  j = randomValue(this->bayesNet_.size());
430 
431  while (i == j)
432  j = randomValue(this->bayesNet_.size());
433  }
434 
435  template < typename GUM_SCALAR,
436  template < typename >
437  class ICPTGenerator,
438  template < typename >
439  class ICPTDisturber >
441  NodeId& i,
442  NodeId& j) {
443  NodeId temp = randomValue(this->bayesNet_.size());
444  Size co = 0;
445 
446  if (this->bayesNet_.parents(temp).size()) {
447  j = temp;
448  auto it = this->bayesNet_.parents(j).begin();
449  co = randomValue(this->bayesNet_.parents(j).size());
450 
451  while (co--) {
452  ++it;
453  }
454 
455  i = *it;
456  } else if (this->bayesNet_.children(temp).size()) {
457  i = temp;
458  auto it = this->bayesNet_.children(i).begin();
459  co = randomValue(this->bayesNet_.children(i).size());
460 
461  while (co--) {
462  ++it;
463  }
464 
465  j = *it;
466  } else {
467  GUM_ERROR(FatalError, "Sorry Misconstructed BN because of isolated node.")
468  }
469  }
470 
471  template < typename GUM_SCALAR,
472  template < typename >
473  class ICPTGenerator,
474  template < typename >
475  class ICPTDisturber >
477  Idx n = 0;
478  Size nb_mod = 2 + randomValue(this->maxModality_ - 1);
480  strBuff << "n_" << n++;
482  Size maxNodes = BNSize - 1;
483  Size SubG = 0;
484 
485  while (maxNodes) {
486  SubG = randomValue(maxNodes) + 1;
487  maxNodes = maxNodes - SubG;
489  this->bayesNet_.addArc(root, rootS);
490  }
491  }
492 
493  template < typename GUM_SCALAR,
494  template < typename >
495  class ICPTGenerator,
496  template < typename >
497  class ICPTDisturber >
498  NodeId
500  Idx& n) {
501  Size nb_mod = 2 + randomValue(this->maxModality_ - 1);
503  strBuff << "n_" << n++;
505  Size maxNodes = BNSize - 1;
506  Size SubG = 0;
507 
508  while (maxNodes) {
509  SubG = randomValue(maxNodes) + 1;
510  maxNodes = maxNodes - SubG;
512  this->bayesNet_.addArc(root, rootS);
513  }
514 
515  return root;
516  }
517 
518  // Allow to invert maximum nbiter arc to use from polytree only
519  template < typename GUM_SCALAR,
520  template < typename >
521  class ICPTGenerator,
522  template < typename >
523  class ICPTDisturber >
524  void
526  while (nbiter--) {
527  NodeId i, j;
529  bayesNettemp_ = this->bayesNet_;
530  _eraseArc_(i, j, false);
531  this->bayesNet_.addArc(j, i);
532 
533  if (!_checkConditions_()) this->bayesNet_ = bayesNettemp_;
534  }
535  }
536 
537  template < typename GUM_SCALAR,
538  template < typename >
539  class ICPTGenerator,
540  template < typename >
541  class ICPTDisturber >
543  const DAG _dag_ = this->bayesNet_.dag();
544  return this->bayesNet_.size() - 1 == this->bayesNet_.sizeArcs();
545  }
546 
547  template < typename GUM_SCALAR,
548  template < typename >
549  class ICPTGenerator,
550  template < typename >
551  class ICPTDisturber >
553  const NodeId j) {
554  const DAG _dag_ = this->bayesNet_.dag();
555 
556  if (_dag_.existsArc(i, j) || _dag_.existsArc(j, i))
557  return true;
558  else {
560  excluded.insert(i);
561 
562  for (auto par: _dag_.parents(i)) {
563  if (!excluded.exists(par) && _connect_(par, j, excluded)) return true;
564  }
565 
566  for (auto chi: _dag_.children(i)) {
567  if (!excluded.exists(chi) && _connect_(chi, j, excluded)) return true;
568  }
569 
570  return false;
571  }
572  }
573 
574  template < typename GUM_SCALAR,
575  template < typename >
576  class ICPTGenerator,
577  template < typename >
578  class ICPTDisturber >
579  bool
581  const NodeId j,
582  NodeSet& excluded) {
583  const DAG _dag_ = this->bayesNet_.dag();
584 
585  if (_dag_.existsArc(i, j) || _dag_.existsArc(j, i))
586  return true;
587  else {
588  excluded.insert(i);
589 
590  for (auto par: _dag_.parents(i)) {
591  if (!excluded.exists(par) && _connect_(par, j, excluded)) return true;
592  }
593 
594  for (auto chi: _dag_.children(i)) {
595  if (!excluded.exists(chi) && _connect_(chi, j, excluded)) return true;
596  }
597 
598  return false;
599  }
600  }
601 
602  template < typename GUM_SCALAR,
603  template < typename >
604  class ICPTGenerator,
605  template < typename >
606  class ICPTDisturber >
607  bool
609  NodeId head) {
610  const DAG _dag_ = this->bayesNet_.dag();
611 
612  if (_dag_.existsArc(tail, head))
613  return true;
614  else {
617 
618  for (auto node: _dag_.children(tail)) {
619  if (_directedPath_(node, head, excluded)) return true;
620  }
621 
622  return false;
623  }
624  }
625 
626  template < typename GUM_SCALAR,
627  template < typename >
628  class ICPTGenerator,
629  template < typename >
630  class ICPTDisturber >
632  NodeId tail,
633  NodeId head,
634  NodeSet& excluded) {
635  const DAG _dag_ = this->bayesNet_.dag();
636 
637  if (_dag_.existsArc(tail, head))
638  return true;
639  else {
641 
642  for (auto node: _dag_.children(tail)) {
643  if (!excluded.exists(node) && _directedPath_(node, head, excluded)) return true;
644  }
645 
646  return false;
647  }
648  }
649 
650  template < typename GUM_SCALAR,
651  template < typename >
652  class ICPTGenerator,
653  template < typename >
654  class ICPTDisturber >
656  return iteration_;
657  }
658 
659  template < typename GUM_SCALAR,
660  template < typename >
661  class ICPTGenerator,
662  template < typename >
663  class ICPTDisturber >
665  return p_;
666  }
667 
668  template < typename GUM_SCALAR,
669  template < typename >
670  class ICPTGenerator,
671  template < typename >
672  class ICPTDisturber >
674  return q_;
675  }
676 
677  template < typename GUM_SCALAR,
678  template < typename >
679  class ICPTGenerator,
680  template < typename >
681  class ICPTDisturber >
682  INLINE void
685  }
686  template < typename GUM_SCALAR,
687  template < typename >
688  class ICPTGenerator,
689  template < typename >
690  class ICPTDisturber >
692  p_ = p;
693 
694  if (p + q_ > 100)
696  "the sum of the probabilities p and q must be at most equal to 100");
697  }
698  template < typename GUM_SCALAR,
699  template < typename >
700  class ICPTGenerator,
701  template < typename >
702  class ICPTDisturber >
704  q_ = q;
705 
706  if (p_ + q > 100)
708  "the sum of the probabilities p and q must be at most equal to 100");
709  }
710 
711 } /* namespace gum */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643
gum::Size getMaxModality(gum::BayesNet< GUM_SCALAR > &bayesNet)