aGrUM  0.14.2
MCBayesNetGenerator_tpl.h
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005 by Pierre-Henri WUILLEMIN & Ariele-Paolo MAESANO *
3  * {prenom.nom}_at_lip6.fr *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
28 
29 namespace gum {
30 
31 #ifdef _MSC_VER
32 # define IBNG IBayesNetGenerator
33 #else
34 # define IBNG IBayesNetGenerator< GUM_SCALAR, ICPTGenerator >
35 #endif
36 
37  template < typename GUM_SCALAR >
39  gum::Size maxMod = 0;
40 
41  for (auto node : bayesNet.nodes())
42  if (maxMod < bayesNet.variable(node).domainSize())
43  maxMod = bayesNet.variable(node).domainSize();
44 
45  return maxMod;
46  }
47 
48  // Default constructor.
49  // Use the SimpleCPTGenerator for generating the BNs CPT.
50  template < typename GUM_SCALAR,
51  template < typename >
52  class ICPTGenerator,
53  template < typename >
54  class ICPTDisturber >
57  Size maxArcs,
58  Idx maxModality,
59  Size iteration,
60  Idx p,
61  Idx q) :
62  IBNG(nbrNodes, maxArcs, maxModality),
63  _bayesNettemp(), _hashMarginal() {
64  if (p + q > 100)
65  GUM_ERROR(
67  "the sum of the probabilities p and q must be at most equal to 100");
68 
70  _p = p;
71  _q = q;
72  _disturbing = false;
73 
74  GUM_CONSTRUCTOR(MCBayesNetGenerator);
75  }
76 
77  template < typename GUM_SCALAR,
78  template < typename >
79  class ICPTGenerator,
80  template < typename >
81  class ICPTDisturber >
85  Idx p,
86  Idx q) :
87  MCBayesNetGenerator(bayesNet.size(),
88  (Size)(bayesNet.sizeArcs() * 1.1),
89  getMaxModality(bayesNet)) {
91  _p = p;
92  _q = q;
93  _disturbing = false;
94  }
95 
96  // Destructor.
97  template < typename GUM_SCALAR,
98  template < typename >
99  class ICPTGenerator,
100  template < typename >
101  class ICPTDisturber >
104  GUM_DESTRUCTOR(MCBayesNetGenerator);
105  }
106 
107  template < typename GUM_SCALAR,
108  template < typename >
109  class ICPTGenerator,
110  template < typename >
111  class ICPTDisturber >
113  BayesNet< GUM_SCALAR >& bayesNet) {
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 >
135  BayesNet< GUM_SCALAR >& bayesNetinit,
136  Size iteration) { // insert option for the variation
137  _disturbing = true;
138  Size iter = _iteration;
139 
140  if (iteration) _iteration = iteration;
141 
142  this->_bayesNet = bayesNetinit;
143 
144  if (__checkConditions()) {
145  LazyPropagation< GUM_SCALAR > inf(&bayesNetinit);
146  inf.makeInference();
147 
148  for (auto node : bayesNetinit.nodes()) {
149  auto pottemp = new Potential< GUM_SCALAR >();
150  pottemp->copy(inf.posterior(node));
151  _hashMarginal.insert(node, pottemp);
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(
166  _hashMarginal.beginSafe()); // safe iterator needed here.
167  }
168 
169  } else {
170  std::cout << this->_bayesNet.toDot() << std::endl;
172  "BN is not valid cause it does not respect constraint ");
173  }
174 
175  _iteration = iter;
176  _disturbing = false;
177  }
178 
179  template < typename GUM_SCALAR,
180  template < typename >
181  class ICPTGenerator,
182  template < typename >
183  class ICPTDisturber >
186  return this->_maxArcs >= this->_bayesNet.sizeArcs();
187  }
188 
189  // main algorithme for moving between state of the IBayesNet according on the
190  // nature of the topology polytree or multi-connected
191 
192  template < typename GUM_SCALAR,
193  template < typename >
194  class ICPTGenerator,
195  template < typename >
196  class ICPTDisturber >
199  if (!_iteration--) return;
200 
201  Idx per = randomValue(100);
202 
203  if (per < _p) {
204  __AorR();
205 
206  if (__checkConditions()) {
207  _bayesNettemp = this->_bayesNet;
208  __PMMx_multi();
209  } else {
210  this->_bayesNet = _bayesNettemp;
211  __PMMx_poly();
212  }
213  } else {
214  if (per < _p + _q) {
215  __AR();
216 
217  if (!__checkConditions()) {
218  this->_bayesNet = _bayesNettemp;
219  } else
220  _bayesNettemp = this->_bayesNet;
221 
222  __PMMx_poly();
223  } else {
224  __jump_poly();
225 
226  if (__checkConditions()) {
227  _bayesNettemp = this->_bayesNet;
228  __PMMx_multi();
229 
230  } else {
231  this->_bayesNet = _bayesNettemp;
232  __PMMx_poly();
233  }
234  }
235  }
236  }
237 
238  template < typename GUM_SCALAR,
239  template < typename >
240  class ICPTGenerator,
241  template < typename >
242  class ICPTDisturber >
245  if (!_iteration--) return;
246 
247  Idx per = randomValue(100);
248 
249  if (per < _p + _q) {
250  __AorR();
251 
252  if (__checkConditions()) {
253  if (__isPolytree()) {
254  if (per < _p) {
255  _bayesNettemp = this->_bayesNet;
256  __PMMx_poly();
257  } else {
258  this->_bayesNet = _bayesNettemp;
259  __PMMx_multi();
260  }
261  } else {
262  _bayesNettemp = this->_bayesNet;
263  __PMMx_multi();
264  }
265  } else {
266  this->_bayesNet = _bayesNettemp;
267  __PMMx_multi();
268  }
269  } else {
270  __jump_multi();
271 
272  if (__checkConditions()) {
273  _bayesNettemp = this->_bayesNet;
274 
275  if (__isPolytree())
276  __PMMx_poly();
277  else
278  __PMMx_multi(); // TODO verification required
279 
280  } else {
281  this->_bayesNet = _bayesNettemp;
282  __PMMx_multi();
283  }
284  }
285  }
286 
287  template < typename GUM_SCALAR,
288  template < typename >
289  class ICPTGenerator,
290  template < typename >
291  class ICPTDisturber >
293  NodeId i, j;
294  __chooseNodes(i, j);
295  const DAG __dag = this->_bayesNet.dag();
296 
297  if (__dag.existsArc(i, j)) {
298  __eraseArc(i, j);
299 
300  return;
301  } else
302  __insertArc(i, j);
303  }
304 
305  template < typename GUM_SCALAR,
306  template < typename >
307  class ICPTGenerator,
308  template < typename >
309  class ICPTDisturber >
311  NodeId i, j, head, tail;
312  __chooseNodes(i, j);
313  const DAG __dag = this->_bayesNet.dag();
314 
315  if (__dag.existsArc(i, j) || __dag.existsArc(j, i)) {
316  return;
317  } else {
318  Idx per = randomValue(100);
319 
320  if (per < 50) {
321  head = i;
322  tail = j;
323  } else {
324  head = j;
325  tail = i;
326  }
327 
328  for (auto node : __dag.parents(j)) {
329  NodeSet excluded;
330  excluded.insert(j);
331 
332  if (__connect(node, i, excluded)) {
333  this->_bayesNet.eraseArc(node, j); // TODO reflect
334  this->_bayesNet.addArc(head, tail);
335  return;
336  }
337  }
338 
339  for (auto node : __dag.children(j)) {
340  NodeSet excluded;
341  excluded.insert(j);
342 
343  if (__connect(node, i, excluded)) {
344  this->_bayesNet.eraseArc(j, node);
345  this->_bayesNet.addArc(head, tail);
346  return;
347  }
348  }
349  }
350  }
351 
352  template < typename GUM_SCALAR,
353  template < typename >
354  class ICPTGenerator,
355  template < typename >
356  class ICPTDisturber >
359  NodeId i, j;
360  __chooseNodes(i, j);
361  const DAG __dag = this->_bayesNet.dag();
362 
363  if (!__dag.existsArc(i, j)) __insertArc(i, j);
364  }
365 
366  template < typename GUM_SCALAR,
367  template < typename >
368  class ICPTGenerator,
369  template < typename >
370  class ICPTDisturber >
373  NodeId i, j;
374  __chooseNodes(i, j);
375  const DAG __dag = this->_bayesNet.dag();
376 
377  if (__dag.existsArc(i, j)) { __eraseArc(i, j); }
378  }
379 
380  template < typename GUM_SCALAR,
381  template < typename >
382  class ICPTGenerator,
383  template < typename >
384  class ICPTDisturber >
385  INLINE void
387  NodeId i, NodeId j) {
388  if (__directedPath(j, i)) return;
389 
390  if (_disturbing) {
391  auto potj = this->_bayesNet.cpt(j);
392  this->_bayesNet.addArc(i, j);
393 
394  this->disturbAugmCPT(j, this->_bayesNet, potj, (GUM_SCALAR)0.5);
395  } else
396  this->_bayesNet.addArc(i, j);
397  }
398 
399  template < typename GUM_SCALAR,
400  template < typename >
401  class ICPTGenerator,
402  template < typename >
403  class ICPTDisturber >
404  INLINE void
406  NodeId i, NodeId j, bool mustbeconnex) {
407  if (_disturbing) {
408  const BayesNet< GUM_SCALAR > bayesNet(this->_bayesNet);
410  potj.copy(this->_bayesNet.cpt(j));
411  this->_bayesNet.eraseArc(i, j);
412 
413  if (__connect(i, j) || !mustbeconnex) {
414  auto marg = *_hashMarginal[i];
415 
416  this->disturbReducCPT(j, this->_bayesNet, potj, marg);
417  } else
418  this->_bayesNet.addArc(i, j);
419  } else {
420  this->_bayesNet.eraseArc(i, j);
421 
422  if (!__connect(i, j) && mustbeconnex) { this->_bayesNet.addArc(i, j); }
423  }
424  }
425 
426  template < typename GUM_SCALAR,
427  template < typename >
428  class ICPTGenerator,
429  template < typename >
430  class ICPTDisturber >
433  i = randomValue(this->_bayesNet.size());
434  j = randomValue(this->_bayesNet.size());
435 
436  while (i == j)
437  j = randomValue(this->_bayesNet.size());
438  }
439 
440  template < typename GUM_SCALAR,
441  template < typename >
442  class ICPTGenerator,
443  template < typename >
444  class ICPTDisturber >
447  NodeId temp = randomValue(this->_bayesNet.size());
448  Size co = 0;
449 
450  if (this->_bayesNet.parents(temp).size()) {
451  j = temp;
452  auto it = this->_bayesNet.parents(j).begin();
453  co = randomValue(this->_bayesNet.parents(j).size());
454 
455  while (co--) {
456  ++it;
457  }
458 
459  i = *it;
460  } else if (this->_bayesNet.children(temp).size()) {
461  i = temp;
462  auto it = this->_bayesNet.children(i).begin();
463  co = randomValue(this->_bayesNet.children(i).size());
464 
465  while (co--) {
466  ++it;
467  }
468 
469  j = *it;
470  } else {
471  GUM_ERROR(FatalError, "Sorry Misconstructed BN because of isolated node.");
472  }
473  }
474 
475  template < typename GUM_SCALAR,
476  template < typename >
477  class ICPTGenerator,
478  template < typename >
479  class ICPTDisturber >
480  void
482  Size BNSize) {
483  Idx n = 0;
484  Size nb_mod = 2 + randomValue(this->_maxModality - 1);
485  std::stringstream strBuff;
486  strBuff << "n_" << n++;
487  NodeId root =
488  this->_bayesNet.add(LabelizedVariable(strBuff.str(), "", nb_mod));
489  Size maxNodes = BNSize - 1;
490  Size SubG = 0;
491 
492  while (maxNodes) {
493  SubG = randomValue(maxNodes) + 1;
494  maxNodes = maxNodes - SubG;
495  NodeId rootS = __createPartTree(SubG, n);
496  this->_bayesNet.addArc(root, rootS);
497  }
498  }
499 
500  template < typename GUM_SCALAR,
501  template < typename >
502  class ICPTGenerator,
503  template < typename >
504  class ICPTDisturber >
507  Size nb_mod = 2 + randomValue(this->_maxModality - 1);
508  std::stringstream strBuff;
509  strBuff << "n_" << n++;
510  NodeId root =
511  this->_bayesNet.add(LabelizedVariable(strBuff.str(), "", nb_mod));
512  Size maxNodes = BNSize - 1;
513  Size SubG = 0;
514 
515  while (maxNodes) {
516  SubG = randomValue(maxNodes) + 1;
517  maxNodes = maxNodes - SubG;
518  NodeId rootS = __createPartTree(SubG, n);
519  this->_bayesNet.addArc(root, rootS);
520  }
521 
522  return root;
523  }
524 
525  // Allow to invert maximum nbiter arc to use from polytree only
526  template < typename GUM_SCALAR,
527  template < typename >
528  class ICPTGenerator,
529  template < typename >
530  class ICPTDisturber >
533  while (nbiter--) {
534  NodeId i, j;
535  __chooseCloseNodes(i, j);
536  _bayesNettemp = this->_bayesNet;
537  __eraseArc(i, j, false);
538  this->_bayesNet.addArc(j, i);
539 
540  if (!__checkConditions()) this->_bayesNet = _bayesNettemp;
541  }
542  }
543 
544  template < typename GUM_SCALAR,
545  template < typename >
546  class ICPTGenerator,
547  template < typename >
548  class ICPTDisturber >
551  const DAG __dag = this->_bayesNet.dag();
552  return this->_bayesNet.size() - 1 == this->_bayesNet.sizeArcs();
553  }
554 
555  template < typename GUM_SCALAR,
556  template < typename >
557  class ICPTGenerator,
558  template < typename >
559  class ICPTDisturber >
561  const NodeId i, const NodeId j) {
562  const DAG __dag = this->_bayesNet.dag();
563 
564  if (__dag.existsArc(i, j) || __dag.existsArc(j, i))
565  return true;
566  else {
567  NodeSet excluded;
568  excluded.insert(i);
569 
570  for (auto par : __dag.parents(i)) {
571  if (!excluded.exists(par) && __connect(par, j, excluded)) return true;
572  }
573 
574  for (auto chi : __dag.children(i)) {
575  if (!excluded.exists(chi) && __connect(chi, j, excluded)) return true;
576  }
577 
578  return false;
579  }
580  }
581 
582  template < typename GUM_SCALAR,
583  template < typename >
584  class ICPTGenerator,
585  template < typename >
586  class ICPTDisturber >
588  const NodeId i, const NodeId j, NodeSet& excluded) {
589  const DAG __dag = this->_bayesNet.dag();
590 
591  if (__dag.existsArc(i, j) || __dag.existsArc(j, i))
592  return true;
593  else {
594  excluded.insert(i);
595 
596  for (auto par : __dag.parents(i)) {
597  if (!excluded.exists(par) && __connect(par, j, excluded)) return true;
598  }
599 
600  for (auto chi : __dag.children(i)) {
601  if (!excluded.exists(chi) && __connect(chi, j, excluded)) return true;
602  }
603 
604  return false;
605  }
606  }
607 
608  template < typename GUM_SCALAR,
609  template < typename >
610  class ICPTGenerator,
611  template < typename >
612  class ICPTDisturber >
615  const DAG __dag = this->_bayesNet.dag();
616 
617  if (__dag.existsArc(tail, head))
618  return true;
619  else {
620  NodeSet excluded;
621  excluded.insert(tail);
622 
623  for (auto node : __dag.children(tail)) {
624  if (__directedPath(node, head, excluded)) return true;
625  }
626 
627  return false;
628  }
629  }
630 
631  template < typename GUM_SCALAR,
632  template < typename >
633  class ICPTGenerator,
634  template < typename >
635  class ICPTDisturber >
637  __directedPath(NodeId tail, NodeId head, NodeSet& excluded) {
638  const DAG __dag = this->_bayesNet.dag();
639 
640  if (__dag.existsArc(tail, head))
641  return true;
642  else {
643  excluded.insert(tail);
644 
645  for (auto node : __dag.children(tail)) {
646  if (!excluded.exists(node) && __directedPath(node, head, excluded))
647  return true;
648  }
649 
650  return false;
651  }
652  }
653 
654  template < typename GUM_SCALAR,
655  template < typename >
656  class ICPTGenerator,
657  template < typename >
658  class ICPTDisturber >
659  INLINE Size
661  const {
662  return _iteration;
663  }
664 
665  template < typename GUM_SCALAR,
666  template < typename >
667  class ICPTGenerator,
668  template < typename >
669  class ICPTDisturber >
670  INLINE Idx
672  return _p;
673  }
674 
675  template < typename GUM_SCALAR,
676  template < typename >
677  class ICPTGenerator,
678  template < typename >
679  class ICPTDisturber >
680  INLINE Idx
682  return _q;
683  }
684 
685  template < typename GUM_SCALAR,
686  template < typename >
687  class ICPTGenerator,
688  template < typename >
689  class ICPTDisturber >
690  INLINE void
692  Size iteration) {
694  }
695  template < typename GUM_SCALAR,
696  template < typename >
697  class ICPTGenerator,
698  template < typename >
699  class ICPTDisturber >
700  INLINE void
702  _p = p;
703 
704  if (p + _q > 100)
705  GUM_ERROR(
707  "the sum of the probabilities p and q must be at most equal to 100");
708  }
709  template < typename GUM_SCALAR,
710  template < typename >
711  class ICPTGenerator,
712  template < typename >
713  class ICPTDisturber >
714  INLINE void
716  _q = q;
717 
718  if (_p + q > 100)
719  GUM_ERROR(
721  "the sum of the probabilities p and q must be at most equal to 100");
722  }
723 
724 } /* namespace gum */
aGrUM&#39;s Potential is a multi-dimensional array with tensor operators.
Definition: potential.h:57
Class representing a Bayesian Network.
Definition: BayesNet.h:76
MCBayesNetGenerator(Size nbrNodes, Size maxArcs, Idx maxModality=2, Size iteration=5000, Idx p=30, Idx q=40)
Constructor.
virtual bool __checkConditions()
The boolean function that will assert the respect of the constraint.
void __PMMx_poly()
In the case that the graph is a polytree, the function will, according to the probability p and q...
const DiscreteVariable & variable(NodeId id) const final
Returns a gum::DiscreteVariable given its gum::NodeId in the gum::BayesNet.
Definition: BayesNet_tpl.h:199
class LabelizedVariable
Idx q() const
Return a constant reference to the probabilité imposed on the Markov Chain BayesNetGenerator.
Idx randomValue(const Size max=2)
Returns a random Idx between 0 and max-1 included.
<agrum/BN/generator/MCayesNetGenerator.h>
void fillCPT()
function that insert random values in the CPT of each nodes according to the CPTGenerator.
gum::Size getMaxModality(gum::BayesNet< GUM_SCALAR > &bayesNet)
bool __connect(NodeId i, NodeId j)
The function that verify if node i and j are connected.
void setQ(Idx q)
Modifies the value of the probability q imposed on the BayesNetGenerator.
gum is the global namespace for all aGrUM entities
Definition: agrum.h:25
virtual void copy(const MultiDimContainer< GUM_SCALAR > &src)
Removes all variables in this MultiDimContainer and copy the content of src, variables included...
void __jump_multi()
In the case that the graph is a multiconnect graph, the function will choose randomly two nodes and w...
bool __isPolytree()
The function that verify if graph is a polytree.
virtual void makeInference() final
perform the heavy computations needed to compute the targets&#39; posteriors
#define IBNG
virtual Size domainSize() const =0
void setP(Idx p)
Modifies the value of the probability p imposed on the BayesNetGenerator.
~MCBayesNetGenerator() override
Destructor.
bool exists(const Key &k) const
Indicates whether a given elements belong to the set.
Definition: set_tpl.h:604
BayesNet< GUM_SCALAR > _bayesNet
BayesNet< GUM_SCALAR > _bayesNettemp
void __transformPoly(Idx nbiter)
The function that randomly change the simple tree into a polytree.
const NodeGraphPart & nodes() const
Returns a constant reference to the dag of this Bayes Net.
Definition: DAGmodel_inl.h:112
const NodeSet & parents(const NodeId id) const
returns the set of nodes with arc ingoing to a given node
void __jump_poly()
In the case that the graph is a polytree, the function will add a ramdom arc by the use of the functi...
NodeId __createPartTree(Size BNSize, Idx &n)
The internal function used by __createTree that randomly generate a simple tree.
void setIteration(Size iteration)
Modifies the value of the number of iterations impose on the BayesNetGenerator.
void disturbBN(BayesNet< GUM_SCALAR > &bayesNetinit, Size iteration=0)
Change randomly the topology of a specific bayesian networks.
void __chooseNodes(NodeId &i, NodeId &j)
The function that randomly choose two nodes of the graph.
const NodeSet & children(const NodeId id) const
returns the set of nodes with arc outgoing from a given node
virtual const Potential< GUM_SCALAR > & posterior(NodeId node) final
Computes and returns the posterior of a node.
void __AR()
The function will remove and add a random arc changing the topology of the graph but asserting its co...
<agrum/BN/inference/lazyPropagation.h>
void __insertArc(NodeId i, NodeId j)
The function that will insert an arc between node i to node j, but only if there isn&#39;t any cycle crea...
void generateBN(BayesNet< GUM_SCALAR > &bayesNet) override
Generates a random bayesian network.
void __eraseArc(NodeId i, NodeId j, bool mustbeconnex=true)
The function that will remove the arc between node i and node j.
void __chooseCloseNodes(NodeId &i, NodeId &j)
The function that randomly choose two neighbours nodes of the graph.
Size Idx
Type for indexes.
Definition: types.h:50
void __AorR()
The function will add or remove a random arc in the graph using the functions __insertArc and __remov...
Size iteration() const
Return a constant reference to the number of iteration imposed on the Markov Chain BayesNetGenerator...
void __PMMx_multi()
In the case that the graph is a multiconnected graph, the function will, according to the probability...
bool __directedPath(NodeId tail, NodeId head)
The function that verify if there is a oriented path from node i to node j.
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:45
Class for generating bayesian networks.using MC algorithm cf.
void __createTree(Size BNSize)
The function that randomly generate a simple tree.
Base class for dag.
Definition: DAG.h:99
Idx p() const
Return a constant reference to the probabilité p imposed on the Markov Chain BayesNetGenerator.
bool existsArc(const Arc &arc) const
indicates whether a given arc exists
Size NodeId
Type for node ids.
Definition: graphElements.h:97
void insert(const Key &k)
Inserts a new element into the set.
Definition: set_tpl.h:610
#define GUM_ERROR(type, msg)
Definition: exceptions.h:52
HashTable< NodeId, Potential< GUM_SCALAR > *> _hashMarginal