aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
structuredInference_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 StructuredInference.
25  *
26  * @author Lionel TORTI and Pierre-Henri WUILLEMIN(@LIP6)
27  */
28 
29 #include <agrum/PRM/inference/structuredInference.h>
30 
31 namespace gum {
32  namespace prm {
33 
34  template < typename GUM_SCALAR >
35  StructuredInference< GUM_SCALAR >::StructuredInference(
36  const PRM< GUM_SCALAR >& prm,
37  const PRMSystem< GUM_SCALAR >& system,
38  gspan::SearchStrategy< GUM_SCALAR >* strategy) :
39  PRMInference< GUM_SCALAR >(prm, system),
40  _gspan_(0), _pdata_(0), _mining_(false), _dot_(".") {
41  GUM_CONSTRUCTOR(StructuredInference);
42  _gspan_ = new GSpan< GUM_SCALAR >(prm, system, strategy);
43  triang_time = 0.0;
44  mining_time = 0.0;
45  pattern_time = 0.0;
46  inner_time = 0.0;
47  obs_time = 0.0;
48  full_time = 0.0;
49  }
50 
51  template < typename GUM_SCALAR >
55  _gspan_(0), _pdata_(0), _mining_(source._mining_), _found_query_(false), _dot_(".") {
57  _gspan_ = new GSpan< GUM_SCALAR >(*(this->prm_), *(this->sys_));
58  }
59 
60  template < typename GUM_SCALAR >
63  delete this->_gspan_;
64 
65  for (const auto& elt: _elim_map_)
66  delete elt.second;
67 
68  for (const auto& elt: _cdata_map_)
69  delete elt.second;
70 
71  for (const auto elt: _trash_)
72  delete (elt);
73 
74  for (const auto& elt: _outputs_)
75  delete elt.second;
76 
77  if (_pdata_) delete _pdata_;
78  }
79 
80  template < typename GUM_SCALAR >
83  this->prm_ = source.prm_;
84  this->sys_ = source.sys_;
85 
86  if (this->_gspan_) delete this->_gspan_;
87 
88  this->_gspan_ = new GSpan< GUM_SCALAR >(*(this->prm_), *(this->sys_));
89  return *this;
90  }
91 
92  template < typename GUM_SCALAR >
94  const typename PRMInference< GUM_SCALAR >::Chain& chain) {}
95 
96  template < typename GUM_SCALAR >
98  const typename PRMInference< GUM_SCALAR >::Chain& chain) {}
99 
100  template < typename GUM_SCALAR >
102  const typename PRMInference< GUM_SCALAR >::Chain& chain,
103  Potential< GUM_SCALAR >& m) {
104  timer.reset();
105  _found_query_ = false;
106  _query_ = chain;
108 
109  if (!this->hasEvidence() && (chain.second->cpf().nbrDim() == 1)) {
110  Instantiation i(m);
111 
112  for (i.setFirst(); !i.end(); i.inc())
113  m.set(i, chain.second->cpf().get(i));
114 
115  return;
116  } else if (this->hasEvidence(chain)) {
117  Instantiation i(m);
118  const Potential< GUM_SCALAR >* e = 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 
127  Set< const Potential< GUM_SCALAR >* > pots;
128 
129  if (data.pool.size() > 1) {
130  for (const auto pot: data.pool)
132 
133  if (pots.size() == 1) {
134  Potential< GUM_SCALAR >* pot = const_cast< Potential< GUM_SCALAR >* >(*(pots.begin()));
137  Instantiation i(*pot), j(m);
138 
139  for (i.setFirst(), j.setFirst(); !i.end(); i.inc(), j.inc())
140  m.set(j, pot->get(i));
141  } else {
144  Instantiation i(m), j(*tmp);
145 
146  for (i.setFirst(), j.setFirst(); !i.end(); i.inc(), j.inc())
147  m.set(i, tmp->get(j));
148 
149  delete tmp;
150  }
151  } else {
152  Potential< GUM_SCALAR >* pot = *(data.pool.begin());
155  Instantiation i(*pot), j(m);
156 
157  for (i.setFirst(), j.setFirst(); !i.end(); i.inc(), j.inc())
158  m.set(j, pot->get(i));
159  }
160 
161  m.normalize();
162 
163  if (_pdata_) {
164  delete _pdata_;
165  _pdata_ = 0;
166  }
167 
168  full_time = timer.step();
169  }
170 
171  template < typename GUM_SCALAR >
173  const std::vector< typename PRMInference< GUM_SCALAR >::Chain >& queries,
174  Potential< GUM_SCALAR >& j) {
175  GUM_ERROR(FatalError, "not implemented")
176  }
177 
178  template < typename GUM_SCALAR >
180  std::stringstream s;
181  s << "Triangulation time: " << triang_time << std::endl;
182  s << "Pattern mining time: " << mining_time << std::endl;
183  s << "Pattern elimination time: " << pattern_time << std::endl;
184  s << "Inner node elimination time: " << inner_time << std::endl;
185  s << "Observed node elimination time: " << obs_time << std::endl;
186  s << "Full inference time: " << full_time << std::endl;
187  s << "#patterns: " << _gspan_->patterns().size() << std::endl;
188  Size count = 0;
189  typedef std::vector< gspan::Pattern* >::const_iterator Iter;
190 
191  for (Iter p = _gspan_->patterns().begin(); p != _gspan_->patterns().end(); ++p) {
192  if (_gspan_->matches(**p).size()) {
193  s << "Pattern n°" << count++ << " match count: " << _gspan_->matches(**p).size()
194  << std::endl;
195  s << "Pattern n°" << count++ << " instance count: " << (**p).size() << std::endl;
196  }
197  }
198 
199  return s.str();
200  }
201 
202  template < typename GUM_SCALAR >
204  typename StructuredInference< GUM_SCALAR >::RGData& data) {
205  // Launch the pattern mining
206  plopTimer.reset();
207 
209 
211  // Reducing each used pattern
212  plopTimer.reset();
213  typedef std::vector< gspan::Pattern* >::const_iterator Iter;
214 
215  for (Iter p = _gspan_->patterns().begin(); p != _gspan_->patterns().end(); ++p)
216  if (_gspan_->matches(**p).size()) _reducePattern_(*p);
217 
219  // reducing instance not already reduced in a pattern
221  // Adding edges using the pools
223  // Placing the query where it belongs
225  data.outputs().erase(id);
226  data.queries().insert(id);
227  // Triangulating, then eliminating
229  const std::vector< NodeId >& elim_order = t.eliminationOrder();
230 
231  for (size_t i = 0; i < data.outputs().size(); ++i)
233  }
234 
235  template < typename GUM_SCALAR >
237  Set< Potential< GUM_SCALAR >* > pool;
242  const std::vector< NodeId >& elim_order = t.eliminationOrder();
243 
244  for (size_t i = 0; i < data.inners().size(); ++i)
245  if (!data.barren.exists(elim_order[i]))
247 
250 
251  for (const auto elt: **iter)
253 
254  if (data.obs().size())
256  else
258 
259  ++iter;
260 
261  if (data.obs().size()) {
262  for (; iter != data.matches.end(); ++iter) {
263  try {
265  } catch (OperationNotAllowed&) { fake_patterns.insert(*iter); }
266  }
267  } else {
268  for (; iter != data.matches.end(); ++iter) {
269  try {
271  } catch (OperationNotAllowed&) { fake_patterns.insert(*iter); }
272  }
273  }
274 
275  for (const auto pat: fake_patterns) {
276  for (const auto elt: *pat)
278 
280  }
281 
282  obs_time += plopTimer.step();
283 
284  if (data.queries().size())
285  for (const auto m: data.matches)
286  if (!(m->exists(const_cast< PRMInstance< GUM_SCALAR >* >(_query_.first))))
289  *(_elim_map_[m]),
290  _trash_);
291  }
292 
293  template < typename GUM_SCALAR >
296  const Sequence< PRMInstance< GUM_SCALAR >* >& match,
299  NodeId id,
300  std::pair< Idx, std::string >& v) {
301  if ((*inst).hasRefAttr((*inst).get(v.second).id())) {
303  = inst->getRefAttr(inst->get(v.second).id());
304 
305  for (auto r = refs.begin(); r != refs.end(); ++r) {
306  if (!match.exists(r->first)) {
307  data.outputs().insert(id);
308  break;
309  }
310  }
311  }
312 
313  if (!(data.outputs().size() && (data.outputs().exists(id)))) {
314  for (const auto m: data.matches) {
315  if (this->hasEvidence(std::make_pair((*m)[v.first], &((*m)[v.first]->get(v.second))))) {
316  GUM_ASSERT(inst->type().name() == (*m)[v.first]->type().name());
318  data.obs().insert(id);
319  break;
320  }
321  }
322 
323  if (!(data.obs().size() && (data.obs().exists(id)))) data.inners().insert(id);
324  }
325  }
326 
327  template < typename GUM_SCALAR >
330  Set< Potential< GUM_SCALAR >* >& pool,
331  const Sequence< PRMInstance< GUM_SCALAR >* >& match) {
332  std::pair< Idx, std::string > v;
333  Potential< GUM_SCALAR >* pot = 0;
334 
335  for (const auto inst: match) {
336  for (const auto& elt: *inst) {
337  NodeId id = data.graph.addNode();
339  data.map.insert(id, v);
342  data.vars.insert(id, &(elt.second->type().variable()));
343  pool.insert(const_cast< Potential< GUM_SCALAR >* >(&(elt.second->cpf())));
344  pot = &(const_cast< Potential< GUM_SCALAR >& >(inst->get(v.second).cpf()));
345 
346  for (const auto var: pot->variablesSequence()) {
347  try {
349  } catch (DuplicateElement&) {
350  } catch (NotFound&) {}
351  }
352 
354 
355  if (data.inners().exists(id)
356  && (inst->type().containerDag().children(elt.second->id()).size() == 0)
358  data.barren.insert(id);
359  }
360  }
361 
362  if (!_found_query_) {
363  for (const auto mat: data.matches) {
364  if (mat->exists(const_cast< PRMInstance< GUM_SCALAR >* >(_query_.first))) {
365  Idx pos = mat->pos(const_cast< PRMInstance< GUM_SCALAR >* >(_query_.first));
368  NodeId id = data.vars.first(&var);
369  data.barren.erase(id);
370  data.inners().erase(id);
371  data.obs().erase(id);
372  data.outputs().erase(id);
373  data.queries().insert(id);
374  _found_query_ = true;
376  break;
377  }
378  }
379  }
380  }
381 
382  template < typename GUM_SCALAR >
385  std::pair< Idx, std::string > attr) {
386  for (const auto mat: data.matches)
388  return false;
389 
390  return true;
391  }
392 
393  template < typename GUM_SCALAR >
396  Set< Potential< GUM_SCALAR >* >& pool) {
398 
399  for (const auto node: data.barren) {
400  for (const auto pot: pool)
401  if (pot->contains(*data.vars.second(node))) {
402  pool.erase(pot);
403  break;
404  }
405 
406  for (const auto nei: data.graph.neighbours(node))
407  if (data.inners().exists(nei)) {
408  try {
410  } catch (DuplicateElement&) {}
411  }
412  }
413 
414  NodeId node;
415  Potential< GUM_SCALAR >* my_pot = nullptr;
416  short count = 0;
417 
418  while (candidates.size()) {
419  node = candidates.back();
421  count = 0;
422 
423  for (const auto pot: pool) {
424  if (pot->contains(*data.vars.second(node))) {
425  ++count;
426  my_pot = pot;
427  }
428  }
429 
430  if (count == 1) {
431  pool.erase(my_pot);
433 
434  for (const auto nei: data.graph.neighbours(node)) {
435  if (data.inners().exists(nei)) {
436  try {
438  } catch (DuplicateElement&) {}
439  }
440  }
441  }
442  }
443  }
444 
445  template < typename GUM_SCALAR >
446  Set< Potential< GUM_SCALAR >* >*
449  const Set< Potential< GUM_SCALAR >* >& pool,
450  const Sequence< PRMInstance< GUM_SCALAR >* >& match,
451  const std::vector< NodeId >& elim_order) {
452  Set< Potential< GUM_SCALAR >* >* my_pool = new Set< Potential< GUM_SCALAR >* >(pool);
453  std::pair< Idx, std::string > target;
454  size_t end = data.inners().size() + data.obs().size();
455 
456  for (size_t idx = data.inners().size(); idx < end; ++idx) {
459  *my_pool,
460  _trash_);
461  }
462 
463  return my_pool;
464  }
465 
466  template < typename GUM_SCALAR >
469  const Set< Potential< GUM_SCALAR >* >& pool,
470  const Sequence< PRMInstance< GUM_SCALAR >* >& match,
471  const std::vector< NodeId >& elim_order) {
473  std::pair< Idx, std::string > target;
474  size_t end = data.inners().size() + data.obs().size();
475 
476  for (size_t idx = data.inners().size(); idx < end; ++idx) {
479  *my_pool,
480  _trash_);
481  }
482 
483  return my_pool;
484  }
485 
486  template < typename GUM_SCALAR >
489  const Set< Potential< GUM_SCALAR >* >& pool,
490  const Sequence< PRMInstance< GUM_SCALAR >* >& match) {
491 #ifdef DEBUG
492 
494  iter != data.matches.end();
495  ++iter) {
496  GUM_ASSERT((**iter).size() == match.size());
497 
498  for (Size idx = 0; idx < match.size(); ++idx) {
499  GUM_ASSERT((**iter).atPos(idx)->type() == match.atPos(idx)->type());
500  }
501  }
502 
503 #endif
504  Set< Potential< GUM_SCALAR >* >* my_pool = new Set< Potential< GUM_SCALAR >* >();
505  std::pair< Idx, std::string > target;
507  const Sequence< PRMInstance< GUM_SCALAR >* >& source = **(data.matches.begin());
508 
509  for (Size idx = 0; idx < match.size(); ++idx) {
511  const auto& chains = source[idx]->type().slotChains();
512 
513  for (const auto sc: chains) {
514 #ifdef DEBUG
515  GUM_ASSERT(!(sc->isMultiple()));
516 #endif
517 
518  try {
519  bij.insert(&(source[idx]
520  ->getInstance(sc->id())
521  .get(sc->lastElt().safeName())
522  .type()
523  .variable()),
524  &(match[idx]
525  ->getInstance(sc->id())
526  .get(sc->lastElt().safeName())
527  .type()
528  .variable()));
529  } catch (DuplicateElement&) {
530  try {
531  if (bij.first(&(match[idx]
532  ->getInstance(sc->id())
533  .get(sc->lastElt().safeName())
534  .type()
535  .variable()))
536  != &(source[idx]
537  ->getInstance(sc->id())
538  .get(sc->lastElt().safeName())
539  .type()
540  .variable())) {
541  delete my_pool;
542  GUM_ERROR(OperationNotAllowed, "fake pattern")
543  }
544  } catch (NotFound&) {
545  delete my_pool;
546  GUM_ERROR(OperationNotAllowed, "fake pattern")
547  }
548  }
549  }
550  }
551 
552  for (const auto p: pool) {
553  for (const auto v: p->variablesSequence()) {
554  try {
555  target = data.map[data.vars.first(v)];
557  } catch (NotFound&) { GUM_ASSERT(bij.existsFirst(v)); } catch (DuplicateElement&) {
558  }
559  }
560 
561  try {
563  } catch (Exception&) {
564  for (const auto pot: *my_pool)
565  delete pot;
566 
567  delete my_pool;
568  GUM_ERROR(OperationNotAllowed, "fake pattern")
569  }
570  }
571 
572  return my_pool;
573  }
574 
575  template < typename GUM_SCALAR >
579  Potential< GUM_SCALAR >* pot = nullptr;
580  PRMInstance< GUM_SCALAR >* inst = nullptr;
581 
582  for (const auto& elt: *this->sys_) {
583  inst = elt.second;
584 
586  // Checking if its not an empty class
587  if (inst->size()) {
588  Set< Potential< GUM_SCALAR >* > pool;
589 
590  try {
591  data = _cdata_map_[&(inst->type())];
592  } catch (NotFound&) {
594  _cdata_map_.insert(&(inst->type()), data);
595  }
596 
598  // Filling up the partial ordering
600 
602 
603  if (data->aggregators().size())
604  for (const auto agg: data->aggregators())
606 
608 
609  if (_query_.first == inst) {
610  // First case, the instance contains the query
612 
613  if (partial_order[0].empty()) partial_order.erase(0);
614 
615  if (partial_order.size() > 1) {
617 
618  if (partial_order[1].empty()) partial_order.erase(1);
619  }
620 
624 
625  // Adding the potentials
626  for (auto attr = inst->begin(); attr != inst->end(); ++attr)
627  pool.insert(&(const_cast< Potential< GUM_SCALAR >& >((*(attr.val())).cpf())));
628 
629  // Adding evidences if any
630  if (this->hasEvidence(inst))
631  for (const auto& elt: this->evidence(inst))
632  pool.insert(const_cast< Potential< GUM_SCALAR >* >(elt.second));
633 
635  const std::vector< NodeId >& v = t.eliminationOrder();
636 
637  if (partial_order.size() > 1)
638  for (size_t idx = 0; idx < partial_order[0].size(); ++idx)
640  } else if (this->hasEvidence(inst)) {
641  // Second case, the instance has evidences
642  // Adding the potentials
643  for (const auto elt: *inst)
644  pool.insert(&const_cast< Potential< GUM_SCALAR >& >(elt.second->cpf()));
645 
646  // Adding evidences
647  for (const auto& elt: this->evidence(inst))
648  pool.insert(const_cast< Potential< GUM_SCALAR >* >(elt.second));
649 
651 
652  for (size_t idx = 0; idx < partial_order[0].size(); ++idx)
654  pool,
655  _trash_);
656  } else {
657  // Last cast, the instance neither contains evidences nor
658  // instances
659  // We translate the class level potentials into the instance ones
660  // and
661  // proceed with elimination
662  for (const auto srcPot: data->pool) {
664  pool.insert(pot);
665  _trash_.insert(pot);
666  }
667 
668  for (const auto agg: data->c.aggregates())
669  pool.insert(&(const_cast< Potential< GUM_SCALAR >& >(inst->get(agg->id()).cpf())));
670 
671  // We eliminate inner aggregators with their parents if necessary
672  // (see
673  // CData constructor)
674  Size size = data->inners().size() + data->aggregators().size();
675 
676  for (size_t idx = data->inners().size(); idx < size; ++idx)
678  pool,
679  _trash_);
680  }
681 
682  for (const auto pot: pool)
684  }
685  }
686  }
687  }
688 
689  template < typename GUM_SCALAR >
691  typename StructuredInference< GUM_SCALAR >::RGData& data) {
692  // We first add edges between variables already in pool (i.e. those of the
693  // reduced instances)
694  NodeId id_1, id_2;
695 
696  for (const auto pot: data.pool) {
697  const Sequence< const DiscreteVariable* >& vars = pot->variablesSequence();
698 
699  for (Size var_1 = 0; var_1 < vars.size(); ++var_1) {
702  } else {
706  data.outputs().insert(id_1);
707  }
708 
709  for (Size var_2 = var_1 + 1; var_2 < vars.size(); ++var_2) {
712  } else {
716  data.outputs().insert(id_2);
717  }
718 
719  try {
721  } catch (DuplicateElement&) {}
722  }
723  }
724  }
725 
726  // Adding potentials obtained from reduced patterns
727  for (const auto& elt: _elim_map_) {
728  // We add edges between variables in the same reduced patterns
729  for (const auto pot: *elt.second) {
730  data.pool.insert(pot);
731  const Sequence< const DiscreteVariable* >& vars = pot->variablesSequence();
732 
733  for (Size var_1 = 0; var_1 < vars.size(); ++var_1) {
736  } else {
740  data.outputs().insert(id_1);
741  }
742 
743  for (Size var_2 = var_1 + 1; var_2 < vars.size(); ++var_2) {
746  } else {
750  data.outputs().insert(id_2);
751  }
752 
753  try {
755  } catch (DuplicateElement&) {}
756  }
757  }
758  }
759  }
760  }
761 
762  template < typename GUM_SCALAR >
767  }
768 
769  template < typename GUM_SCALAR >
771  const gspan::Pattern& p,
772  typename GSpan< GUM_SCALAR >::MatchedInstances& m) :
773  pattern(p),
774  matches(m), _real_order_(0) {
776 
777  for (int i = 0; i < 4; ++i)
779  }
780 
781  template < typename GUM_SCALAR >
783  const typename StructuredInference< GUM_SCALAR >::PData& source) :
788  }
789 
790  template < typename GUM_SCALAR >
792  if (!_real_order_) {
793  _real_order_ = new List< NodeSet >();
794 
795  for (const auto set: _partial_order_)
796  if (set.size() > 0) _real_order_->insert(set);
797  }
798 
799  return _real_order_;
800  }
801 
802  template < typename GUM_SCALAR >
804  c(a_class), _elim_order_(0) {
806 
807  // First step we add Attributes and Aggregators
808  for (const auto node: c.containerDag().nodes()) {
809  switch (c.get(node).elt_type()) {
811  pool.insert(&(const_cast< Potential< GUM_SCALAR >& >(c.get(node).cpf())));
812  // break omited : We want to execute the next block
813  // for attributes
814  }
815 
819  break;
820  }
821 
822  default: { /* do nothing */
823  }
824  }
825  }
826 
827  // Second, we add edges, moralise the graph and build the partial ordering
828  for (const auto node: moral_graph.nodes()) {
829  const auto& parents = c.containerDag().parents(node);
830 
831  // Adding edges and marrying parents
832  for (auto tail = parents.begin(); tail != parents.end(); ++tail) {
837  ++marry;
838 
839  while (marry != parents.end()) {
843 
844  ++marry;
845  }
846  }
847  }
848 
849  // Adding nodes to the partial ordering
850  switch (c.get(node).elt_type()) {
852  if (c.isOutputNode(c.get(node)))
853  outputs().insert(node);
854  else
856 
857  // If the aggregators is not an output and have parents which are
858  // not outputs, we must eliminate the parents after adding the
859  // aggregator's CPT
860  for (const auto par: c.containerDag().parents(node)) {
861  const auto& prnt = c.get(par);
862 
863  if ((!c.isOutputNode(prnt))
866  inners().erase(prnt.id());
867  aggregators().insert(prnt.id());
868  }
869  }
870 
871  break;
872  }
873 
875  pool.insert(const_cast< Potential< GUM_SCALAR >* >(&(c.get(node).cpf())));
876 
877  if (c.isOutputNode(c.get(node)))
878  outputs().insert(node);
879  else if (!aggregators().exists(node))
880  inners().insert(node);
881 
882  break;
883  }
884 
885  default: { /* Do nothing */
886  }
887  }
888  }
889 
890  if (inners().size()) partial_order.insert(inners());
891 
893 
895 
899 
900  for (size_t i = 0; i < inners().size(); ++i)
902  }
903 
904  template < typename GUM_SCALAR >
907 
908  for (const auto pot: _trash_)
909  delete pot;
910  }
911 
912  template < typename GUM_SCALAR >
914  const PRMInstance< GUM_SCALAR >* i = (this->sys_->begin()).val();
915  _query_ = std::make_pair(i, i->begin().val());
916  _found_query_ = false;
919  }
920 
921  template < typename GUM_SCALAR >
923  _mining_ = b;
924  }
925 
926  template < typename GUM_SCALAR >
927  INLINE std::string
929  const PRMAttribute< GUM_SCALAR >* a) const {
930  return i->name() + _dot_ + a->safeName();
931  }
932 
933  template < typename GUM_SCALAR >
934  INLINE std::string
936  const PRMAttribute< GUM_SCALAR >& a) const {
937  return i->name() + _dot_ + a.safeName();
938  }
939 
940  template < typename GUM_SCALAR >
941  INLINE std::string
943  const PRMSlotChain< GUM_SCALAR >& a) const {
944  return i->name() + _dot_ + a.lastElt().safeName();
945  }
946 
947  template < typename GUM_SCALAR >
950  }
951 
952  template < typename GUM_SCALAR >
955  }
956 
957  template < typename GUM_SCALAR >
959  return "StructuredInference";
960  }
961 
962  template < typename GUM_SCALAR >
964  return *_gspan_;
965  }
966 
967  template < typename GUM_SCALAR >
969  return *_gspan_;
970  }
971 
972  template < typename GUM_SCALAR >
975  NodeId id,
976  Set< Potential< GUM_SCALAR >* >& pool) {
979  data.mod.erase(id);
983  data.map.erase(id);
987  data.inners().erase(id);
989  pool.erase(data.pots[id]);
991  data.pots.erase(id);
993  }
994 
995  } /* namespace prm */
996 } /* namespace gum */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643
ParamScopeData(const std::string &s, const PRMReferenceSlot< GUM_SCALAR > &ref, Idx d)