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