aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
SVED_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 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 SVED.
25  *
26  * @author Lionel TORTI and Pierre-Henri WUILLEMIN(@LIP6)
27  */
28 #include <agrum/PRM/inference/SVED.h>
29 
30 namespace gum {
31  namespace prm {
32 
33  template < typename GUM_SCALAR >
34  SVED< GUM_SCALAR >::~SVED() {
36 
37  for (const auto& elt: elim_orders__)
38  delete elt.second;
39 
40  if (class_elim_order__ != nullptr) delete class_elim_order__;
41  }
42 
43  template < typename GUM_SCALAR >
44  void
46  NodeId node,
47  BucketSet& pool,
48  BucketSet& trash) {
49  Set< const PRMInstance< GUM_SCALAR >* > ignore;
51  // Extracting required attributes and slotchains
54  // Downward elimination
55  List< const PRMInstance< GUM_SCALAR >* > elim_list;
56 
57  for (const auto attr: attr_set) {
58  try {
59  for (auto iter = query->getRefAttr(attr).begin();
60  iter != query->getRefAttr(attr).end();
61  ++iter)
62  if ((!ignore.exists(iter->first)) && (bb__.exists(iter->first)))
64  iter->first,
65  pool,
66  trash,
67  elim_list,
68  ignore);
69  } catch (NotFound&) {
70  // Ok
71  }
72  }
73 
74  // Eliminating all nodes in query instance, except query
78 
80 
81  for (const auto attr: attr_set)
82  pool.insert(
83  &(const_cast< Potential< GUM_SCALAR >& >(query->get(attr).cpf())));
84 
85  for (size_t idx = 0; idx < t.eliminationOrder().size(); ++idx) {
86  if (t.eliminationOrder()[idx] != node) {
87  auto var_id = t.eliminationOrder()[idx];
88  const auto& var = bn.variable(var_id);
90  }
91  }
92 
94  // Eliminating instance in elim_list
95  List< const PRMInstance< GUM_SCALAR >* > tmp_list;
97 
98  while (!elim_list.empty()) {
100  if ((!ignore.exists(elim_list.front()))
101  && (bb__.exists(elim_list.front())))
103  elim_list.front(),
104  pool,
105  trash,
106  elim_list,
107  ignore);
108  } else if (bb__.exists(elim_list.front())) {
110  }
111 
113  }
114 
115  // Upward elimination
116  for (const auto chain: sc_set)
117  for (const auto parent: query->getInstances(chain))
118  if ((!ignore.exists(parent)) && (bb__.exists(*parent)))
120  }
121 
122  template < typename GUM_SCALAR >
124  const PRMInstance< GUM_SCALAR >* from,
125  const PRMInstance< GUM_SCALAR >* i,
126  BucketSet& pool,
127  BucketSet& trash,
128  List< const PRMInstance< GUM_SCALAR >* >& elim_list,
129  Set< const PRMInstance< GUM_SCALAR >* >& ignore) {
130  ignore.insert(i);
131  // Extracting required attributes and slotchains
133  Set< NodeId >& sc_set = getSCSet__(i);
134  // Calling elimination over child instance
135  List< const PRMInstance< GUM_SCALAR >* > my_list;
136 
137  for (const auto attr: attr_set) {
138  try {
139  for (auto iter = i->getRefAttr(attr).begin();
140  iter != i->getRefAttr(attr).end();
141  ++iter)
142  if ((!ignore.exists(iter->first)) && (bb__.exists(iter->first)))
144  iter->first,
145  pool,
146  trash,
147  my_list,
148  ignore);
149  } catch (NotFound&) {
150  // Ok
151  }
152  }
153 
154  // Eliminating all nodes in current instance
155  if (this->hasEvidence(i)) {
157  } else {
159 
160  for (const auto agg: i->type().aggregates())
161  if (bb__.requisiteNodes(i).exists(agg->id()))
163 
164  try {
167 
168  for (auto node: getElimOrder__(i->type())) {
169  const auto& var = bn.variable(node);
171  }
172 
174  } catch (NotFound&) {
175  // Raised if there is no inner nodes to eliminate
176  }
177  }
178 
179  // Calling elimination over child's parents
180  while (!my_list.empty()) {
181  if (checkElimOrder__(i, my_list.front())) {
182  if ((!ignore.exists(my_list.front())) && (bb__.exists(my_list.front())))
184  my_list.front(),
185  pool,
186  trash,
187  my_list,
188  ignore);
189  } else if (bb__.exists(my_list.front())) {
191  }
192 
193  my_list.popFront();
194  }
195 
196  // Adding parents instance to elim_list
197  for (const auto chain: sc_set)
198  for (const auto parent: i->getInstances(chain))
199  if ((!ignore.exists(parent)) && bb__.exists(parent) && (parent != from))
201  }
202 
203  template < typename GUM_SCALAR >
205  const PRMInstance< GUM_SCALAR >* i,
206  BucketSet& pool,
207  BucketSet& trash,
208  List< const PRMInstance< GUM_SCALAR >* >& elim_list,
209  Set< const PRMInstance< GUM_SCALAR >* >& ignore) {
210  ignore.insert(i);
211  // Extracting required attributes and slotchains
213  Set< NodeId >& sc_set = getSCSet__(i);
214 
215  // Downward elimination
216  for (const auto attr: attr_set) {
217  try {
218  for (auto iter = i->getRefAttr(attr).begin();
219  iter != i->getRefAttr(attr).end();
220  ++iter)
221  if ((!ignore.exists(iter->first)) && (bb__.exists(iter->first)))
223  iter->first,
224  pool,
225  trash,
226  elim_list,
227  ignore);
228  } catch (NotFound&) {
229  // Ok
230  }
231  }
232 
233  // Eliminating all nodes in i instance
234  if (this->hasEvidence(i)) {
236  } else {
238 
239  for (const auto agg: i->type().aggregates())
240  if (bb__.requisiteNodes(i).exists(agg->id()))
242 
243  try {
246 
247  for (auto node: getElimOrder__(i->type())) {
248  const auto& var = bn.variable(node);
250  }
252  } catch (NotFound&) {
253  // Raised if there is no inner nodes to eliminate
254  }
255  }
256 
257  // Eliminating instance in elim_list
258  List< const PRMInstance< GUM_SCALAR >* > tmp_list;
259 
260  while (!elim_list.empty()) {
261  if (checkElimOrder__(i, elim_list.front())) {
262  if ((!ignore.exists(elim_list.front()))
263  && (bb__.exists(elim_list.front())))
265  elim_list.front(),
266  pool,
267  trash,
268  elim_list,
269  ignore);
270  } else if (bb__.exists(elim_list.front())) {
272  }
273 
275  }
276 
277  // Upward elimination
278  for (const auto chain: sc_set)
279  for (const auto parent: i->getInstances(chain))
280  if ((!ignore.exists(parent)) && (bb__.exists(parent)))
282  }
283 
284  template < typename GUM_SCALAR >
286  const PRMInstance< GUM_SCALAR >* i,
287  BucketSet& pool,
288  BucketSet& trash) {
289  // Adding required evidences
290  for (const auto& elt: this->evidence(i))
292  pool.insert(const_cast< Potential< GUM_SCALAR >* >(elt.second));
293 
294  // Adding potentials and eliminating the remaining nodes
295  for (const auto& a: *i)
297  pool.insert(&(const_cast< Potential< GUM_SCALAR >& >(a.second->cpf())));
298 
302 
303  for (auto var = full_elim_order.begin(); var != full_elim_order.end(); ++var)
304  eliminateNode(&(i->get(*var).type().variable()), pool, trash);
305  }
306 
307  template < typename GUM_SCALAR >
308  void
310  BucketSet& pool,
311  BucketSet& trash) {
312  BucketSet* lifted_pool = nullptr;
313 
314  try {
316  } catch (NotFound&) {
319  }
320 
321  for (const auto lifted_pot: *lifted_pool) {
323  pool.insert(pot);
324  trash.insert(pot);
325  }
326  }
327 
328  template < typename GUM_SCALAR >
330  BucketSet& trash) {
331  PRMClass< GUM_SCALAR >& c = const_cast< PRMClass< GUM_SCALAR >& >(i->type());
334 
335  for (const auto node: bb__.requisiteNodes(i))
338  const_cast< Potential< GUM_SCALAR >* >(&(c.get(node).cpf())));
339 
341 
342  for (const auto& elt: *i) {
343  if (bb__.requisiteNodes(*i).exists(elt.first)) {
345  if (c.isOutputNode(c.get(elt.first)))
347  else if (!outers.exists(elt.first))
349  } else if (PRMClassElement< GUM_SCALAR >::isAggregate(
350  c.get(elt.first))) {
352 
353  // We need to put in the output_elim_order aggregator's parents
354  // which are
355  // innner nodes
356  for (const auto par: c.containerDag().parents(elt.first))
358  && i->type().isInnerNode(i->type().get(par))
359  && bb__.requisiteNodes(i).exists(par)) {
360  inners.erase(par);
361  outers.insert(par);
362  }
363  }
364  } else {
366  }
367  }
368 
369  // Now we proceed with the elimination of inner attributes
372 
374 
376 
378 
379  GUM_ASSERT(inners.size() || outers.size());
381  &(bn.modalities()),
383 
384  for (size_t idx = 0; idx < inners.size(); ++idx)
386  *lifted_pool,
387  trash);
388 
389  // If there is not only inner and input Attributes
390  if (outers.size()) {
392  &c,
394  t.eliminationOrder().end()));
395  }
396  }
397 
398  template < typename GUM_SCALAR >
402  std::list< NodeId > l;
403 
404  for (const auto node: cdg.dag().nodes()) {
405  if (cdg.dag().parents(node).empty()) { l.push_back(node); }
406  }
407 
409 
410  while (!l.empty()) {
412 
415  }
416 
417  for (const auto child: cdg.dag().children(l.front())) {
419  }
420 
421  l.pop_front();
422  }
423 
425  for (auto c: class_elim_order) {
426  std::string name = c->name();
427  auto pos = name.find_first_of("<");
428  if (pos != std::string::npos) { name = name.substr(0, pos); }
429  try {
431  } catch (DuplicateElement&) {}
432  }
433  }
434 
435  template < typename GUM_SCALAR >
437  Potential< GUM_SCALAR >& m) {
438  const PRMInstance< GUM_SCALAR >* i = chain.first;
439  const PRMAttribute< GUM_SCALAR >* elt = chain.second;
441  bb__.compute(i, elt->id());
443 
444  std::vector< const Potential< GUM_SCALAR >* > result;
445  for (auto pot: pool) {
446  if (pot->contains(*(m.variablesSequence().atPos(0))))
448  }
449 
450  while (result.size() > 1) {
451  const auto& p1 = *(result.back());
452  result.pop_back();
453  const auto& p2 = *(result.back());
454  result.pop_back();
455  auto mult = new Potential< GUM_SCALAR >(p1 * p2);
457  trash.insert(mult);
458  }
459 
460  m = *(result.back());
461  m.normalize();
462 
463  GUM_ASSERT(m.nbrDim() == (Size)1);
464 
465  // cleaning up the mess
466  for (const auto pot: trash)
467  delete pot;
468 
469  for (const auto& elt: lifted_pools__)
470  delete elt.second;
471 
473 
474  for (const auto& elt: req_set__) {
475  delete elt.second.first;
476  delete elt.second.second;
477  }
478 
479  req_set__.clear();
480 
481  for (const auto elt: elim_orders__)
482  delete elt.second;
483 
485  }
486 
487  template < typename GUM_SCALAR >
488  void SVED< GUM_SCALAR >::joint_(const std::vector< Chain >& queries,
489  Potential< GUM_SCALAR >& j) {
490  GUM_ERROR(FatalError, "Not implemented.");
491  }
492 
493  template < typename GUM_SCALAR >
495  Set< NodeId >* attr_set = new Set< NodeId >();
496  Set< NodeId >* sc_set = new Set< NodeId >();
497 
498  for (const auto node: bb__.requisiteNodes(i)) {
499  switch (i->type().get(node).elt_type()) {
502  attr_set->insert(node);
503  break;
504  }
505 
507  sc_set->insert(node);
508  break;
509  }
510 
511  default: {
513  "There should not be elements other"
514  " than PRMAttribute<GUM_SCALAR> and SlotChain.");
515  }
516  }
517  }
518 
520  &(bb__.requisiteNodes(i)),
521  std::pair< Set< NodeId >*, Set< NodeId >* >(attr_set, sc_set));
522  }
523 
524  template < typename GUM_SCALAR >
526  const PRMSystem< GUM_SCALAR >& model) :
528  class_elim_order__(0), bb__(*this) {
530  }
531 
532 
533  template < typename GUM_SCALAR >
534  INLINE void
536  BucketSet& pool) {
537  for (const auto& elt: this->evidence(i))
538  pool.insert(const_cast< Potential< GUM_SCALAR >* >(elt.second));
539  }
540 
541  template < typename GUM_SCALAR >
542  INLINE std::vector< NodeId >&
544  return *(elim_orders__[&c]);
545  }
546 
547  template < typename GUM_SCALAR >
549  auto pos = s.find_first_of("<");
550  if (pos != std::string::npos) { return s.substr(0, pos); }
551  return s;
552  }
553 
554  template < typename GUM_SCALAR >
556  const PRMInstance< GUM_SCALAR >* first,
557  const PRMInstance< GUM_SCALAR >* second) {
558  if (class_elim_order__ == 0) { initElimOrder__(); }
559 
560  auto first_name = trim__(first->type().name());
561  auto second_name = trim__(second->type().name());
564  }
565 
566  template < typename GUM_SCALAR >
568  const PRMInstance< GUM_SCALAR >* i,
569  const PRMAggregate< GUM_SCALAR >* agg) {
570  return &(
571  const_cast< Potential< GUM_SCALAR >& >(i->get(agg->safeName()).cpf()));
572  }
573 
574  template < typename GUM_SCALAR >
576  const typename SVED< GUM_SCALAR >::Chain& chain) {
577  // Do nothing
578  }
579 
580  template < typename GUM_SCALAR >
582  const typename SVED< GUM_SCALAR >::Chain& chain) {
583  // Do nothing
584  }
585 
586  template < typename GUM_SCALAR >
587  INLINE Set< NodeId >&
589  try {
590  return *(req_set__[&(bb__.requisiteNodes(i))].first);
591  } catch (NotFound&) {
592  initReqSets__(i);
593  return *(req_set__[&(bb__.requisiteNodes(i))].first);
594  }
595  }
596 
597  template < typename GUM_SCALAR >
598  INLINE Set< NodeId >&
600  try {
601  return *(req_set__[&(bb__.requisiteNodes(i))].second);
602  } catch (NotFound&) {
603  initReqSets__(i);
604  return *(req_set__[&(bb__.requisiteNodes(i))].second);
605  }
606  }
607 
608  template < typename GUM_SCALAR >
610  const PRMInstance< GUM_SCALAR >* i,
611  List< const PRMInstance< GUM_SCALAR >* >& elim_list,
612  List< const PRMInstance< GUM_SCALAR >* >& reduced_list,
613  Set< const PRMInstance< GUM_SCALAR >* >& ignore,
614  BucketSet& pool,
615  BucketSet& trash) {
616  while (!elim_list.empty()) {
617  if (checkElimOrder__(i, elim_list.front())) {
618  if ((!ignore.exists(elim_list.front()))
619  && (bb__.exists(elim_list.front()))) {
621  elim_list.front(),
622  pool,
623  trash,
624  elim_list,
625  ignore);
626  }
627  } else if (bb__.exists(elim_list.front())) {
629  }
630 
632  }
633  }
634 
635  template < typename GUM_SCALAR >
637  return "SVED";
638  }
639 
640  } /* namespace prm */
641 } /* namespace gum */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669
ParamScopeData(const std::string &s, const PRMReferenceSlot< GUM_SCALAR > &ref, Idx d)