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