aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
SVE_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /**
23  * @file
24  * @brief Inline implementation of SVE.
25  *
26  * @author Lionel TORTI and Pierre-Henri WUILLEMIN(@LIP6)
27  */
28 #include <agrum/PRM/classDependencyGraph.h>
29 #include <agrum/PRM/inference/SVE.h>
30 
31 namespace gum {
32  namespace prm {
33 
34  template < typename GUM_SCALAR >
36  const PRMAttribute< GUM_SCALAR >& a) {
37  std::stringstream s;
38  const auto& class_a = i.type().get(a.safeName());
39  s << &(a.type().variable()) << " - ";
40  s << i.name() << "." << a.safeName() << ": input=" << i.type().isInputNode(class_a);
41  s << " output=" << i.type().isOutputNode(class_a)
42  << " inner=" << i.type().isInnerNode(class_a);
43  return s.str();
44  }
45 
46  template < typename GUM_SCALAR >
48  std::stringstream s;
49  s << i.name() << std::endl;
50  s << "Attributes: " << std::endl;
51  for (auto a: i) {
52  s << __print_attribute__(i, *(a.second));
53  }
54  if (i.type().slotChains().size()) {
55  s << std::endl << "SlotChains: " << std::endl;
56  for (auto sc: i.type().slotChains()) {
57  s << sc->name() << " ";
58  }
59  }
60  return s.str();
61  }
62 
63  template < typename GUM_SCALAR >
65  std::stringstream str;
66  for (auto i: s) {
67  str << __print_instance__(*(i.second)) << std::endl;
68  }
69  return str.str();
70  }
71 
72  template < typename LIST >
74  std::stringstream s;
75  s << "[";
76  for (auto i: l) {
77  s << i->name() << " ";
78  }
79  s << "]";
80  return s.str();
81  }
82 
83  template < typename GUM_SCALAR >
85  std::stringstream s;
86  s << "{";
87  for (auto var: pot.variablesSequence()) {
88  s << var << ", ";
89  }
90  s << "}";
91  return s.str();
92  }
93 
94  template < typename SET >
96  std::stringstream s;
97  s << "[";
98  for (auto p: set) {
99  s << __print_pot__(*p) << " ";
100  }
101  s << "]";
102  return s.str();
103  }
104 
105  template < typename GUM_SCALAR >
106  SVE< GUM_SCALAR >::~SVE() {
108 
109  for (const auto& elt: _elim_orders_)
110  delete elt.second;
111 
112  for (const auto& elt: _lifted_pools_)
113  delete elt.second;
114 
115  if (_class_elim_order_ != nullptr) delete _class_elim_order_;
116 
117  for (const auto trash: _lifted_trash_)
118  delete trash;
119 
120  for (auto set: _delayedVariables_)
121  delete set.second;
122  }
123 
124  template < typename GUM_SCALAR >
126  NodeId node,
127  BucketSet& pool,
128  BucketSet& trash) {
131  // Downward elimination
132  List< const PRMInstance< GUM_SCALAR >* > elim_list;
134 
135  for (auto iter = query->beginInvRef(); iter != query->endInvRef(); ++iter) {
136  for (auto child = (*(iter.val())).begin(); child != (*(iter.val())).end(); ++child) {
137  if (!ignore.exists(child->first)) {
139  child->first,
140  pool,
141  trash,
142  elim_list,
143  ignore,
144  eliminated);
145  } else if (!eliminated.exists(child->first)) {
148  }
149  }
150  }
151 
152  // Eliminating all nodes in query instance, except query
156 
157  if (this->hasEvidence(query)) { _insertEvidence_(query, pool); }
158 
159  for (auto attr = query->begin(); attr != query->end(); ++attr) {
160  pool.insert(&(const_cast< Potential< GUM_SCALAR >& >((*(attr.val())).cpf())));
161  }
162 
163  for (size_t idx = 0; idx < t.eliminationOrder().size(); ++idx) {
164  if ((t.eliminationOrder()[idx] != node)
166  auto var_id = t.eliminationOrder()[idx];
167  const auto& var = bn.variable(var_id);
169  }
170  }
171 
173 
174  // Eliminating delayed variables, if any
176 
178  // Eliminating instance in elim_list
179  List< const PRMInstance< GUM_SCALAR >* > tmp_list;
180 
181  while (!elim_list.empty()) {
183  if (!ignore.exists(elim_list.front())) {
185  elim_list.front(),
186  pool,
187  trash,
188  elim_list,
189  ignore,
190  eliminated);
191  }
192  } else {
194  }
195 
197  }
198 
199  // Upward elimination
200  for (const auto chain: query->type().slotChains())
201  for (const auto parent: query->getInstances(chain->id()))
202  if (!ignore.exists(parent))
204  }
205 
206  template < typename GUM_SCALAR >
208  BucketSet& pool,
209  BucketSet& trash) {
211 
212  for (const auto var: *_delayedVariables_[i]) {
214 
215  for (const auto pot: pool)
216  if (pot->contains(*var)) {
217  bucket->add(*pot);
219  }
220 
221  for (const auto pot: toRemove)
222  pool.erase(pot);
223 
224  for (const auto other: bucket->allVariables())
225  if (other != var) bucket->add(*other);
226 
230  }
231  }
232 
233  template < typename GUM_SCALAR >
235  const PRMInstance< GUM_SCALAR >* from,
236  const PRMInstance< GUM_SCALAR >* i,
237  BucketSet& pool,
238  BucketSet& trash,
239  List< const PRMInstance< GUM_SCALAR >* >& elim_list,
240  Set< const PRMInstance< GUM_SCALAR >* >& ignore,
241  Set< const PRMInstance< GUM_SCALAR >* >& eliminated) {
243  ignore.insert(i);
244  // Calling elimination over child instance
245  List< const PRMInstance< GUM_SCALAR >* > my_list;
246 
247  for (auto iter = i->beginInvRef(); iter != i->endInvRef(); ++iter) {
248  for (auto child = (*(iter.val())).begin(); child != (*(iter.val())).end(); ++child) {
249  if (!ignore.exists(child->first)) {
251  } else if (!eliminated.exists(child->first)) {
254  }
255  }
256  }
257 
258  // Eliminating all nodes in current instance
261 
262  // Calling elimination over child's parents
263  for (const auto node: my_list) {
264  if (_checkElimOrder_(i, node) && (node != from)) {
265  if (!ignore.exists(node)) {
267  }
268  } else if (node != from) {
270  }
271  }
272 
273  // Adding parents instance to elim_list
274  for (const auto chain: i->type().slotChains()) {
275  for (const auto inst: i->getInstances(chain->id())) {
276  if (inst != from) { elim_list.insert(inst); }
277  }
278  }
279  }
280 
281  template < typename GUM_SCALAR >
283  BucketSet& pool,
284  BucketSet& trash,
285  Set< NodeId >* delayedVars) {
286  if (this->hasEvidence(i)) {
288  } else {
290 
291  for (const auto agg: i->type().aggregates())
293 
294  try {
296 
297  std::vector< const DiscreteVariable* > elim;
298 
299  for (const auto node: _getElimOrder_(i->type())) {
300  const auto& var = bn.variable(node);
301  if (delayedVars != nullptr) {
302  if (!delayedVars->exists(node)) {
303  const auto& var = bn.variable(node);
304  elim.push_back(&var);
305  }
306  } else {
307  elim.push_back(&var);
308  }
309  }
310 
312  } catch (NotFound&) {
313  // Raised if there is no inner nodes to eliminate
314  }
315  }
316 
317  // Eliminating delayed variables, if any
319  }
320 
321  template < typename GUM_SCALAR >
323  const PRMInstance< GUM_SCALAR >* i,
324  BucketSet& pool,
325  BucketSet& trash,
326  List< const PRMInstance< GUM_SCALAR >* >& elim_list,
327  Set< const PRMInstance< GUM_SCALAR >* >& ignore,
328  Set< const PRMInstance< GUM_SCALAR >* >& eliminated) {
329  // Downward elimination
330  ignore.insert(i);
331 
332  for (auto iter = i->beginInvRef(); iter != i->endInvRef(); ++iter) {
333  for (auto child = (*(iter.val())).begin(); child != (*(iter.val())).end(); ++child) {
334  if (!ignore.exists(child->first)) {
336  }
337  }
338  }
339 
340  // Eliminating all nodes in i instance
343  // Eliminating instance in elim_list
344  List< const PRMInstance< GUM_SCALAR >* > tmp_list;
345 
346  while (!elim_list.empty()) {
347  if (_checkElimOrder_(i, elim_list.front())) {
348  if (!ignore.exists(elim_list.front())) {
350  elim_list.front(),
351  pool,
352  trash,
353  elim_list,
354  ignore,
355  eliminated);
356  }
357  } else {
359  }
360 
362  }
363 
364  // Upward elimination
365  for (const auto chain: i->type().slotChains()) {
366  for (const auto parent: i->getInstances(chain->id())) {
367  if (!ignore.exists(parent)) {
369  }
370  }
371  }
372  }
373 
374  template < typename GUM_SCALAR >
376  BucketSet& pool,
377  BucketSet& trash,
378  Set< NodeId >* delayedVars) {
379  // First we check if evidences are on inner nodes
380  bool inner = false;
381 
382  for (const auto& elt: this->evidence(i)) {
383  inner
384  = i->type().isInputNode(i->get(elt.first)) || i->type().isInnerNode(i->get(elt.first));
385 
386  if (inner) { break; }
387  }
388 
389  // Evidence on inner nodes
390  if (inner) {
393 
394  // We need a local to not eliminate queried inner nodes of the same
395  // class
396  for (const auto& elt: *i) {
397  tmp_pool.insert(&(const_cast< Potential< GUM_SCALAR >& >(elt.second->cpf())));
398  }
399 
403  // Removing Output nodes of elimination order
406 
407  for (size_t idx = 0; idx < full_elim_order.size(); ++idx) {
408  auto var_id = full_elim_order[idx];
409  const auto& var = bn.variable(var_id);
410 
411  if (!i->type().isOutputNode(i->get(full_elim_order[idx]))) {
413  } else if (delayedVars != nullptr) {
415  } else {
417  }
418  }
419 
421 
422  // Now we add the new potentials in pool and eliminate output nodes
423  for (const auto pot: tmp_pool)
424  pool.insert(pot);
425 
427 
428  } else {
432 
433  for (const auto agg: i->type().aggregates())
435 
436  try {
437  std::vector< const DiscreteVariable* > elim;
438 
439  for (auto iter = _getElimOrder_(i->type()).begin();
440  iter != _getElimOrder_(i->type()).end();
441  ++iter) {
442  const auto& var = bn.variable(*iter);
443  if (delayedVars != nullptr) {
444  if (!delayedVars->exists(*iter)) { elim.push_back(&var); }
445  } else {
446  elim.push_back(&var);
447  }
448  }
449 
451  } catch (NotFound&) { GUM_ERROR(FatalError, "there should be at least one node here.") }
452  }
453  }
454 
455  template < typename GUM_SCALAR >
457  BucketSet& pool,
458  BucketSet& trash) {
460 
461  try {
462  lifted_pool = _lifted_pools_[&(i->type())];
463  } catch (NotFound&) {
465  lifted_pool = _lifted_pools_[&(i->type())];
466  }
467 
468  for (const auto lifted_pot: *lifted_pool) {
470  pool.insert(pot);
471  trash.insert(pot);
472  }
473  }
474 
475  template < typename GUM_SCALAR >
480 
481  for (const auto node: c.containerDag().nodes())
483  if (c.isOutputNode(c.get(node)))
484  outers.insert(node);
485  else if (!outers.exists(node))
486  inners.insert(node);
487 
488  lifted_pool->insert(const_cast< Potential< GUM_SCALAR >* >(&(c.get(node).cpf())));
489  } else if (PRMClassElement< GUM_SCALAR >::isAggregate(c.get(node))) {
490  outers.insert(node);
491 
492  // We need to put in the output_elim_order aggregator's parents which
493  // are
494  // innner nodes
495  for (const auto par: c.containerDag().parents(node))
497  && c.isInnerNode(c.get(par))) {
498  inners.erase(par);
499  outers.insert(par);
500  }
501  }
502 
503  // Now we proceed with the elimination of inner attributes
506 
508 
510 
512 
513  for (size_t idx = 0; idx < inners.size(); ++idx)
515  *lifted_pool,
517 
518  // If there is not only inner and input Attributes
519  if (outers.size()) {
522  t.eliminationOrder().end()));
523  }
524  }
525 
526  template < typename GUM_SCALAR >
530  std::list< NodeId > l;
531 
532  for (const auto node: cdg.dag().nodes()) {
533  if (cdg.dag().parents(node).empty()) { l.push_back(node); }
534  }
535 
537 
538  while (!l.empty()) {
540 
543  }
544 
545  for (const auto child: cdg.dag().children(l.front())) {
547  }
548 
549  l.pop_front();
550  }
551 
553  for (auto c: class_elim_order) {
554  std::string name = c->name();
555  auto pos = name.find_first_of("<");
556  if (pos != std::string::npos) { name = name.substr(0, pos); }
557  try {
559  } catch (DuplicateElement&) {}
560  }
561  }
562 
563  template < typename GUM_SCALAR >
565  const PRMInstance< GUM_SCALAR >* i = chain.first;
566  const PRMAttribute< GUM_SCALAR >* elt = chain.second;
568 
570 
572 
573  for (const auto pot: pool) {
574  if (pot->contains(elt->type().variable())) { result.push_back(pot); }
575  }
576 
577  while (result.size() > 1) {
578  auto& p1 = *(result.back());
579  result.pop_back();
580  auto& p2 = *(result.back());
581  result.pop_back();
582  auto mult = new Potential< GUM_SCALAR >(p1 * p2);
583  trash.insert(mult);
585  }
586 
587  m = *(result.back());
588  m.normalize();
589 
590  for (const auto pot: trash) {
591  delete pot;
592  }
593  }
594 
595  template < typename GUM_SCALAR >
596  void SVE< GUM_SCALAR >::joint_(const std::vector< Chain >& queries,
597  Potential< GUM_SCALAR >& j) {
598  GUM_ERROR(FatalError, "Not implemented.")
599  }
600 
601  template < typename GUM_SCALAR >
603  const PRMSystem< GUM_SCALAR >& system) :
605  _class_elim_order_(0) {
607  }
608 
609  template < typename GUM_SCALAR >
611  BucketSet& pool) {
612  for (const auto& elt: this->evidence(i))
613  pool.insert(const_cast< Potential< GUM_SCALAR >* >(elt.second));
614  }
615 
616  template < typename GUM_SCALAR >
617  INLINE std::vector< NodeId >&
619  return *(_elim_orders_[&c]);
620  }
621 
622  template < typename GUM_SCALAR >
624  auto pos = s.find_first_of("<");
625  if (pos != std::string::npos) { return s.substr(0, pos); }
626  return s;
627  }
628 
629  template < typename GUM_SCALAR >
631  const PRMInstance< GUM_SCALAR >* second) {
632  if (_class_elim_order_ == 0) { _initElimOrder_(); }
633 
634  auto first_name = _trim_(first->type().name());
635  auto second_name = _trim_(second->type().name());
637  }
638 
639  template < typename GUM_SCALAR >
642  const PRMAggregate< GUM_SCALAR >* agg) {
643  return &(const_cast< Potential< GUM_SCALAR >& >(i->get(agg->id()).cpf()));
644  }
645 
646  template < typename GUM_SCALAR >
648  // Do nothing
649  }
650 
651  template < typename GUM_SCALAR >
653  // Do nothing
654  }
655 
656  template < typename GUM_SCALAR >
658  const PRMInstance< GUM_SCALAR >* j,
659  NodeId id) {
660  try {
662  } catch (NotFound&) {
663  _delayedVariables_.insert(i, new Set< const DiscreteVariable* >());
665  } catch (DuplicateElement&) {
666  // happends if j->get(id) is parent of more than one variable in i
667  }
668 
669  static std::string dot = ".";
670 
671  try {
672  _delayedVariablesCounters_[j->name() + dot + j->get(id).safeName()] += 1;
673  } catch (NotFound&) {
675  }
676  }
677 
678  template < typename GUM_SCALAR >
680  return "SVE";
681  }
682 
683  } /* namespace prm */
684 } /* namespace gum */
std::string __print_pot__(const Potential< GUM_SCALAR > &pot)
Definition: SVE_tpl.h:84
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643
std::string __print_list__(LIST l)
Definition: SVE_tpl.h:73
std::string __print_instance__(const PRMInstance< GUM_SCALAR > &i)
Definition: SVE_tpl.h:47
ParamScopeData(const std::string &s, const PRMReferenceSlot< GUM_SCALAR > &ref, Idx d)
std::string __print_attribute__(const PRMInstance< GUM_SCALAR > &i, const PRMAttribute< GUM_SCALAR > &a)
Definition: SVE_tpl.h:35
std::string __print_system__(const PRMSystem< GUM_SCALAR > &s)
Definition: SVE_tpl.h:64
std::string __print_set__(SET set)
Definition: SVE_tpl.h:95