aGrUM  0.17.2
a C++ library for (probabilistic) graphical models
Miic.cpp
Go to the documentation of this file.
1 
30 #include <agrum/tools/core/heap.h>
31 #include <agrum/tools/core/timer.h>
33 #include <agrum/BN/learning/Miic.h>
36 
37 
38 namespace gum {
39 
40  namespace learning {
41 
43  Miic::Miic() { GUM_CONSTRUCTOR(Miic); }
44 
46  Miic::Miic(int maxLog) : __maxLog(maxLog) { GUM_CONSTRUCTOR(Miic); }
47 
49  Miic::Miic(const Miic& from) : ApproximationScheme(from) {
50  GUM_CONS_CPY(Miic);
51  }
52 
54  Miic::Miic(Miic&& from) : ApproximationScheme(std::move(from)) {
55  GUM_CONS_MOV(Miic);
56  }
57 
59  Miic::~Miic() { GUM_DESTRUCTOR(Miic); }
60 
62  Miic& Miic::operator=(const Miic& from) {
63  ApproximationScheme::operator=(from);
64  return *this;
65  }
66 
69  ApproximationScheme::operator=(std::move(from));
70  return *this;
71  }
72 
73 
75  const std::pair<
76  std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >*,
77  double >& e1,
78  const std::pair<
79  std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >*,
80  double >& e2) const {
81  return e1.second > e2.second;
82  }
83 
85  const std::pair< std::tuple< NodeId, NodeId, NodeId >*, double >& e1,
86  const std::pair< std::tuple< NodeId, NodeId, NodeId >*, double >& e2)
87  const {
88  return std::abs(e1.second) > std::abs(e2.second);
89  }
90 
92  const std::
93  tuple< std::tuple< NodeId, NodeId, NodeId >*, double, double, double >&
94  e1,
95  const std::
96  tuple< std::tuple< NodeId, NodeId, NodeId >*, double, double, double >&
97  e2) const {
98  double p1xz = std::get< 2 >(e1);
99  double p1yz = std::get< 3 >(e1);
100  double p2xz = std::get< 2 >(e2);
101  double p2yz = std::get< 3 >(e2);
102  double I1 = std::get< 1 >(e1);
103  double I2 = std::get< 1 >(e2);
104  if (std::max(p1xz, p1yz) == std::max(p2xz, p2yz)) {
105  return I1 > I2;
106  } else {
107  return std::max(p1xz, p1yz) > std::max(p2xz, p2yz);
108  }
109  }
110 
113  MixedGraph graph) {
114  _timer.reset();
115  _current_step = 0;
116 
117  // clear the vector of latent arcs to be sure
118  __latent_couples.clear();
119 
121  Heap<
122  std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >*,
123  double >,
125  _rank;
126 
128  HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > sep_set;
129 
130  _initiation(I, graph, sep_set, _rank);
131 
132  _iteration(I, graph, sep_set, _rank);
133 
134  if (__usemiic) {
135  _orientation_miic(I, graph, sep_set);
136  } else {
137  _orientation_3off2(I, graph, sep_set);
138  }
139 
140  return graph;
141  }
142 
143  /*
144  * PHASE 1 : INITIATION
145  *
146  * We go over all edges and test if the variables are independent. If they
147  * are,
148  * the edge is deleted. If not, the best contributor is found.
149  */
152  MixedGraph& graph,
153  HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >& sep_set,
154  Heap<
155  std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >*,
156  double >,
157  GreaterPairOn2nd >& _rank) {
158  NodeId x, y;
159  EdgeSet edges = graph.edges();
160  Size steps_init = edges.size();
161 
162  for (const Edge& edge: edges) {
163  x = edge.first();
164  y = edge.second();
165  double Ixy = I.score(x, y);
166 
167  if (Ixy <= 0) { //< K
168  graph.eraseEdge(edge);
169  sep_set.insert(std::make_pair(x, y), __empty_set);
170  } else {
171  _findBestContributor(x, y, __empty_set, graph, I, _rank);
172  }
173 
174  ++_current_step;
175  if (onProgress.hasListener()) {
176  GUM_EMIT3(
177  onProgress, (_current_step * 33) / steps_init, 0., _timer.step());
178  }
179  }
180  }
181 
182  /*
183  * PHASE 2 : ITERATION
184  *
185  * As long as we find important nodes for edges, we go over them to see if
186  * we can assess the independence of the variables.
187  */
190  MixedGraph& graph,
191  HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >& sep_set,
192  Heap<
193  std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >*,
194  double >,
195  GreaterPairOn2nd >& _rank) {
196  // if no triples to further examine pass
197  std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >*,
198  double >
199  best;
200 
201  Size steps_init = _current_step;
202  Size steps_iter = _rank.size();
203 
204  try {
205  while (_rank.top().second > 0.5) {
206  best = _rank.pop();
207 
208  const NodeId x = std::get< 0 >(*(best.first));
209  const NodeId y = std::get< 1 >(*(best.first));
210  const NodeId z = std::get< 2 >(*(best.first));
211  std::vector< NodeId > ui = std::move(std::get< 3 >(*(best.first)));
212 
213  ui.push_back(z);
214  const double Ixy_ui = I.score(x, y, ui);
215  if (Ixy_ui < 0) {
216  graph.eraseEdge(Edge(x, y));
217  sep_set.insert(std::make_pair(x, y), std::move(ui));
218  } else {
219  _findBestContributor(x, y, ui, graph, I, _rank);
220  }
221 
222  delete best.first;
223 
224  ++_current_step;
225  if (onProgress.hasListener()) {
227  (_current_step * 66) / (steps_init + steps_iter),
228  0.,
229  _timer.step());
230  }
231  }
232  } catch (...) {} // here, rank is empty
233  _current_step = steps_init + steps_iter;
234  if (onProgress.hasListener()) {
235  GUM_EMIT3(onProgress, 66, 0., _timer.step());
236  }
237  _current_step = steps_init + steps_iter;
238  }
239 
240  /*
241  * PHASE 3 : ORIENTATION
242  *
243  * Try to assess v-structures and propagate them.
244  */
247  MixedGraph& graph,
248  const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >&
249  sep_set) {
250  std::vector< std::pair< std::tuple< NodeId, NodeId, NodeId >*, double > >
251  triples = _getUnshieldedTriples(graph, I, sep_set);
252  Size steps_orient = triples.size();
253  Size past_steps = _current_step;
254 
255  // marks always correspond to the head of the arc/edge. - is for a forbidden
256  // arc, > for a mandatory arc
257  // we start by adding the mandatory arcs
258  for (auto iter = __initial_marks.begin(); iter != __initial_marks.end();
259  ++iter) {
260  if (graph.existsEdge(iter.key().first, iter.key().second)
261  && iter.val() == '>') {
262  graph.eraseEdge(Edge(iter.key().first, iter.key().second));
263  graph.addArc(iter.key().first, iter.key().second);
264  }
265  }
266 
267  NodeId i = 0;
268  // list of elements that we shouldnt read again, ie elements that are
269  // eligible to
270  // rule 0 after the first time they are tested, and elements on which rule 1
271  // has been applied
272  while (i < triples.size()) {
273  // if i not in do_not_reread
274  std::pair< std::tuple< NodeId, NodeId, NodeId >*, double > triple =
275  triples[i];
276  NodeId x, y, z;
277  x = std::get< 0 >(*triple.first);
278  y = std::get< 1 >(*triple.first);
279  z = std::get< 2 >(*triple.first);
280 
281  std::vector< NodeId > ui;
282  std::pair< NodeId, NodeId > key = {x, y};
283  std::pair< NodeId, NodeId > rev_key = {y, x};
284  if (sep_set.exists(key)) {
285  ui = sep_set[key];
286  } else if (sep_set.exists(rev_key)) {
287  ui = sep_set[rev_key];
288  }
289  double Ixyz_ui = triple.second;
290  bool reset{false};
291  // try Rule 0
292  if (Ixyz_ui < 0) {
293  // if ( z not in Sep[x,y])
294  if (std::find(ui.begin(), ui.end(), z) == ui.end()) {
295  if (!graph.existsArc(x, z) && !graph.existsArc(z, x)) {
296  // when we try to add an arc to the graph, we always verify if
297  // we are allowed to do so, ie it is not a forbidden arc an it
298  // does not create a cycle
299  if (!__existsDirectedPath(graph, z, x)
300  && !(__initial_marks.exists({x, z})
301  && __initial_marks[{x, z}] == '-')) {
302  reset = true;
303  graph.eraseEdge(Edge(x, z));
304  graph.addArc(x, z);
305  } else if (__existsDirectedPath(graph, z, x)
306  && !(__initial_marks.exists({z, x})
307  && __initial_marks[{z, x}] == '-')) {
308  reset = true;
309  graph.eraseEdge(Edge(x, z));
310  // if we find a cycle, we force the competing edge
311  graph.addArc(z, x);
312  if (std::find(
313  __latent_couples.begin(), __latent_couples.end(), Arc(z, x))
314  == __latent_couples.end()) {
315  __latent_couples.push_back(Arc(z, x));
316  }
317  }
318  } else if (!graph.existsArc(y, z) && !graph.existsArc(z, y)) {
319  if (!__existsDirectedPath(graph, z, y)
320  && !(__initial_marks.exists({x, z})
321  && __initial_marks[{x, z}] == '-')) {
322  reset = true;
323  graph.eraseEdge(Edge(y, z));
324  graph.addArc(y, z);
325  } else if (__existsDirectedPath(graph, z, y)
326  && !(__initial_marks.exists({z, y})
327  && __initial_marks[{z, y}] == '-')) {
328  reset = true;
329  graph.eraseEdge(Edge(y, z));
330  // if we find a cycle, we force the competing edge
331  graph.addArc(z, y);
332  if (std::find(
333  __latent_couples.begin(), __latent_couples.end(), Arc(z, y))
334  == __latent_couples.end()) {
335  __latent_couples.push_back(Arc(z, y));
336  }
337  }
338  } else {
339  // checking if the anti-directed arc already exists, to register a
340  // latent variable
341  if (graph.existsArc(z, x)
342  && std::find(__latent_couples.begin(),
343  __latent_couples.end(),
344  Arc(z, x))
345  == __latent_couples.end()
346  && std::find(__latent_couples.begin(),
347  __latent_couples.end(),
348  Arc(x, z))
349  == __latent_couples.end()) {
350  __latent_couples.push_back(Arc(z, x));
351  }
352  if (graph.existsArc(z, y)
353  && std::find(__latent_couples.begin(),
354  __latent_couples.end(),
355  Arc(z, y))
356  == __latent_couples.end()
357  && std::find(__latent_couples.begin(),
358  __latent_couples.end(),
359  Arc(y, z))
360  == __latent_couples.end()) {
361  __latent_couples.push_back(Arc(z, y));
362  }
363  }
364  }
365  } else { // try Rule 1
366  if (graph.existsArc(x, z) && !graph.existsArc(z, y)
367  && !graph.existsArc(y, z)) {
368  if (!__existsDirectedPath(graph, y, z)
369  && !(__initial_marks.exists({z, y})
370  && __initial_marks[{z, y}] == '-')) {
371  reset = true;
372  graph.eraseEdge(Edge(z, y));
373  graph.addArc(z, y);
374  } else if (__existsDirectedPath(graph, y, z)
375  && !(__initial_marks.exists({y, z})
376  && __initial_marks[{y, z}] == '-')) {
377  reset = true;
378  graph.eraseEdge(Edge(z, y));
379  // if we find a cycle, we force the competing edge
380  graph.addArc(y, z);
381  if (std::find(
382  __latent_couples.begin(), __latent_couples.end(), Arc(y, z))
383  == __latent_couples.end()) {
384  __latent_couples.push_back(Arc(y, z));
385  }
386  }
387  }
388  if (graph.existsArc(y, z) && !graph.existsArc(z, x)
389  && !graph.existsArc(x, z)) {
390  if (!__existsDirectedPath(graph, x, z)
391  && !(__initial_marks.exists({z, x})
392  && __initial_marks[{z, x}] == '-')) {
393  reset = true;
394  graph.eraseEdge(Edge(z, x));
395  graph.addArc(z, x);
396  } else if (__existsDirectedPath(graph, x, z)
397  && !(__initial_marks.exists({x, z})
398  && __initial_marks[{x, z}] == '-')) {
399  reset = true;
400  graph.eraseEdge(Edge(z, x));
401  // if we find a cycle, we force the competing edge
402  graph.addArc(x, z);
403  if (std::find(
404  __latent_couples.begin(), __latent_couples.end(), Arc(x, z))
405  == __latent_couples.end()) {
406  __latent_couples.push_back(Arc(x, z));
407  }
408  }
409  }
410  } // if rule 0 or rule 1
411 
412  // if what we want to add already exists : pass to the next triplet
413  if (reset) {
414  i = 0;
415  } else {
416  ++i;
417  }
418  if (onProgress.hasListener()) {
420  ((_current_step + i) * 100) / (past_steps + steps_orient),
421  0.,
422  _timer.step());
423  }
424  } // while
425 
426  // erasing the the double headed arcs
427  for (const Arc& arc: __latent_couples) {
428  graph.eraseArc(Arc(arc.head(), arc.tail()));
429  }
430  }
431 
435  MixedGraph& graph,
436  const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >&
437  sep_set) {
438  std::vector< std::pair< std::tuple< NodeId, NodeId, NodeId >*, double > >
439  triples = _getUnshieldedTriples(graph, I, sep_set);
440  Size steps_orient = triples.size();
441  Size past_steps = _current_step;
442 
443  NodeId i = 0;
444  // list of elements that we shouldnt read again, ie elements that are
445  // eligible to
446  // rule 0 after the first time they are tested, and elements on which rule 1
447  // has been applied
448  while (i < triples.size()) {
449  // if i not in do_not_reread
450  std::pair< std::tuple< NodeId, NodeId, NodeId >*, double > triple =
451  triples[i];
452  NodeId x, y, z;
453  x = std::get< 0 >(*triple.first);
454  y = std::get< 1 >(*triple.first);
455  z = std::get< 2 >(*triple.first);
456 
457  std::vector< NodeId > ui;
458  std::pair< NodeId, NodeId > key = {x, y};
459  std::pair< NodeId, NodeId > rev_key = {y, x};
460  if (sep_set.exists(key)) {
461  ui = sep_set[key];
462  } else if (sep_set.exists(rev_key)) {
463  ui = sep_set[rev_key];
464  }
465  double Ixyz_ui = triple.second;
466  // try Rule 0
467  if (Ixyz_ui < 0) {
468  // if ( z not in Sep[x,y])
469  if (std::find(ui.begin(), ui.end(), z) == ui.end()) {
470  // if what we want to add already exists : pass
471  if ((graph.existsArc(x, z) || graph.existsArc(z, x))
472  && (graph.existsArc(y, z) || graph.existsArc(z, y))) {
473  ++i;
474  } else {
475  i = 0;
476  graph.eraseEdge(Edge(x, z));
477  graph.eraseEdge(Edge(y, z));
478  // checking for cycles
479  if (graph.existsArc(z, x)) {
480  graph.eraseArc(Arc(z, x));
481  try {
482  std::vector< NodeId > path = graph.directedPath(z, x);
483  // if we find a cycle, we force the competing edge
484  __latent_couples.push_back(Arc(z, x));
485  } catch (gum::NotFound) { graph.addArc(x, z); }
486  graph.addArc(z, x);
487  } else {
488  try {
489  std::vector< NodeId > path = graph.directedPath(z, x);
490  // if we find a cycle, we force the competing edge
491  graph.addArc(z, x);
492  __latent_couples.push_back(Arc(z, x));
493  } catch (gum::NotFound) { graph.addArc(x, z); }
494  }
495  if (graph.existsArc(z, y)) {
496  graph.eraseArc(Arc(z, y));
497  try {
498  std::vector< NodeId > path = graph.directedPath(z, y);
499  // if we find a cycle, we force the competing edge
500  __latent_couples.push_back(Arc(z, y));
501  } catch (gum::NotFound) { graph.addArc(y, z); }
502  graph.addArc(z, y);
503  } else {
504  try {
505  std::vector< NodeId > path = graph.directedPath(z, y);
506  // if we find a cycle, we force the competing edge
507  graph.addArc(z, y);
508  __latent_couples.push_back(Arc(z, y));
509 
510  } catch (gum::NotFound) { graph.addArc(y, z); }
511  }
512  if (graph.existsArc(z, x)
513  && std::find(__latent_couples.begin(),
514  __latent_couples.end(),
515  Arc(z, x))
516  == __latent_couples.end()
517  && std::find(__latent_couples.begin(),
518  __latent_couples.end(),
519  Arc(x, z))
520  == __latent_couples.end()) {
521  __latent_couples.push_back(Arc(z, x));
522  }
523  if (graph.existsArc(z, y)
524  && std::find(__latent_couples.begin(),
525  __latent_couples.end(),
526  Arc(z, y))
527  == __latent_couples.end()
528  && std::find(__latent_couples.begin(),
529  __latent_couples.end(),
530  Arc(y, z))
531  == __latent_couples.end()) {
532  __latent_couples.push_back(Arc(z, y));
533  }
534  }
535  } else {
536  ++i;
537  }
538  } else { // try Rule 1
539  bool reset{false};
540  if (graph.existsArc(x, z) && !graph.existsArc(z, y)
541  && !graph.existsArc(y, z)) {
542  reset = true;
543  graph.eraseEdge(Edge(z, y));
544  try {
545  std::vector< NodeId > path = graph.directedPath(y, z);
546  // if we find a cycle, we force the competing edge
547  graph.addArc(y, z);
548  __latent_couples.push_back(Arc(y, z));
549  } catch (gum::NotFound) { graph.addArc(z, y); }
550  }
551  if (graph.existsArc(y, z) && !graph.existsArc(z, x)
552  && !graph.existsArc(x, z)) {
553  reset = true;
554  graph.eraseEdge(Edge(z, x));
555  try {
556  std::vector< NodeId > path = graph.directedPath(x, z);
557  // if we find a cycle, we force the competing edge
558  graph.addArc(x, z);
559  __latent_couples.push_back(Arc(x, z));
560  } catch (gum::NotFound) { graph.addArc(z, x); }
561  }
562 
563  if (reset) {
564  i = 0;
565  } else {
566  ++i;
567  }
568  } // if rule 0 or rule 1
569  if (onProgress.hasListener()) {
571  ((_current_step + i) * 100) / (past_steps + steps_orient),
572  0.,
573  _timer.step());
574  }
575  } // while
576 
577  // erasing the the double headed arcs
578  for (const Arc& arc: __latent_couples) {
579  graph.eraseArc(Arc(arc.head(), arc.tail()));
580  }
581  }
582 
584  void
586  MixedGraph& graph,
587  const HashTable< std::pair< NodeId, NodeId >,
588  std::vector< NodeId > >& sep_set) {
589  // structure to store the orientations marks -, o, or >,
590  // Considers the head of the arc/edge first node -* second node
592 
593  // marks always correspond to the head of the arc/edge. - is for a forbidden
594  // arc, > for a mandatory arc
595  // we start by adding the mandatory arcs
596  for (auto iter = marks.begin(); iter != marks.end(); ++iter) {
597  if (graph.existsEdge(iter.key().first, iter.key().second)
598  && iter.val() == '>') {
599  graph.eraseEdge(Edge(iter.key().first, iter.key().second));
600  graph.addArc(iter.key().first, iter.key().second);
601  }
602  }
603 
604  std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId >*,
605  double,
606  double,
607  double > >
608  proba_triples = _getUnshieldedTriplesMIIC(graph, I, sep_set, marks);
609 
610  Size steps_orient = proba_triples.size();
611  Size past_steps = _current_step;
612 
613  std::tuple< std::tuple< NodeId, NodeId, NodeId >*, double, double, double >
614  best;
615  if (steps_orient > 0) { best = proba_triples[0]; }
616 
617  while (!proba_triples.empty()
618  && std::max(std::get< 2 >(best), std::get< 3 >(best)) > 0.5) {
619  NodeId x, y, z;
620  x = std::get< 0 >(*std::get< 0 >(best));
621  y = std::get< 1 >(*std::get< 0 >(best));
622  z = std::get< 2 >(*std::get< 0 >(best));
623 
624  const double i3 = std::get< 1 >(best);
625 
626  if (i3 <= 0) {
627  // v-structure discovery
628  if (marks[{x, z}] == 'o' && marks[{y, z}] == 'o') {
629  graph.eraseEdge(Edge(x, z));
630  graph.eraseEdge(Edge(y, z));
631  graph.addArc(x, z);
632  graph.addArc(y, z);
633  marks[{x, z}] = '>';
634  marks[{y, z}] = '>';
635  if (graph.existsArc(z, x)
636  && std::find(
637  __latent_couples.begin(), __latent_couples.end(), Arc(z, x))
638  == __latent_couples.end()
639  && std::find(
640  __latent_couples.begin(), __latent_couples.end(), Arc(x, z))
641  == __latent_couples.end()) {
642  __latent_couples.push_back(Arc(z, x));
643  }
644  if (graph.existsArc(z, y)
645  && std::find(
646  __latent_couples.begin(), __latent_couples.end(), Arc(z, y))
647  == __latent_couples.end()
648  && std::find(
649  __latent_couples.begin(), __latent_couples.end(), Arc(y, z))
650  == __latent_couples.end()) {
651  __latent_couples.push_back(Arc(z, y));
652  }
653  if (!__arc_probas.exists(Arc(x, z)))
654  __arc_probas.insert(Arc(x, z), std::get< 2 >(best));
655  if (!__arc_probas.exists(Arc(y, z)))
656  __arc_probas.insert(Arc(y, z), std::get< 3 >(best));
657  } else if (marks[{x, z}] == '>' && marks[{y, z}] == 'o') {
658  graph.eraseEdge(Edge(y, z));
659  graph.addArc(y, z);
660  marks[{y, z}] = '>';
661  if (graph.existsArc(z, y)
662  && std::find(
663  __latent_couples.begin(), __latent_couples.end(), Arc(z, y))
664  == __latent_couples.end()
665  && std::find(
666  __latent_couples.begin(), __latent_couples.end(), Arc(y, z))
667  == __latent_couples.end()) {
668  __latent_couples.push_back(Arc(z, y));
669  }
670  if (!__arc_probas.exists(Arc(y, z)))
671  __arc_probas.insert(Arc(y, z), std::get< 3 >(best));
672  } else if (marks[{y, z}] == '>' && marks[{x, z}] == 'o') {
673  graph.eraseEdge(Edge(x, z));
674  graph.addArc(x, z);
675  marks[{x, z}] = '>';
676  if (graph.existsArc(z, x)
677  && std::find(
678  __latent_couples.begin(), __latent_couples.end(), Arc(z, x))
679  == __latent_couples.end()
680  && std::find(
681  __latent_couples.begin(), __latent_couples.end(), Arc(x, z))
682  == __latent_couples.end()) {
683  __latent_couples.push_back(Arc(z, x));
684  }
685  if (!__arc_probas.exists(Arc(x, z)))
686  __arc_probas.insert(Arc(x, z), std::get< 2 >(best));
687  }
688 
689  } else {
690  // orientation propagation
691  if (marks[{x, z}] == '>' && marks[{y, z}] == 'o'
692  && marks[{z, y}] != '-') {
693  graph.eraseEdge(Edge(z, y));
694  if (!__existsDirectedPath(graph, y, z) && graph.parents(y).empty()) {
695  graph.addArc(z, y);
696  marks[{z, y}] = '>';
697  marks[{y, z}] = '-';
698  if (!__arc_probas.exists(Arc(z, y)))
699  __arc_probas.insert(Arc(z, y), std::get< 3 >(best));
700  } else if (!__existsDirectedPath(graph, z, y)
701  && graph.parents(z).empty()) {
702  graph.addArc(y, z);
703  marks[{z, y}] = '-';
704  marks[{y, z}] = '>';
705  __latent_couples.push_back(Arc(y, z));
706  if (!__arc_probas.exists(Arc(y, z)))
707  __arc_probas.insert(Arc(y, z), std::get< 3 >(best));
708  }
709  } else if (marks[{y, z}] == '>' && marks[{x, z}] == 'o'
710  && marks[{z, x}] != '-') {
711  graph.eraseEdge(Edge(z, x));
712  if (!__existsDirectedPath(graph, x, z) && graph.parents(x).empty()) {
713  graph.addArc(z, x);
714  marks[{z, x}] = '>';
715  marks[{x, z}] = '-';
716  if (!__arc_probas.exists(Arc(z, x)))
717  __arc_probas.insert(Arc(z, x), std::get< 2 >(best));
718  } else if (!__existsDirectedPath(graph, z, x)
719  && graph.parents(z).empty()) {
720  graph.addArc(x, z);
721  marks[{z, x}] = '-';
722  marks[{x, z}] = '>';
723  __latent_couples.push_back(Arc(x, z));
724  if (!__arc_probas.exists(Arc(x, z)))
725  __arc_probas.insert(Arc(x, z), std::get< 2 >(best));
726  }
727  }
728  }
729 
730  delete std::get< 0 >(best);
731  proba_triples.erase(proba_triples.begin());
732  // actualisation of the list of triples
733  proba_triples = _updateProbaTriples(graph, proba_triples);
734 
735  best = proba_triples[0];
736 
737  ++_current_step;
738  if (onProgress.hasListener()) {
740  (_current_step * 100) / (steps_orient + past_steps),
741  0.,
742  _timer.step());
743  }
744  } // while
745 
746  // erasing the double headed arcs
747  for (auto iter = __latent_couples.rbegin(); iter != __latent_couples.rend();
748  ++iter) {
749  graph.eraseArc(Arc(iter->head(), iter->tail()));
750  if (__existsDirectedPath(graph, iter->head(), iter->tail())) {
751  // if we find a cycle, we force the competing edge
752  graph.addArc(iter->head(), iter->tail());
753  graph.eraseArc(Arc(iter->tail(), iter->head()));
754  *iter = Arc(iter->head(), iter->tail());
755  }
756  }
757 
758  if (onProgress.hasListener()) {
759  GUM_EMIT3(onProgress, 100, 0., _timer.step());
760  }
761  }
762 
765  NodeId x,
766  NodeId y,
767  const std::vector< NodeId >& ui,
768  const MixedGraph& graph,
770  Heap<
771  std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >*,
772  double >,
773  GreaterPairOn2nd >& _rank) {
774  double maxP = -1.0;
775  NodeId maxZ = 0;
776 
777  // compute N
778  //__N = I.N();
779  const double Ixy_ui = I.score(x, y, ui);
780 
781  for (const NodeId z: graph) {
782  // if z!=x and z!=y and z not in ui
783  if (z != x && z != y && std::find(ui.begin(), ui.end(), z) == ui.end()) {
784  double Pnv;
785  double Pb;
786 
787  // Computing Pnv
788  const double Ixyz_ui = I.score(x, y, z, ui);
789  double calc_expo1 = -Ixyz_ui * M_LN2;
790  // if exponentials are too high or to low, crop them at |__maxLog|
791  if (calc_expo1 > __maxLog) {
792  Pnv = 0.0;
793  } else if (calc_expo1 < -__maxLog) {
794  Pnv = 1.0;
795  } else {
796  Pnv = 1 / (1 + std::exp(calc_expo1));
797  }
798 
799  // Computing Pb
800  const double Ixz_ui = I.score(x, z, ui);
801  const double Iyz_ui = I.score(y, z, ui);
802 
803  calc_expo1 = -(Ixz_ui - Ixy_ui) * M_LN2;
804  double calc_expo2 = -(Iyz_ui - Ixy_ui) * M_LN2;
805 
806  // if exponentials are too high or to low, crop them at __maxLog
807  if (calc_expo1 > __maxLog || calc_expo2 > __maxLog) {
808  Pb = 0.0;
809  } else if (calc_expo1 < -__maxLog && calc_expo2 < -__maxLog) {
810  Pb = 1.0;
811  } else {
812  double expo1, expo2;
813  if (calc_expo1 < -__maxLog) {
814  expo1 = 0.0;
815  } else {
816  expo1 = std::exp(calc_expo1);
817  }
818  if (calc_expo2 < -__maxLog) {
819  expo2 = 0.0;
820  } else {
821  expo2 = std::exp(calc_expo2);
822  }
823  Pb = 1 / (1 + expo1 + expo2);
824  }
825 
826  // Getting max(min(Pnv, pb))
827  const double min_pnv_pb = std::min(Pnv, Pb);
828  if (min_pnv_pb > maxP) {
829  maxP = min_pnv_pb;
830  maxZ = z;
831  }
832  } // if z not in (x, y)
833  } // for z in graph.nodes
834  // storing best z in _rank
835  std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >*,
836  double >
837  final;
838  auto tup = new std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >{
839  x, y, maxZ, ui};
840  final.first = tup;
841  final.second = maxP;
842  _rank.insert(final);
843  }
844 
847  std::vector< std::pair< std::tuple< NodeId, NodeId, NodeId >*, double > >
849  const MixedGraph& graph,
851  const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >&
852  sep_set) {
853  std::vector< std::pair< std::tuple< NodeId, NodeId, NodeId >*, double > >
854  triples;
855  for (NodeId z: graph) {
856  for (NodeId x: graph.neighbours(z)) {
857  for (NodeId y: graph.neighbours(z)) {
858  if (y < x && !graph.existsEdge(x, y)) {
859  std::vector< NodeId > ui;
860  std::pair< NodeId, NodeId > key = {x, y};
861  std::pair< NodeId, NodeId > rev_key = {y, x};
862  if (sep_set.exists(key)) {
863  ui = sep_set[key];
864  } else if (sep_set.exists(rev_key)) {
865  ui = sep_set[rev_key];
866  }
867  // remove z from ui if it's present
868  const auto iter_z_place = std::find(ui.begin(), ui.end(), z);
869  if (iter_z_place != ui.end()) { ui.erase(iter_z_place); }
870 
871  double Ixyz_ui = I.score(x, y, z, ui);
872  std::pair< std::tuple< NodeId, NodeId, NodeId >*, double > triple;
873  auto tup = new std::tuple< NodeId, NodeId, NodeId >{x, y, z};
874  triple.first = tup;
875  triple.second = Ixyz_ui;
876  triples.push_back(triple);
877  }
878  }
879  }
880  }
881  std::sort(triples.begin(), triples.end(), GreaterAbsPairOn2nd());
882  return triples;
883  }
884 
887  std::vector<
888  std::
889  tuple< std::tuple< NodeId, NodeId, NodeId >*, double, double, double > >
891  const MixedGraph& graph,
893  const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >&
894  sep_set,
895  HashTable< std::pair< NodeId, NodeId >, char >& marks) {
896  std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId >*,
897  double,
898  double,
899  double > >
900  triples;
901  for (NodeId z: graph) {
902  for (NodeId x: graph.neighbours(z)) {
903  for (NodeId y: graph.neighbours(z)) {
904  if (y < x && !graph.existsEdge(x, y)) {
905  std::vector< NodeId > ui;
906  std::pair< NodeId, NodeId > key = {x, y};
907  std::pair< NodeId, NodeId > rev_key = {y, x};
908  if (sep_set.exists(key)) {
909  ui = sep_set[key];
910  } else if (sep_set.exists(rev_key)) {
911  ui = sep_set[rev_key];
912  }
913  // remove z from ui if it's present
914  const auto iter_z_place = std::find(ui.begin(), ui.end(), z);
915  if (iter_z_place != ui.end()) { ui.erase(iter_z_place); }
916 
917  const double Ixyz_ui = I.score(x, y, z, ui);
918  auto tup = new std::tuple< NodeId, NodeId, NodeId >{x, y, z};
919  std::tuple< std::tuple< NodeId, NodeId, NodeId >*,
920  double,
921  double,
922  double >
923  triple{tup, Ixyz_ui, 0.5, 0.5};
924  triples.push_back(triple);
925  if (!marks.exists({x, z})) { marks.insert({x, z}, 'o'); }
926  if (!marks.exists({z, x})) { marks.insert({z, x}, 'o'); }
927  if (!marks.exists({y, z})) { marks.insert({y, z}, 'o'); }
928  if (!marks.exists({z, y})) { marks.insert({z, y}, 'o'); }
929  }
930  }
931  }
932  }
933  triples = _updateProbaTriples(graph, triples);
934  std::sort(triples.begin(), triples.end(), GreaterTupleOnLast());
935  return triples;
936  }
937 
939  std::vector<
940  std::
941  tuple< std::tuple< NodeId, NodeId, NodeId >*, double, double, double > >
943  const MixedGraph& graph,
944  std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId >*,
945  double,
946  double,
947  double > > proba_triples) {
948  for (auto& triple: proba_triples) {
949  NodeId x, y, z;
950  x = std::get< 0 >(*std::get< 0 >(triple));
951  y = std::get< 1 >(*std::get< 0 >(triple));
952  z = std::get< 2 >(*std::get< 0 >(triple));
953  const double Ixyz = std::get< 1 >(triple);
954  double Pxz = std::get< 2 >(triple);
955  double Pyz = std::get< 3 >(triple);
956 
957  if (Ixyz <= 0) {
958  const double expo = std::exp(Ixyz);
959  const double P0 = (1 + expo) / (1 + 3 * expo);
960  // distinguish betweeen the initialization and the update process
961  if (Pxz == Pyz && Pyz == 0.5) {
962  std::get< 2 >(triple) = P0;
963  std::get< 3 >(triple) = P0;
964  } else {
965  if (graph.existsArc(x, z) && Pxz >= P0) {
966  std::get< 3 >(triple) = Pxz * (1 / (1 + expo) - 0.5) + 0.5;
967  } else if (graph.existsArc(y, z) && Pyz >= P0) {
968  std::get< 2 >(triple) = Pyz * (1 / (1 + expo) - 0.5) + 0.5;
969  }
970  }
971  } else {
972  const double expo = std::exp(-Ixyz);
973  if (graph.existsArc(x, z) && Pxz >= 0.5) {
974  std::get< 3 >(triple) = Pxz * (1 / (1 + expo) - 0.5) + 0.5;
975  } else if (graph.existsArc(y, z) && Pyz >= 0.5) {
976  std::get< 2 >(triple) = Pyz * (1 / (1 + expo) - 0.5) + 0.5;
977  }
978  }
979  }
980  std::sort(proba_triples.begin(), proba_triples.end(), GreaterTupleOnLast());
981  return proba_triples;
982  }
983 
987  MixedGraph initialGraph) {
988  MixedGraph essentialGraph = learnMixedStructure(I, initialGraph);
989 
990  // Second, orientate remaining edges
991  const Sequence< NodeId > order = essentialGraph.topologicalOrder();
992  // first, propagate existing orientations
993  for (NodeId x: order) {
994  if (!essentialGraph.parents(x).empty()) {
995  _propagatesHead(essentialGraph, x);
996  }
997  }
998  // then decide the orientation by the topological order and propagate them
999  for (NodeId x: order) {
1000  if (!essentialGraph.neighbours(x).empty()) {
1001  _propagatesHead(essentialGraph, x);
1002  }
1003  }
1004 
1005  // turn the mixed graph into a dag
1006  DAG dag;
1007  for (auto node: essentialGraph) {
1008  dag.addNodeWithId(node);
1009  }
1010  for (const Arc& arc: essentialGraph.arcs()) {
1011  dag.addArc(arc.tail(), arc.head());
1012  }
1013 
1014  return dag;
1015  }
1016 
1019  const auto neighbours = graph.neighbours(node);
1020  for (auto& neighbour: neighbours) {
1021  // only propagate if it doesn't create a circle and isn't forbidden
1022  // and doesn't create a new v-structure
1023  if (!__existsDirectedPath(graph, neighbour, node)
1024  && !(__initial_marks.exists({node, neighbour})
1025  && __initial_marks[{node, neighbour}] == '-')
1026  && graph.parents(neighbour).empty()) {
1027  graph.eraseEdge(Edge(neighbour, node));
1028  graph.addArc(node, neighbour);
1029  _propagatesHead(graph, neighbour);
1030  } else if (!__existsDirectedPath(graph, node, neighbour)
1031  && !(__initial_marks.exists({neighbour, node})
1032  && __initial_marks[{neighbour, node}] == '-')
1033  && graph.parents(node).empty()) {
1034  graph.eraseEdge(Edge(neighbour, node));
1035  graph.addArc(neighbour, node);
1036  } else if (!graph.parents(neighbour).empty()
1037  && !graph.parents(node).empty()) {
1038  graph.eraseEdge(Edge(neighbour, node));
1039  graph.addArc(node, neighbour);
1040  __latent_couples.push_back(Arc(node, neighbour));
1041  } else {
1042  graph.eraseEdge(Edge(neighbour, node));
1043  }
1044  }
1045  }
1046 
1048  const std::vector< Arc > Miic::latentVariables() const {
1049  return __latent_couples;
1050  }
1051 
1053  template < typename GUM_SCALAR,
1054  typename GRAPH_CHANGES_SELECTOR,
1055  typename PARAM_ESTIMATOR >
1056  BayesNet< GUM_SCALAR > Miic::learnBN(GRAPH_CHANGES_SELECTOR& selector,
1057  PARAM_ESTIMATOR& estimator,
1058  DAG initial_dag) {
1059  return DAG2BNLearner<>::createBN< GUM_SCALAR >(
1060  estimator, learnStructure(selector, initial_dag));
1061  }
1062 
1063  void Miic::setMiicBehaviour() { this->__usemiic = true; }
1064  void Miic::set3off2Behaviour() { this->__usemiic = false; }
1065 
1067  HashTable< std::pair< NodeId, NodeId >, char > constraints) {
1068  this->__initial_marks = constraints;
1069  }
1070 
1071 
1072  const bool Miic::__existsDirectedPath(const MixedGraph& graph,
1073  const NodeId n1,
1074  const NodeId n2) const {
1075  // not recursive version => use a FIFO for simulating the recursion
1076  List< NodeId > nodeFIFO;
1077  nodeFIFO.pushBack(n2);
1078 
1079  // mark[node] = successor if visited, else mark[node] does not exist
1081  mark.insert(n2, n2);
1082 
1083  NodeId current;
1084 
1085  while (!nodeFIFO.empty()) {
1086  current = nodeFIFO.front();
1087  nodeFIFO.popFront();
1088 
1089  // check the parents
1090 
1091  for (const auto new_one: graph.parents(current)) {
1092  if (mark.exists(new_one)) // if this node is already marked, do not
1093  continue; // check it again
1094 
1095  if (graph.existsArc(current,
1096  new_one)) // if there is a double arc, pass
1097  continue;
1098 
1099  mark.insert(new_one, current);
1100 
1101  if (new_one == n1) { return true; }
1102 
1103  nodeFIFO.pushBack(new_one);
1104  }
1105  }
1106 
1107  return false;
1108  }
1109 
1110  } /* namespace learning */
1111 
1112 } /* namespace gum */
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
iterator begin()
Returns an unsafe iterator pointing to the beginning of the hashtable.
void _iteration(CorrectedMutualInformation<> &I, MixedGraph &graph, HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set, Heap< std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > > *, double >, GreaterPairOn2nd > &_rank)
Iteration phase.
Definition: Miic.cpp:188
bool empty() const noexcept
Returns a boolean indicating whether the chained list is empty.
Definition: list_tpl.h:1970
Class representing a Bayesian Network.
Definition: BayesNet.h:78
ArcProperty< double > __arc_probas
Storing the propabilities for each arc set in the graph.
Definition: Miic.h:362
void _findBestContributor(NodeId x, NodeId y, const std::vector< NodeId > &ui, const MixedGraph &graph, CorrectedMutualInformation<> &I, Heap< std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > > *, double >, GreaterPairOn2nd > &_rank)
finds the best contributor node for a pair given a conditioning set
Definition: Miic.cpp:764
virtual void addNodeWithId(const NodeId id)
try to insert a node with the given id
virtual void addArc(const NodeId tail, const NodeId head)
insert a new arc into the directed graph
Definition: diGraph_inl.h:35
double step() const
Returns the delta time between now and the last reset() call (or the constructor).
Definition: timer_inl.h:42
Signaler3< Size, double, double > onProgress
Progression, error and time.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
const iterator & end() noexcept
Returns the unsafe iterator pointing to the end of the hashtable.
bool empty() const noexcept
Indicates whether the set is the empty set.
Definition: set_tpl.h:709
The class computing n times the corrected mutual information, as used in the 3off2 algorithm...
Approximation Scheme.
void set3off2Behaviour()
Sets the orientation phase to follow the one of the 3off2 algorithm.
Definition: Miic.cpp:1064
MixedGraph learnMixedStructure(CorrectedMutualInformation<> &I, MixedGraph graph)
learns the structure of an Essential Graph
Definition: Miic.cpp:112
virtual void eraseArc(const Arc &arc)
removes an arc from the ArcGraphPart
Miic & operator=(const Miic &from)
copy operator
Definition: Miic.cpp:62
void addConstraints(HashTable< std::pair< NodeId, NodeId >, char > constraints)
Set a ensemble of constraints for the orientation phase.
Definition: Miic.cpp:1066
STL namespace.
void _orientation_latents(CorrectedMutualInformation<> &I, MixedGraph &graph, const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set)
Modified version of the orientation phase that tries to propagate orientations from both orientations...
Definition: Miic.cpp:433
bool exists(const Key &key) const
Checks whether there exists an element with a given key in the hashtable.
#define M_LN2
Definition: math.h:44
void _orientation_miic(CorrectedMutualInformation<> &I, MixedGraph &graph, const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set)
Orientation phase from the MIIC algorithm, returns a mixed graph that may contain circles...
Definition: Miic.cpp:585
Generic doubly linked lists.
Definition: list.h:372
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
const std::vector< Arc > latentVariables() const
get the list of arcs hiding latent variables
Definition: Miic.cpp:1048
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Definition: agrum.h:25
bool __usemiic
wether to use the miic algorithm or not
Definition: Miic.h:359
void popFront()
Removes the first element of a List, if any.
Definition: list_tpl.h:1964
void setMiicBehaviour()
Sets the orientation phase to follow the one of the MIIC algorithm.
Definition: Miic.cpp:1063
void _propagatesHead(MixedGraph &graph, NodeId node)
Propagates the orientation from a node to its neighbours.
Definition: Miic.cpp:1018
The class for generic Hash Tables.
Definition: hashTable.h:679
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
const NodeSet & neighbours(const NodeId id) const
returns the set of edges adjacent to a given node
bool operator()(const std::pair< std::tuple< NodeId, NodeId, NodeId > *, double > &e1, const std::pair< std::tuple< NodeId, NodeId, NodeId > *, double > &e2) const
Definition: Miic.cpp:84
void reset()
Reset the timer.
Definition: timer_inl.h:32
double score(NodeId var1, NodeId var2)
returns the 2-point mutual information corresponding to a given nodeset
const EdgeSet & edges() const
returns the set of edges stored within the EdgeGraphPart
HashTable< std::pair< NodeId, NodeId >, char > __initial_marks
Initial marks for the orientation phase, used to convey constraints.
Definition: Miic.h:365
std::vector< Arc > __latent_couples
an empty vector of arcs
Definition: Miic.h:354
bool existsEdge(const Edge &edge) const
indicates whether a given edge exists
The base class for all directed edgesThis class is used as a basis for manipulating all directed edge...
std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId > *, double, double, double > > _getUnshieldedTriplesMIIC(const MixedGraph &graph, CorrectedMutualInformation<> &I, const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set, HashTable< std::pair< NodeId, NodeId >, char > &marks)
gets the list of unshielded triples in the graph in decreasing value of |I&#39;(x, y, z|{ui})|...
Definition: Miic.cpp:890
const NodeSet & parents(const NodeId id) const
returns the set of nodes with arc ingoing to a given node
Val & pushBack(const Val &val)
Inserts a new element (a copy) at the end of the chained list.
Definition: list_tpl.h:1592
Size _current_step
The current step.
const std::vector< NodeId > directedPath(const NodeId node1, const NodeId node2) const
returns a directed path from node1 to node2 belonging to the set of arcs
virtual void addArc(const NodeId tail, const NodeId head)
insert a new arc into the directed graph
Definition: DAG_inl.h:43
const Sequence< NodeId > & topologicalOrder(bool clear=true) const
The topological order stays the same as long as no variable or arcs are added or erased src the topol...
Definition: diGraph.cpp:91
void _initiation(CorrectedMutualInformation<> &I, MixedGraph &graph, HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set, Heap< std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > > *, double >, GreaterPairOn2nd > &_rank)
Initiation phase.
Definition: Miic.cpp:150
std::vector< std::pair< std::tuple< NodeId, NodeId, NodeId > *, double > > _getUnshieldedTriples(const MixedGraph &graph, CorrectedMutualInformation<> &I, const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set)
gets the list of unshielded triples in the graph in decreasing value of |I&#39;(x, y, z|{ui})| ...
Definition: Miic.cpp:848
Val & front() const
Returns a reference to first element of a list, if any.
Definition: list_tpl.h:1831
The base class for all undirected edges.
Miic()
default constructor
Definition: Miic.cpp:43
std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId > *, double, double, double > > _updateProbaTriples(const MixedGraph &graph, std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId > *, double, double, double > > proba_triples)
Gets the orientation probabilities like MIIC for the orientation phase.
Definition: Miic.cpp:942
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
bool operator()(const std::tuple< std::tuple< NodeId, NodeId, NodeId > *, double, double, double > &e1, const std::tuple< std::tuple< NodeId, NodeId, NodeId > *, double, double, double > &e2) const
Definition: Miic.cpp:91
int __maxLog
Fixes the maximum log that we accept in exponential computations.
Definition: Miic.h:350
The miic learning algorithm.
Definition: Miic.h:106
const bool __existsDirectedPath(const MixedGraph &graph, const NodeId n1, const NodeId n2) const
checks for directed paths in a graph, consider double arcs like edges
Definition: Miic.cpp:1072
A class that, given a structure and a parameter estimator returns a full Bayes net.
Definition: DAG2BNLearner.h:52
bool operator()(const std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > > *, double > &e1, const std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > > *, double > &e2) const
Definition: Miic.cpp:74
Heap data structureThis structure is a basic heap data structure, i.e., it is a container in which el...
Definition: heap.h:48
~Miic()
destructor
Definition: Miic.cpp:59
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
const std::vector< NodeId > __empty_set
an empty conditioning set
Definition: Miic.h:352
virtual void eraseEdge(const Edge &edge)
removes an edge from the EdgeGraphPart
Size size() const noexcept
Returns the number of elements in the set.
Definition: set_tpl.h:703
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
#define GUM_EMIT3(signal, arg1, arg2, arg3)
Definition: signaler3.h:42
BayesNet< GUM_SCALAR > learnBN(GRAPH_CHANGES_SELECTOR &selector, PARAM_ESTIMATOR &estimator, DAG initial_dag=DAG())
learns the structure and the parameters of a BN
Definition: Miic.cpp:1056
Base class for dag.
Definition: DAG.h:102
bool existsArc(const Arc &arc) const
indicates whether a given arc exists
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Size NodeId
Type for node ids.
Definition: graphElements.h:98
DAG learnStructure(CorrectedMutualInformation<> &I, MixedGraph graph)
learns the structure of an Bayesian network, ie a DAG, by first learning an Essential graph and then ...
Definition: Miic.cpp:986
Base class for mixed graphs.
Definition: mixedGraph.h:127
void _orientation_3off2(CorrectedMutualInformation<> &I, MixedGraph &graph, const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set)
Orientation phase from the 3off2 algorithm, returns a CPDAG.
Definition: Miic.cpp:245