aGrUM  0.14.2
structuredInference_tpl.h
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005 by Christophe GONZALES and Pierre-Henri WUILLEMIN *
3  * {prenom.nom}_at_lip6.fr *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
28 
29 namespace gum {
30  namespace prm {
31 
32  template < typename GUM_SCALAR >
34  const PRM< GUM_SCALAR >& prm,
35  const PRMSystem< GUM_SCALAR >& system,
37  PRMInference< GUM_SCALAR >(prm, system),
38  __gspan(0), __pdata(0), __mining(false), __dot(".") {
39  GUM_CONSTRUCTOR(StructuredInference);
40  __gspan = new GSpan< GUM_SCALAR >(prm, system, strategy);
41  triang_time = 0.0;
42  mining_time = 0.0;
43  pattern_time = 0.0;
44  inner_time = 0.0;
45  obs_time = 0.0;
46  full_time = 0.0;
47  }
48 
49  template < typename GUM_SCALAR >
51  const StructuredInference< GUM_SCALAR >& source) :
52  PRMInference< GUM_SCALAR >(source),
53  __gspan(0), __pdata(0), __mining(source.__mining), __found_query(false),
54  __dot(".") {
55  GUM_CONS_CPY(StructuredInference);
56  __gspan = new GSpan< GUM_SCALAR >(*(this->_prm), *(this->_sys));
57  }
58 
59  template < typename GUM_SCALAR >
61  GUM_DESTRUCTOR(StructuredInference);
62  delete this->__gspan;
63 
64  for (const auto& elt : __elim_map)
65  delete elt.second;
66 
67  for (const auto& elt : __cdata_map)
68  delete elt.second;
69 
70  for (const auto elt : __trash)
71  delete (elt);
72 
73  for (const auto& elt : __outputs)
74  delete elt.second;
75 
76  if (__pdata) delete __pdata;
77  }
78 
79  template < typename GUM_SCALAR >
82  this->_prm = source._prm;
83  this->_sys = source._sys;
84 
85  if (this->__gspan) delete this->__gspan;
86 
87  this->__gspan = new GSpan< GUM_SCALAR >(*(this->_prm), *(this->_sys));
88  return *this;
89  }
90 
91  template < typename GUM_SCALAR >
93  const typename PRMInference< GUM_SCALAR >::Chain& chain) {}
94 
95  template < typename GUM_SCALAR >
97  const typename PRMInference< GUM_SCALAR >::Chain& chain) {}
98 
99  template < typename GUM_SCALAR >
101  const typename PRMInference< GUM_SCALAR >::Chain& chain,
103  timer.reset();
104  __found_query = false;
105  __query = chain;
107 
108  if (!this->hasEvidence() && (chain.second->cpf().nbrDim() == 1)) {
109  Instantiation i(m);
110 
111  for (i.setFirst(); !i.end(); i.inc())
112  m.set(i, chain.second->cpf().get(i));
113 
114  return;
115  } else if (this->hasEvidence(chain)) {
116  Instantiation i(m);
117  const Potential< GUM_SCALAR >* e =
118  this->evidence(__query.first)[__query.second->id()];
119 
120  for (i.setFirst(); !i.end(); i.inc())
121  m.set(i, e->get(i));
122 
123  return;
124  }
125 
126  __buildReduceGraph(data);
128 
129  if (data.pool.size() > 1) {
130  for (const auto pot : data.pool)
131  if (pot->contains(__query.second->type().variable())) pots.insert(pot);
132 
133  if (pots.size() == 1) {
135  const_cast< Potential< GUM_SCALAR >* >(*(pots.begin()));
136  GUM_ASSERT(pot->contains(__query.second->type().variable()));
137  GUM_ASSERT(pot->variablesSequence().size() == 1);
138  Instantiation i(*pot), j(m);
139 
140  for (i.setFirst(), j.setFirst(); !i.end(); i.inc(), j.inc())
141  m.set(j, pot->get(i));
142  } else {
144  Potential< GUM_SCALAR >* tmp = Comb.combine(pots);
145  Instantiation i(m), j(*tmp);
146 
147  for (i.setFirst(), j.setFirst(); !i.end(); i.inc(), j.inc())
148  m.set(i, tmp->get(j));
149 
150  delete tmp;
151  }
152  } else {
153  Potential< GUM_SCALAR >* pot = *(data.pool.begin());
154  GUM_ASSERT(pot->contains(__query.second->type().variable()));
155  GUM_ASSERT(pot->variablesSequence().size() == 1);
156  Instantiation i(*pot), j(m);
157 
158  for (i.setFirst(), j.setFirst(); !i.end(); i.inc(), j.inc())
159  m.set(j, pot->get(i));
160  }
161 
162  m.normalize();
163 
164  if (__pdata) {
165  delete __pdata;
166  __pdata = 0;
167  }
168 
169  full_time = timer.step();
170  }
171 
172  template < typename GUM_SCALAR >
174  const std::vector< typename PRMInference< GUM_SCALAR >::Chain >& queries,
176  GUM_ERROR(FatalError, "not implemented");
177  }
178 
179  template < typename GUM_SCALAR >
181  std::stringstream s;
182  s << "Triangulation time: " << triang_time << std::endl;
183  s << "Pattern mining time: " << mining_time << std::endl;
184  s << "Pattern elimination time: " << pattern_time << std::endl;
185  s << "Inner node elimination time: " << inner_time << std::endl;
186  s << "Observed node elimination time: " << obs_time << std::endl;
187  s << "Full inference time: " << full_time << std::endl;
188  s << "#patterns: " << __gspan->patterns().size() << std::endl;
189  Size count = 0;
190  typedef std::vector< gspan::Pattern* >::const_iterator Iter;
191 
192  for (Iter p = __gspan->patterns().begin(); p != __gspan->patterns().end();
193  ++p) {
194  if (__gspan->matches(**p).size()) {
195  s << "Pattern n°" << count++
196  << " match count: " << __gspan->matches(**p).size() << std::endl;
197  s << "Pattern n°" << count++ << " instance count: " << (**p).size()
198  << std::endl;
199  }
200  }
201 
202  return s.str();
203  }
204 
205  template < typename GUM_SCALAR >
208  // Launch the pattern mining
209  plopTimer.reset();
210 
211  if (__mining) __gspan->discoverPatterns();
212 
214  // Reducing each used pattern
215  plopTimer.reset();
216  typedef std::vector< gspan::Pattern* >::const_iterator Iter;
217 
218  for (Iter p = __gspan->patterns().begin(); p != __gspan->patterns().end();
219  ++p)
220  if (__gspan->matches(**p).size()) __reducePattern(*p);
221 
223  // reducing instance not already reduced in a pattern
225  // Adding edges using the pools
227  // Placing the query where it belongs
228  NodeId id = data.var2node.second(&(__query.second->type().variable()));
229  data.outputs().erase(id);
230  data.queries().insert(id);
231  // Triangulating, then eliminating
233  &(data.reducedGraph), &(data.mods), &(data.partial_order));
234  const std::vector< NodeId >& elim_order = t.eliminationOrder();
235 
236  for (size_t i = 0; i < data.outputs().size(); ++i)
237  eliminateNode(data.var2node.first(elim_order[i]), data.pool, __trash);
238  }
239 
240  template < typename GUM_SCALAR >
242  const gspan::Pattern* p) {
245  __gspan->matches(*p));
246  __buildPatternGraph(data, pool, **(data.matches.begin()));
247  __removeBarrenNodes(data, pool);
249  &(data.graph), &(data.mod), data.partial_order());
250  const std::vector< NodeId >& elim_order = t.eliminationOrder();
251 
252  for (size_t i = 0; i < data.inners().size(); ++i)
253  if (!data.barren.exists(elim_order[i]))
254  eliminateNode(data.vars.second(elim_order[i]), pool, __trash);
255 
256  typename GSpan< GUM_SCALAR >::MatchedInstances fake_patterns;
258  data.matches.begin();
259 
260  for (const auto elt : **iter)
261  __reducedInstances.insert(elt);
262 
263  if (data.obs().size())
264  __elim_map.insert(
265  *iter,
266  __eliminateObservedNodesInSource(data, pool, **iter, elim_order));
267  else
268  __elim_map.insert(*iter, new Set< Potential< GUM_SCALAR >* >(pool));
269 
270  ++iter;
271 
272  if (data.obs().size()) {
273  for (; iter != data.matches.end(); ++iter) {
274  try {
275  __elim_map.insert(
276  *iter, __eliminateObservedNodes(data, pool, **iter, elim_order));
277  } catch (OperationNotAllowed&) { fake_patterns.insert(*iter); }
278  }
279  } else {
280  for (; iter != data.matches.end(); ++iter) {
281  try {
282  __elim_map.insert(*iter, __translatePotSet(data, pool, **iter));
283  } catch (OperationNotAllowed&) { fake_patterns.insert(*iter); }
284  }
285  }
286 
287  for (const auto pat : fake_patterns) {
288  for (const auto elt : *pat)
289  __reducedInstances.erase(elt);
290 
291  data.matches.erase(pat);
292  }
293 
294  obs_time += plopTimer.step();
295 
296  if (data.queries().size())
297  for (const auto m : data.matches)
298  if (!(m->exists(
299  const_cast< PRMInstance< GUM_SCALAR >* >(__query.first))))
300  eliminateNode(&(m->atPos(__query_data.first)
301  ->get(__query_data.second)
302  .type()
303  .variable()),
304  *(__elim_map[m]),
305  __trash);
306  }
307 
308  template < typename GUM_SCALAR >
311  const Sequence< PRMInstance< GUM_SCALAR >* >& match,
314  NodeId id,
315  std::pair< Idx, std::string >& v) {
316  if ((*inst).hasRefAttr((*inst).get(v.second).id())) {
317  std::vector< std::pair< PRMInstance< GUM_SCALAR >*, std::string > >& refs =
318  inst->getRefAttr(inst->get(v.second).id());
319 
320  for (auto r = refs.begin(); r != refs.end(); ++r) {
321  if (!match.exists(r->first)) {
322  data.outputs().insert(id);
323  break;
324  }
325  }
326  }
327 
328  if (!(data.outputs().size() && (data.outputs().exists(id)))) {
329  for (const auto m : data.matches) {
330  if (this->hasEvidence(
331  std::make_pair((*m)[v.first], &((*m)[v.first]->get(v.second))))) {
332  GUM_ASSERT(inst->type().name() == (*m)[v.first]->type().name());
333  GUM_ASSERT(inst->get(v.second).safeName()
334  == (*m)[v.first]->get(v.second).safeName());
335  data.obs().insert(id);
336  break;
337  }
338  }
339 
340  if (!(data.obs().size() && (data.obs().exists(id))))
341  data.inners().insert(id);
342  }
343  }
344 
345  template < typename GUM_SCALAR >
348  Set< Potential< GUM_SCALAR >* >& pool,
349  const Sequence< PRMInstance< GUM_SCALAR >* >& match) {
350  std::pair< Idx, std::string > v;
351  Potential< GUM_SCALAR >* pot = 0;
352 
353  for (const auto inst : match) {
354  for (const auto& elt : *inst) {
355  NodeId id = data.graph.addNode();
356  v = std::make_pair(match.pos(inst), elt.second->safeName());
357  data.map.insert(id, v);
358  data.node2attr.insert(id, __str(inst, elt.second));
359  data.mod.insert(id, elt.second->type()->domainSize());
360  data.vars.insert(id, &(elt.second->type().variable()));
361  pool.insert(
362  const_cast< Potential< GUM_SCALAR >* >(&(elt.second->cpf())));
363  pot =
364  &(const_cast< Potential< GUM_SCALAR >& >(inst->get(v.second).cpf()));
365 
366  for (const auto var : pot->variablesSequence()) {
367  try {
368  if (id != data.vars.first(var))
369  data.graph.addEdge(id, data.vars.first(var));
370  } catch (DuplicateElement&) {
371  } catch (NotFound&) {}
372  }
373 
374  __insertNodeInElimLists(data, match, inst, elt.second, id, v);
375 
376  if (data.inners().exists(id)
377  && (inst->type().containerDag().children(elt.second->id()).size()
378  == 0)
379  && __allInstanceNoRefAttr(data, v))
380  data.barren.insert(id);
381  }
382  }
383 
384  if (!__found_query) {
385  for (const auto mat : data.matches) {
386  if (mat->exists(
387  const_cast< PRMInstance< GUM_SCALAR >* >(__query.first))) {
388  Idx pos =
389  mat->pos(const_cast< PRMInstance< GUM_SCALAR >* >(__query.first));
390  DiscreteVariable& var =
391  match.atPos(pos)->get(__query.second->safeName()).type().variable();
392  NodeId id = data.vars.first(&var);
393  data.barren.erase(id);
394  data.inners().erase(id);
395  data.obs().erase(id);
396  data.outputs().erase(id);
397  data.queries().insert(id);
398  __found_query = true;
399  __query_data = std::make_pair(pos, __query.second->safeName());
400  break;
401  }
402  }
403  }
404  }
405 
406  template < typename GUM_SCALAR >
409  std::pair< Idx, std::string > attr) {
410  for (const auto mat : data.matches)
411  if (mat->atPos(attr.first)
412  ->hasRefAttr(mat->atPos(attr.first)->get(attr.second).id()))
413  return false;
414 
415  return true;
416  }
417 
418  template < typename GUM_SCALAR >
421  Set< Potential< GUM_SCALAR >* >& pool) {
422  Sequence< NodeId > candidates;
423 
424  for (const auto node : data.barren) {
425  for (const auto pot : pool)
426  if (pot->contains(*data.vars.second(node))) {
427  pool.erase(pot);
428  break;
429  }
430 
431  for (const auto nei : data.graph.neighbours(node))
432  if (data.inners().exists(nei)) {
433  try {
434  candidates.insert(nei);
435  } catch (DuplicateElement&) {}
436  }
437  }
438 
439  NodeId node;
440  Potential< GUM_SCALAR >* my_pot = nullptr;
441  short count = 0;
442 
443  while (candidates.size()) {
444  node = candidates.back();
445  candidates.erase(node);
446  count = 0;
447 
448  for (const auto pot : pool) {
449  if (pot->contains(*data.vars.second(node))) {
450  ++count;
451  my_pot = pot;
452  }
453  }
454 
455  if (count == 1) {
456  pool.erase(my_pot);
457  data.barren.insert(node);
458 
459  for (const auto nei : data.graph.neighbours(node)) {
460  if (data.inners().exists(nei)) {
461  try {
462  candidates.insert(nei);
463  } catch (DuplicateElement&) {}
464  }
465  }
466  }
467  }
468  }
469 
470  template < typename GUM_SCALAR >
474  const Set< Potential< GUM_SCALAR >* >& pool,
475  const Sequence< PRMInstance< GUM_SCALAR >* >& match,
476  const std::vector< NodeId >& elim_order) {
477  Set< Potential< GUM_SCALAR >* >* my_pool =
478  new Set< Potential< GUM_SCALAR >* >(pool);
479  std::pair< Idx, std::string > target;
480  size_t end = data.inners().size() + data.obs().size();
481 
482  for (size_t idx = data.inners().size(); idx < end; ++idx) {
483  target = data.map[data.vars.first(data.vars.second(elim_order[idx]))];
484  eliminateNode(&(match[target.first]->get(target.second).type().variable()),
485  *my_pool,
486  __trash);
487  }
488 
489  return my_pool;
490  }
491 
492  template < typename GUM_SCALAR >
496  const Set< Potential< GUM_SCALAR >* >& pool,
497  const Sequence< PRMInstance< GUM_SCALAR >* >& match,
498  const std::vector< NodeId >& elim_order) {
499  Set< Potential< GUM_SCALAR >* >* my_pool =
500  __translatePotSet(data, pool, match);
501  std::pair< Idx, std::string > target;
502  size_t end = data.inners().size() + data.obs().size();
503 
504  for (size_t idx = data.inners().size(); idx < end; ++idx) {
505  target = data.map[data.vars.first(data.vars.second(elim_order[idx]))];
506  eliminateNode(&(match[target.first]->get(target.second).type().variable()),
507  *my_pool,
508  __trash);
509  }
510 
511  return my_pool;
512  }
513 
514  template < typename GUM_SCALAR >
518  const Set< Potential< GUM_SCALAR >* >& pool,
519  const Sequence< PRMInstance< GUM_SCALAR >* >& match) {
520 #ifdef DEBUG
521 
523  data.matches.begin();
524  iter != data.matches.end();
525  ++iter) {
526  GUM_ASSERT((**iter).size() == match.size());
527 
528  for (Size idx = 0; idx < match.size(); ++idx) {
529  GUM_ASSERT((**iter).atPos(idx)->type() == match.atPos(idx)->type());
530  }
531  }
532 
533 #endif
534  Set< Potential< GUM_SCALAR >* >* my_pool =
536  std::pair< Idx, std::string > target;
538  const Sequence< PRMInstance< GUM_SCALAR >* >& source =
539  **(data.matches.begin());
540 
541  for (Size idx = 0; idx < match.size(); ++idx) {
542  __reducedInstances.insert(match[idx]);
543  const auto& chains = source[idx]->type().slotChains();
544 
545  for (const auto sc : chains) {
546 #ifdef DEBUG
547  GUM_ASSERT(!(sc->isMultiple()));
548 #endif
549 
550  try {
551  bij.insert(&(source[idx]
552  ->getInstance(sc->id())
553  .get(sc->lastElt().safeName())
554  .type()
555  .variable()),
556  &(match[idx]
557  ->getInstance(sc->id())
558  .get(sc->lastElt().safeName())
559  .type()
560  .variable()));
561  } catch (DuplicateElement&) {
562  try {
563  if (bij.first(&(match[idx]
564  ->getInstance(sc->id())
565  .get(sc->lastElt().safeName())
566  .type()
567  .variable()))
568  != &(source[idx]
569  ->getInstance(sc->id())
570  .get(sc->lastElt().safeName())
571  .type()
572  .variable())) {
573  delete my_pool;
574  GUM_ERROR(OperationNotAllowed, "fake pattern");
575  }
576  } catch (NotFound&) {
577  delete my_pool;
578  GUM_ERROR(OperationNotAllowed, "fake pattern");
579  }
580  }
581  }
582  }
583 
584  for (const auto p : pool) {
585  for (const auto v : p->variablesSequence()) {
586  try {
587  target = data.map[data.vars.first(v)];
588  bij.insert(
589  v, &(match[target.first]->get(target.second).type().variable()));
590  } catch (NotFound&) {
591  GUM_ASSERT(bij.existsFirst(v));
592  } catch (DuplicateElement&) {}
593  }
594 
595  try {
596  my_pool->insert(copyPotential(bij, *p));
597  } catch (Exception&) {
598  for (const auto pot : *my_pool)
599  delete pot;
600 
601  delete my_pool;
602  GUM_ERROR(OperationNotAllowed, "fake pattern");
603  }
604  }
605 
606  return my_pool;
607  }
608 
609  template < typename GUM_SCALAR >
611  typename StructuredInference< GUM_SCALAR >::RGData& rg_data) {
613  Potential< GUM_SCALAR >* pot = nullptr;
614  PRMInstance< GUM_SCALAR >* inst = nullptr;
615 
616  for (const auto& elt : *this->_sys) {
617  inst = elt.second;
618 
619  if (!__reducedInstances.exists(inst)) {
620  // Checking if its not an empty class
621  if (inst->size()) {
623 
624  try {
625  data = __cdata_map[&(inst->type())];
626  } catch (NotFound&) {
628  __cdata_map.insert(&(inst->type()), data);
629  }
630 
631  data->instances.insert(inst);
632  // Filling up the partial ordering
633  List< NodeSet > partial_order;
634 
635  if (data->inners().size()) partial_order.push_back(data->inners());
636 
637  if (data->aggregators().size())
638  for (const auto agg : data->aggregators())
639  partial_order[0].insert(agg);
640 
641  if (data->outputs().size()) partial_order.push_back(data->outputs());
642 
643  if (__query.first == inst) {
644  // First case, the instance contains the query
645  partial_order[0].erase(__query.second->id());
646 
647  if (partial_order[0].empty()) partial_order.erase(0);
648 
649  if (partial_order.size() > 1) {
650  partial_order[1].erase(__query.second->id());
651 
652  if (partial_order[1].empty()) partial_order.erase(1);
653  }
654 
655  NodeSet query_set;
656  query_set.insert(__query.second->id());
657  partial_order.insert(query_set);
658 
659  // Adding the potentials
660  for (auto attr = inst->begin(); attr != inst->end(); ++attr)
661  pool.insert(&(
662  const_cast< Potential< GUM_SCALAR >& >((*(attr.val())).cpf())));
663 
664  // Adding evidences if any
665  if (this->hasEvidence(inst))
666  for (const auto& elt : this->evidence(inst))
667  pool.insert(const_cast< Potential< GUM_SCALAR >* >(elt.second));
668 
670  &(data->moral_graph), &(data->mods), &(partial_order));
671  const std::vector< NodeId >& v = t.eliminationOrder();
672 
673  if (partial_order.size() > 1)
674  for (size_t idx = 0; idx < partial_order[0].size(); ++idx)
676  &(inst->get(v[idx]).type().variable()), pool, __trash);
677  } else if (this->hasEvidence(inst)) {
678  // Second case, the instance has evidences
679  // Adding the potentials
680  for (const auto elt : *inst)
681  pool.insert(
682  &const_cast< Potential< GUM_SCALAR >& >(elt.second->cpf()));
683 
684  // Adding evidences
685  for (const auto& elt : this->evidence(inst))
686  pool.insert(const_cast< Potential< GUM_SCALAR >* >(elt.second));
687 
689  &(data->moral_graph), &(data->mods), &(partial_order));
690 
691  for (size_t idx = 0; idx < partial_order[0].size(); ++idx)
693  &(inst->get(t.eliminationOrder()[idx]).type().variable()),
694  pool,
695  __trash);
696  } else {
697  // Last cast, the instance neither contains evidences nor
698  // instances
699  // We translate the class level potentials into the instance ones
700  // and
701  // proceed with elimination
702  for (const auto srcPot : data->pool) {
703  pot = copyPotential(inst->bijection(), *srcPot);
704  pool.insert(pot);
705  __trash.insert(pot);
706  }
707 
708  for (const auto agg : data->c.aggregates())
709  pool.insert(&(const_cast< Potential< GUM_SCALAR >& >(
710  inst->get(agg->id()).cpf())));
711 
712  // We eliminate inner aggregators with their parents if necessary
713  // (see
714  // CData constructor)
715  Size size = data->inners().size() + data->aggregators().size();
716 
717  for (size_t idx = data->inners().size(); idx < size; ++idx)
719  &(inst->get(data->elim_order()[idx]).type().variable()),
720  pool,
721  __trash);
722  }
723 
724  for (const auto pot : pool)
725  rg_data.pool.insert(pot);
726  }
727  }
728  }
729  }
730 
731  template < typename GUM_SCALAR >
734  // We first add edges between variables already in pool (i.e. those of the
735  // reduced instances)
736  NodeId id_1, id_2;
737 
738  for (const auto pot : data.pool) {
739  const Sequence< const DiscreteVariable* >& vars = pot->variablesSequence();
740 
741  for (Size var_1 = 0; var_1 < vars.size(); ++var_1) {
742  if (data.var2node.existsFirst(vars.atPos(var_1))) {
743  id_1 = data.var2node.second(vars.atPos(var_1));
744  } else {
745  id_1 = data.reducedGraph.addNode();
746  data.var2node.insert(vars.atPos(var_1), id_1);
747  data.mods.insert(id_1, vars.atPos(var_1)->domainSize());
748  data.outputs().insert(id_1);
749  }
750 
751  for (Size var_2 = var_1 + 1; var_2 < vars.size(); ++var_2) {
752  if (data.var2node.existsFirst(vars.atPos(var_2))) {
753  id_2 = data.var2node.second(vars.atPos(var_2));
754  } else {
755  id_2 = data.reducedGraph.addNode();
756  data.var2node.insert(vars.atPos(var_2), id_2);
757  data.mods.insert(id_2, vars.atPos(var_2)->domainSize());
758  data.outputs().insert(id_2);
759  }
760 
761  try {
762  data.reducedGraph.addEdge(id_1, id_2);
763  } catch (DuplicateElement&) {}
764  }
765  }
766  }
767 
768  // Adding potentials obtained from reduced patterns
769  for (const auto& elt : __elim_map) {
770  // We add edges between variables in the same reduced patterns
771  for (const auto pot : *elt.second) {
772  data.pool.insert(pot);
774  pot->variablesSequence();
775 
776  for (Size var_1 = 0; var_1 < vars.size(); ++var_1) {
777  if (data.var2node.existsFirst(vars.atPos(var_1))) {
778  id_1 = data.var2node.second(vars.atPos(var_1));
779  } else {
780  id_1 = data.reducedGraph.addNode();
781  data.var2node.insert(vars.atPos(var_1), id_1);
782  data.mods.insert(id_1, vars.atPos(var_1)->domainSize());
783  data.outputs().insert(id_1);
784  }
785 
786  for (Size var_2 = var_1 + 1; var_2 < vars.size(); ++var_2) {
787  if (data.var2node.existsFirst(vars.atPos(var_2))) {
788  id_2 = data.var2node.second(vars.atPos(var_2));
789  } else {
790  id_2 = data.reducedGraph.addNode();
791  data.var2node.insert(vars.atPos(var_2), id_2);
792  data.mods.insert(id_2, vars.atPos(var_2)->domainSize());
793  data.outputs().insert(id_2);
794  }
795 
796  try {
797  data.reducedGraph.addEdge(id_1, id_2);
798  } catch (DuplicateElement&) {}
799  }
800  }
801  }
802  }
803  }
804 
805  template < typename GUM_SCALAR >
808  partial_order.insert(NodeSet());
809  partial_order.insert(NodeSet());
810  }
811 
812  template < typename GUM_SCALAR >
814  const gspan::Pattern& p,
816  pattern(p),
817  matches(m), __real_order(0) {
819 
820  for (int i = 0; i < 4; ++i)
821  __partial_order.push_front(NodeSet());
822  }
823 
824  template < typename GUM_SCALAR >
826  const typename StructuredInference< GUM_SCALAR >::PData& source) :
827  pattern(source.pattern),
828  matches(source.matches), graph(source.graph), mod(source.mod),
829  node2attr(source.node2attr), vars(source.vars),
832  }
833 
834  template < typename GUM_SCALAR >
835  const List< NodeSet >*
837  if (!__real_order) {
839 
840  for (const auto set : __partial_order)
841  if (set.size() > 0) __real_order->insert(set);
842  }
843 
844  return __real_order;
845  }
846 
847  template < typename GUM_SCALAR >
849  const PRMClass< GUM_SCALAR >& a_class) :
850  c(a_class),
851  __elim_order(0) {
853 
854  // First step we add Attributes and Aggregators
855  for (const auto node : c.containerDag().nodes()) {
856  switch (c.get(node).elt_type()) {
858  pool.insert(
859  &(const_cast< Potential< GUM_SCALAR >& >(c.get(node).cpf())));
860  // break omited : We want to execute the next block
861  // for attributes
862  }
863 
866  mods.insert(node, c.get(node).type()->domainSize());
867  break;
868  }
869 
870  default: { /* do nothing */
871  }
872  }
873  }
874 
875  // Second, we add edges, moralise the graph and build the partial ordering
876  for (const auto node : moral_graph.nodes()) {
877  const auto& parents = c.containerDag().parents(node);
878 
879  // Adding edges and marrying parents
880  for (auto tail = parents.begin(); tail != parents.end(); ++tail) {
883  moral_graph.addEdge(*tail, node);
884  NodeSet::const_iterator marry = tail;
885  ++marry;
886 
887  while (marry != parents.end()) {
890  moral_graph.addEdge(*tail, *marry);
891 
892  ++marry;
893  }
894  }
895  }
896 
897  // Adding nodes to the partial ordering
898  switch (c.get(node).elt_type()) {
900  if (c.isOutputNode(c.get(node)))
901  outputs().insert(node);
902  else
903  aggregators().insert(node);
904 
905  // If the aggregators is not an output and have parents which are
906  // not outputs, we must eliminate the parents after adding the
907  // aggregator's CPT
908  for (const auto par : c.containerDag().parents(node)) {
909  const auto& prnt = c.get(par);
910 
911  if ((!c.isOutputNode(prnt))
914  inners().erase(prnt.id());
915  aggregators().insert(prnt.id());
916  }
917  }
918 
919  break;
920  }
921 
923  pool.insert(
924  const_cast< Potential< GUM_SCALAR >* >(&(c.get(node).cpf())));
925 
926  if (c.isOutputNode(c.get(node)))
927  outputs().insert(node);
928  else if (!aggregators().exists(node))
929  inners().insert(node);
930 
931  break;
932  }
933 
934  default: { /* Do nothing */
935  }
936  }
937  }
938 
939  if (inners().size()) partial_order.insert(inners());
940 
941  if (aggregators().size()) partial_order.insert(aggregators());
942 
943  if (outputs().size()) partial_order.insert(outputs());
944 
945  GUM_ASSERT(partial_order.size());
947  __elim_order = t.eliminationOrder();
948 
949  for (size_t i = 0; i < inners().size(); ++i)
950  eliminateNode(&(c.get(__elim_order[i]).type().variable()), pool, __trash);
951  }
952 
953  template < typename GUM_SCALAR >
956 
957  for (const auto pot : __trash)
958  delete pot;
959  }
960 
961  template < typename GUM_SCALAR >
963  const PRMInstance< GUM_SCALAR >* i = (this->_sys->begin()).val();
964  __query = std::make_pair(i, i->begin().val());
965  __found_query = false;
967  __buildReduceGraph(data);
968  }
969 
970  template < typename GUM_SCALAR >
972  __mining = b;
973  }
974 
975  template < typename GUM_SCALAR >
977  const PRMInstance< GUM_SCALAR >* i,
978  const PRMAttribute< GUM_SCALAR >* a) const {
979  return i->name() + __dot + a->safeName();
980  }
981 
982  template < typename GUM_SCALAR >
984  const PRMInstance< GUM_SCALAR >* i,
985  const PRMAttribute< GUM_SCALAR >& a) const {
986  return i->name() + __dot + a.safeName();
987  }
988 
989  template < typename GUM_SCALAR >
991  const PRMInstance< GUM_SCALAR >* i,
992  const PRMSlotChain< GUM_SCALAR >& a) const {
993  return i->name() + __dot + a.lastElt().safeName();
994  }
995 
996  template < typename GUM_SCALAR >
999  }
1000 
1001  template < typename GUM_SCALAR >
1004  }
1005 
1006  template < typename GUM_SCALAR >
1007  INLINE std::string StructuredInference< GUM_SCALAR >::name() const {
1008  return "StructuredInference";
1009  }
1010 
1011  template < typename GUM_SCALAR >
1013  return *__gspan;
1014  }
1015 
1016  template < typename GUM_SCALAR >
1017  INLINE const GSpan< GUM_SCALAR >&
1019  return *__gspan;
1020  }
1021 
1022  template < typename GUM_SCALAR >
1025  NodeId id,
1027  data.graph.eraseNode(id);
1028  GUM_ASSERT(!data.graph.exists(id));
1029  data.mod.erase(id);
1030  GUM_ASSERT(!data.mod.exists(id));
1031  data.node2attr.eraseFirst(id);
1032  GUM_ASSERT(!data.node2attr.existsFirst(id));
1033  data.map.erase(id);
1034  GUM_ASSERT(!data.map.exists(id));
1035  data.vars.eraseFirst(id);
1036  GUM_ASSERT(!data.vars.existsFirst(id));
1037  data.inners().erase(id);
1038  GUM_ASSERT(!data.inners().exists(id));
1039  pool.erase(data.pots[id]);
1040  GUM_ASSERT(!pool.exists(data.pots[id]));
1041  data.pots.erase(id);
1042  GUM_ASSERT(!data.pots.exists(id));
1043  }
1044 
1045  } /* namespace prm */
1046 } /* namespace gum */
List< NodeSet > partial_order
The partial order used of variable elimination.
void __buildPatternGraph(PData &data, Set< Potential< GUM_SCALAR > * > &pool, const Sequence< PRMInstance< GUM_SCALAR > * > &match)
Build the DAG corresponding to Pattern data.pattern, initialize pool with all the Potentials of all v...
A class to combine efficiently several MultiDim tablesMultiDimCombinationDefault is a class designed ...
Headers of StructuredInference.
void insert(const T1 &first, const T2 &second)
Inserts a new association in the gum::Bijection.
HashTable< const PRMClass< GUM_SCALAR > *, CData *> __cdata_map
Mapping between a Class<GUM_SCALAR> and data about instances reduced using only Class<GUM_SCALAR> lev...
aGrUM&#39;s Potential is a multi-dimensional array with tensor operators.
Definition: potential.h:57
void __reducePattern(const gspan::Pattern *p)
Proceed with the elimination of all inner variables (observed or not) of all usable matches of Patter...
NodeProperty< Size > mods
The class variables modalities.
UndiGraph reducedGraph
The reduced graph.
virtual void _marginal(const typename PRMInference< GUM_SCALAR >::Chain &chain, Potential< GUM_SCALAR > &m)
See PRMInference::_marginal().
virtual void addNodeWithId(const NodeId id)
try to insert a node with the given id
Val & push_back(Args &&... args)
An alias for pushBack used for STL compliance.
PData(const gspan::Pattern &p, typename GSpan< GUM_SCALAR >::MatchedInstances &m)
Default constructor.
double step() const
Returns the delta time between now and the last reset() call (or the constructor).
Definition: timer_inl.h:39
NodeSet & queries()
Returns the set of queried nodes given all the matches of pattern.
List< NodeSet > partial_order
Partial order used for triangulation, first is outputs nodes, second query nodes. ...
Set< Potential< GUM_SCALAR > *> __trash
Keeping track of create potentials to delete them after inference.
PRMAttribute< GUM_SCALAR > & get(NodeId id)
Getter on an PRMAttribute<GUM_SCALAR> of this PRMInstance<GUM_SCALAR>.
const T1 & first(const T2 &second) const
Returns the first value of a pair given its second value.
const std::string & name() const
Returns the name of this object.
Definition: PRMObject_inl.h:32
virtual GUM_SCALAR get(const Instantiation &i) const final
Default implementation of MultiDimContainer::get().
GSpan< GUM_SCALAR >::MatchedInstances & matches
A reference over the usable matches of pattern.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
void eraseFirst(const T1 &first)
Erases an association containing the given first element.
Size size() const noexcept
Returns the size of the sequence.
Definition: sequence_tpl.h:35
EMap & evidence(const PRMInstance< GUM_SCALAR > &i)
Returns EMap of evidences over i.
GSpan< GUM_SCALAR > * __gspan
Pointer over th GSpan<GUM_SCALAR> instance used by this class.
An PRMInstance is a Bayesian Network fragment defined by a Class and used in a PRMSystem.
Definition: PRMInstance.h:60
const Potential< GUM_SCALAR > & normalize() const
normalisation of this do nothing if sum is 0
UndiGraph moral_graph
The class moral graph. NodeId matches those in c.
PData * __pdata
The pattern data of the pattern which one of its matches contains the query.
The generic class for storing (ordered) sequences of objects.
Definition: sequence.h:1019
virtual void addEdge(const NodeId first, const NodeId second)
insert a new edge into the undirected graph
Definition: undiGraph_inl.h:32
NodeSet & outputs()
Returns the set of outputs nodes given all the matches of pattern.
PRMClass< GUM_SCALAR > & type()
Returns the type of this instance.
NodeProperty< std::pair< Idx, std::string > > map
To ease translating potentials from one match to another.
bool __mining
Flag which tells to use pattern mining or not.
virtual void erase(const DiscreteVariable &var) final
Removes a var from the variables of the multidimensional matrix.
Set< Potential< GUM_SCALAR > *> * __eliminateObservedNodesInSource(typename StructuredInference::PData &data, const Set< Potential< GUM_SCALAR > * > &pool, const Sequence< PRMInstance< GUM_SCALAR > * > &match, const std::vector< NodeId > &elim_order)
List< NodeSet > * __real_order
A copy of __partial_order without empty sets.
Set< const PRMInstance< GUM_SCALAR > *> instances
The Set of Instances reduces at class level.
Bijection< const DiscreteVariable *, NodeId > var2node
Mapping between DiscreteVariable and NodeId.
void __insertNodeInElimLists(typename StructuredInference::PData &data, const Sequence< PRMInstance< GUM_SCALAR > * > &match, PRMInstance< GUM_SCALAR > *inst, PRMAttribute< GUM_SCALAR > *attr, NodeId id, std::pair< Idx, std::string > &v)
Abstract class representing an element of PRM class.
Private structure to represent data about a Class<GUM_SCALAR>.
void __reduceAloneInstances(RGData &data)
Add the reduced potentials of instances not in any used patterns.
UndiGraph graph
A yet to be triangulated undigraph.
NodeSet & obs()
Returns the set of inner and observed nodes given all the matches of pattern.
std::string __dot
Unreduce the match containing the query.
void erase(const Key &k)
Erases an element from the set.
Definition: set_tpl.h:653
bool exists(const NodeId id) const
alias for existsNode
Base class for discrete random variable.
Generic doubly linked lists.
Definition: list.h:369
gum is the global namespace for all aGrUM entities
Definition: agrum.h:25
NodeSet & outputs()
Returns the set of outputs nodes.
bool __found_query
Flag with an explicit name.
iterator begin() const
The usual unsafe begin iterator to parse the set.
Definition: set_tpl.h:514
void __addEdgesInReducedGraph(RGData &data)
Add the nodes in the reduced graph.
PRM< GUM_SCALAR > const * _prm
The PRM<GUM_SCALAR> on which inference is done.
Definition: PRMInference.h:210
virtual NodeId addNode()
insert a new node and return its id
const gspan::Pattern & pattern
The pattern for which this represents data about it.
Size size() const
Returns the number of attributes in this PRMInstance<GUM_SCALAR>.
NodeSet & queries()
Returns the set of query nodes (which will not be eliminated).
StructuredInference & operator=(const StructuredInference &source)
Copy operator.
NodeProperty< Potential< GUM_SCALAR > *> pots
To handle barren nodes.
void __buildReduceGraph(RGData &data)
This calls __reducePattern() over each pattern and then build the reduced graph which is used for inf...
const NodeSet & neighbours(const NodeId id) const
returns the set of edges adjacent to a given node
virtual void eraseNode(const NodeId id)
remove a node and its adjacent edges from the graph
Definition: undiGraph_inl.h:55
std::vector< std::pair< PRMInstance< GUM_SCALAR > *, std::string > > & getRefAttr(NodeId id)
Returns a vector of pairs of refering attributes of id.
NodeSet & outputs()
Returns the set of outputs nodes (which will be eliminated).
Representation of a setA Set is a structure that contains arbitrary elements.
Definition: set.h:162
const std::string & safeName() const
Returns the safe name of this PRMClassElement, if any.
void reset()
Reset the timer.
Definition: timer_inl.h:29
bool existsFirst(const T1 &first) const
Returns true if first is the first element in a pair in the gum::Bijection.
bool exists(const Key &k) const
Indicates whether a given elements belong to the set.
Definition: set_tpl.h:604
void __removeBarrenNodes(typename StructuredInference::PData &data, Set< Potential< GUM_SCALAR > * > &pool)
void erase(Size i)
Erases the ith element of the List (the first one is in position 0).
Definition: list_tpl.h:1906
HashTable< const Sequence< PRMInstance< GUM_SCALAR > *> *, Set< Potential< GUM_SCALAR > *> *> __elim_map
Mapping between a Pattern&#39;s match and its potential pool after inner variables were eliminated...
<agrum/PRM/structuredInference.h>
Bijection< NodeId, const DiscreteVariable *> vars
Bijection between graph&#39;s nodes and their corresponding DiscreteVariable, for inference purpose...
Private structure to represent data about a pattern.
class for graph triangulations for which we enforce a given partial ordering on the nodes elimination...
PRMInference< GUM_SCALAR >::Chain __query
The query.
void inc()
Operator increment.
StructuredInference(const PRM< GUM_SCALAR > &prm, const PRMSystem< GUM_SCALAR > &system, gspan::SearchStrategy< GUM_SCALAR > *strategy=0)
Default constructor.
Set< Potential< GUM_SCALAR > *> pool
The potential pool obtained by C elimination of inner nodes.
Size size() const noexcept
Returns the number of elements in the list.
Definition: list_tpl.h:1848
const Bijection< const DiscreteVariable *, const DiscreteVariable *> & bijection() const
Returns a mapping between DiscreteVariable used in this and the ones used in this PRMInstance<GUM_SCA...
Set< const PRMInstance< GUM_SCALAR > *> __reducedInstances
This keeps track of reduced instances.
const std::vector< NodeId > & eliminationOrder()
returns an elimination ordering compatible with the triangulated graph
Set< NodeId > barren
Set of barren nodes.
const NodeGraphPart & nodes() const
return *this as a NodeGraphPart
A PRMSystem is a container of PRMInstance and describe a relational skeleton.
Definition: PRMObject.h:226
Base class for all aGrUM&#39;s exceptions.
Definition: exceptions.h:103
virtual std::string name() const
Tells this algorithm to use pattern mining or not.
Set of pairs of elements with fast search for both elements.
Definition: bijection.h:1803
Potential< GUM_SCALAR > * copyPotential(const Bijection< const DiscreteVariable *, const DiscreteVariable * > &bij, const Potential< GUM_SCALAR > &source)
Returns a copy of a Potential after applying a bijection over the variables in source.
Definition: utils_prm_tpl.h:27
List< NodeSet > __partial_order
We&#39;ll use a PartialOrderedTriangulation with three sets: output, nodes and obs with children outside ...
void eliminateNode(const DiscreteVariable *var, Set< Potential< GUM_SCALAR > * > &pool, Set< Potential< GUM_SCALAR > * > &trash)
Proceeds with the elimination of var in pool.
NodeSet & inners()
Returns the set of inner nodes.
Set< Potential< GUM_SCALAR > *> * __eliminateObservedNodes(typename StructuredInference::PData &data, const Set< Potential< GUM_SCALAR > * > &pool, const Sequence< PRMInstance< GUM_SCALAR > * > &match, const std::vector< NodeId > &elim_order)
Add in data.queries() any queried variable in one of data.pattern matches.
A PRMSlotChain represents a sequence of gum::prm::PRMClassElement<GUM_SCALAR> where the n-1 first gum...
Definition: PRMObject.h:218
bool hasEvidence() const
Returns true if i has evidence on PRMAttribute<GUM_SCALAR> a.
PRMSystem< GUM_SCALAR > const * _sys
The Model on which inference is done.
Definition: PRMInference.h:213
NodeProperty< Size > mod
The pattern&#39;s variables modalities.
NodeSet & aggregators()
Returns the set of aggregators and their parents.
Unsafe iterators for the Set class.
Definition: set.h:1022
std::pair< const PRMInstance< GUM_SCALAR > *, const PRMAttribute< GUM_SCALAR > *> Chain
Code alias.
Definition: PRMInference.h:54
Set< Potential< GUM_SCALAR > *> * __translatePotSet(typename StructuredInference::PData &data, const Set< Potential< GUM_SCALAR > * > &pool, const Sequence< PRMInstance< GUM_SCALAR > * > &match)
Translate a given Potential Set into one w.r.t. variables in match.
Class for assigning/browsing values to tuples of discrete variables.
Definition: instantiation.h:80
virtual void _joint(const std::vector< typename PRMInference< GUM_SCALAR >::Chain > &queries, Potential< GUM_SCALAR > &j)
See PRMInference::_joint().
void erase(const Key &k)
Remove an element from the sequence.
Definition: sequence_tpl.h:450
HashTable< const PRMClass< GUM_SCALAR > *, std::vector< NodeId > *> __outputs
std::string __str(const PRMInstance< GUM_SCALAR > *i, const PRMAttribute< GUM_SCALAR > *a) const
Val & insert(const Val &val)
Inserts a new element at the end of the chained list (alias of pushBack).
Definition: list_tpl.h:1616
This abstract class is used as base class for all inference class on PRM<GUM_SCALAR>.
Definition: PRMInference.h:49
bool __allInstanceNoRefAttr(typename StructuredInference::PData &data, std::pair< Idx, std::string > attr)
Private structure to represent data about a reduced graph.
std::vector< NodeId > & elim_order()
The elimination order for nodes of this class.
This class represents a Probabilistic Relational PRMSystem<GUM_SCALAR>.
Definition: PRM.h:63
const iterator & end()
Returns a reference over the iterator at the end of the list of gum::prm::PRMAttribute<GUM_SCALAR> in...
A PRMClass is an object of a PRM representing a fragment of a Bayesian Network which can be instantia...
Definition: PRMClass.h:63
This class discovers pattern in a PRM<GUM_SCALAR>&#39;s PRMSystem<GUM_SCALAR> to speed up structured infe...
Definition: DFSTree.h:54
std::pair< Idx, std::string > __query_data
virtual void set(const Instantiation &i, const GUM_SCALAR &value) const final
Default implementation of MultiDimContainer::set().
void setFirst()
Assign the first values to the tuple of the Instantiation.
virtual ~StructuredInference()
Destructor.
Size Idx
Type for indexes.
Definition: types.h:50
CData(const PRMClass< GUM_SCALAR > &c)
Default constructor.
NodeSet & inners()
Returns the set of inner nodes.
GSpan< GUM_SCALAR > & gspan()
Returns the instance of gspan used to search patterns.
virtual void _evidenceRemoved(const typename PRMInference< GUM_SCALAR >::Chain &chain)
See PRMInference::_evidenceRemoved().
PRMAttribute is a member of a Class in a PRM.
Definition: PRMAttribute.h:58
Bijection< NodeId, std::string > node2attr
A bijection to easily keep track between graph and attributes, its of the form instance_name DOT attr...
virtual void _evidenceAdded(const typename PRMInference< GUM_SCALAR >::Chain &chain)
See PRMInference::_evidenceAdded().
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:45
PRMClassElement< GUM_SCALAR > & lastElt()
Returns the last element of the slot chain, typically this is an gum::PRMAttribute or a gum::PRMAggre...
virtual const Sequence< const DiscreteVariable *> & variablesSequence() const final
Returns a const ref to the sequence of DiscreteVariable*.
iterator begin()
Returns an iterator at the begining of the list of gum::prm::PRMAttribute<GUM_SCALAR> in this PRMInst...
Set< Potential< GUM_SCALAR > *> pool
The pool of potentials matching the reduced graph.
Size size() const noexcept
Returns the number of elements in the set.
Definition: set_tpl.h:698
void setPatternMining(bool b)
Tells this algorithm to use pattern mining or not.
static INLINE bool isAggregate(const PRMClassElement< GUM_SCALAR > &elt)
Return true if obj is of type PRMAggregate.
virtual bool contains(const DiscreteVariable &var) const final
Returns true if var is in *this.
virtual TABLE< GUM_SCALAR > * combine(const Set< const TABLE< GUM_SCALAR > * > &set)
Creates and returns the result of the combination of the tables within set.
This contains all the information we want for a node in a DFSTree.
Definition: pattern.h:70
This is an abstract class used to tune search strategies in the gspan algorithm.
Definition: DFSTree.h:58
Size NodeId
Type for node ids.
Definition: graphElements.h:97
NodeProperty< Size > mods
Mapping between NodeId and modalities.
void insert(const Key &k)
Inserts a new element into the set.
Definition: set_tpl.h:610
const Key & back() const
Returns the last element of the sequence.
Definition: sequence_tpl.h:565
const PRMClass< GUM_SCALAR > & c
The class about what this data is about.
#define GUM_ERROR(type, msg)
Definition: exceptions.h:52
const Key & atPos(Idx i) const
Returns the object at the pos i.
Definition: sequence_tpl.h:497
Set< Potential< GUM_SCALAR > *> __trash
void __removeNode(typename StructuredInference::PData &data, NodeId id, Set< Potential< GUM_SCALAR > * > &pool)
bool end() const
Returns true if the Instantiation reached the end.
Potential< GUM_SCALAR > * multPotential(const Potential< GUM_SCALAR > &t1, const Potential< GUM_SCALAR > &t2)
void searchPatterns()
Search for patterns without doing any computations.
void insert(const Key &k)
Insert an element at the end of the sequence.
Definition: sequence_tpl.h:405