49#ifndef DOXYGEN_SHOULD_SKIP_THIS
58# define GUM_SSLI_TRACE_ON(x)
59# define GUM_SSLI_TENSOR_TRACE_ON(x)
63 template <
typename GUM_SCALAR >
67 GUM_CONSTRUCTOR(ShaferShenoyLIMIDInference);
71 template <
typename GUM_SCALAR >
72 ShaferShenoyLIMIDInference< GUM_SCALAR >::~ShaferShenoyLIMIDInference() {
73 GUM_DESTRUCTOR(ShaferShenoyLIMIDInference);
76 template <
typename GUM_SCALAR >
77 void ShaferShenoyLIMIDInference< GUM_SCALAR >::clear() {
78 GraphicalModelInference< GUM_SCALAR >::clear();
79 noForgettingOrder_.clear();
81 reducedJunctionTree_.clear();
82 solvabilityOrder_.clear();
84 unconditionalDecisions_.clear();
86 reversePartialOrder_.clear();
89 template <
typename GUM_SCALAR >
90 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onStateChanged_() {}
92 template <
typename GUM_SCALAR >
93 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onEvidenceAdded_(
const NodeId
id,
94 bool isHardEvidence) {
95 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
97 if (infdiag.isDecisionNode(
id)) {
102 template <
typename GUM_SCALAR >
103 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onEvidenceErased_(
const NodeId
id,
104 bool isHardEvidence) {}
106 template <
typename GUM_SCALAR >
107 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onAllEvidenceErased_(
bool contains_hard_evidence) {
110 template <
typename GUM_SCALAR >
111 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onEvidenceChanged_(
const NodeId
id,
112 bool hasChangedSoftHard) {}
114 template <
typename GUM_SCALAR >
115 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onModelChanged_(
const GraphicalModel* model) {
119 template <
typename GUM_SCALAR >
120 void ShaferShenoyLIMIDInference< GUM_SCALAR >::updateOutdatedStructure_() {
124 template <
typename GUM_SCALAR >
125 void ShaferShenoyLIMIDInference< GUM_SCALAR >::updateOutdatedTensors_() {}
127 template <
typename GUM_SCALAR >
128 void ShaferShenoyLIMIDInference< GUM_SCALAR >::makeInference_() {
129 if (!isSolvable()) {
GUM_ERROR(
FatalError,
"This LIMID/Influence Diagram is not solvable.") }
134 GUM_SSLI_TRACE_ON(
"\n\n")
136 initializingInference_(phi, psi);
139 const auto firstRootIndice = 0;
140 collectingMessage_(phi, psi, node_to_clique_[solvabilityOrder_[firstRootIndice]]);
141 deciding_(phi, psi, solvabilityOrder_[firstRootIndice]);
143 for (Idx nextRootIndice = 1; nextRootIndice < solvabilityOrder_.size(); nextRootIndice++) {
144 if (node_to_clique_[solvabilityOrder_[nextRootIndice - 1]]
145 != node_to_clique_[solvabilityOrder_[nextRootIndice]]) {
146 collectingToFollowingRoot_(phi,
148 node_to_clique_[solvabilityOrder_[nextRootIndice - 1]],
149 node_to_clique_[solvabilityOrder_[nextRootIndice]]);
151 deciding_(phi, psi, solvabilityOrder_[nextRootIndice]);
155 distributingMessage_(phi,
157 node_to_clique_[solvabilityOrder_[solvabilityOrder_.size() - 1]]);
158 computingPosteriors_(phi, psi);
161 template <
typename GUM_SCALAR >
162 void ShaferShenoyLIMIDInference< GUM_SCALAR >::initializingInference_(PhiNodeProperty& phi,
163 PsiArcProperty& psi) {
164 const auto& jt = *junctionTree();
165 const auto& infdiag = this->influenceDiagram();
168 for (
const auto node: jt.nodes()) {
169 phi.insert(node, DecisionTensor< GUM_SCALAR >());
170 for (
const auto nei: jt.neighbours(node)) {
171 psi.insert(Arc(node, nei), DecisionTensor< GUM_SCALAR >());
174 for (
const auto n: jt.clique(node) * jt.clique(nei))
175 varsSeparator_.getWithDefault(Edge(node, nei), SetOfVars())
176 .insert(&(infdiag.variable(n)));
180 for (
const auto node: infdiag.nodes()) {
181 const auto clik = node_to_clique_[node];
182 if (this->hasEvidence(node)) {
183 auto q = *(this->evidence()[node]);
184 phi[clik].insertProba(q.normalize());
187 if (infdiag.isDecisionNode(node)) {
188 if (!this->hasEvidence(node)) {
189 auto p = (Tensor< GUM_SCALAR >() << infdiag.variable(node)).fillWith(1).normalize();
190 phi[clik].insertProba(p);
192 }
else if (infdiag.isChanceNode(node)) phi[clik].insertProba(infdiag.cpt(node));
193 else if (infdiag.isUtilityNode(node)) phi[clik].insertUtility(infdiag.utility(node));
198 template <
typename GUM_SCALAR >
199 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_creatingJunctionTree_() {
200 const auto& infdiag = this->influenceDiagram();
201 auto moral = reduced_.moralGraph();
205 NodeProperty< Size > modalities;
206 for (
const auto node: infdiag.nodes())
207 if (infdiag.isUtilityNode(node)) {
208 moral.eraseNode(node);
210 modalities.insert(node, infdiag.variable(node).domainSize());
212 DefaultTriangulation triangulation(&moral, &modalities);
213 reducedJunctionTree_ = triangulation.junctionTree();
214 _findingCliqueForEachNode_(triangulation);
217 template <
typename GUM_SCALAR >
218 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_findingCliqueForEachNode_(
219 DefaultTriangulation& triangulation) {
222 const auto& infdiag = this->influenceDiagram();
223 NodeId first_eliminated_node;
225 node_to_clique_.clear();
226 const std::vector< NodeId >& JT_elim_order = triangulation.eliminationOrder();
227 NodeProperty< Idx > elim_order(Size(JT_elim_order.size()));
228 for (Idx i = Idx(0), size = JT_elim_order.size(); i < size; ++i)
229 elim_order.insert(JT_elim_order[i], (
int)i);
230 for (
const auto node: reduced_.nodes()) {
231 if (infdiag.isUtilityNode(node)) {
234 first_eliminated_node = node;
235 elim_number = std::numeric_limits< NodeId >::max();
238 first_eliminated_node = node;
239 elim_number = elim_order[first_eliminated_node];
242 for (
const auto parent: reduced_.parents(node)) {
243 if (elim_order[parent] < elim_number) {
244 elim_number = elim_order[parent];
245 first_eliminated_node = parent;
253 node_to_clique_.insert(node, triangulation.createdJunctionTreeClique(first_eliminated_node));
257 template <
typename GUM_SCALAR >
258 std::pair< GUM_SCALAR, GUM_SCALAR > ShaferShenoyLIMIDInference< GUM_SCALAR >::MEU() {
261 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
263 GUM_SCALAR resmean = 0;
264 GUM_SCALAR resvar = 0;
265 for (auto node: infdiag.nodes()) {
266 if (infdiag.isUtilityNode(node)) {
267 auto p = meanVar(node);
272 return std::pair< GUM_SCALAR, GUM_SCALAR >(resmean, resvar);
275 template <
typename GUM_SCALAR >
277 ShaferShenoyLIMIDInference< GUM_SCALAR >::optimalDecision(NodeId decisionId) {
280 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
281 if (!infdiag.isDecisionNode(decisionId))
283 infdiag.variable(decisionId).name()
284 <<
"(" << decisionId <<
") is not a decision node.")
286 return strategies_[decisionId];
289 template < typename GUM_SCALAR >
290 bool ShaferShenoyLIMIDInference< GUM_SCALAR >::isSolvable()
const {
291 return (!solvabilityOrder_.empty());
294 template <
typename GUM_SCALAR >
295 void ShaferShenoyLIMIDInference< GUM_SCALAR >::createReduced_() {
298 reducedJunctionTree_.clear();
299 solvabilityOrder_.clear();
300 reversePartialOrder_.clear();
302 unconditionalDecisions_.clear();
304 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
309 for (
auto node: infdiag.nodes()) {
310 reduced_.addNodeWithId(node);
311 if (infdiag.isUtilityNode(node)) { utilities.insert(node); }
314 for (
const auto& arc: infdiag.arcs())
315 reduced_.addArc(arc.tail(), arc.head());
317 _completingNoForgettingAssumption_();
318 _creatingPartialOrder_(utilities);
319 _checkingSolvability_(utilities);
322 _creatingJunctionTree_();
325 this->setState_(GraphicalModelInference< GUM_SCALAR >::StateOfInference::OutdatedStructure);
328 template <
typename GUM_SCALAR >
329 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_completingNoForgettingAssumption_() {
331 if (hasNoForgettingAssumption()) {
332 auto last = *(noForgettingOrder_.begin());
333 for (
auto node: noForgettingOrder_)
338 if (!reduced_.existsArc(last, node)) { reduced_.addArc(last, node); }
339 for (
auto par: reduced_.parents(last)) {
340 if (!reduced_.existsArc(par, node)) reduced_.addArc(par, node);
347 template <
typename GUM_SCALAR >
348 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_checkingSolvability_(
const NodeSet& utilities) {
349 if (hasNoForgettingAssumption()) {
350 solvabilityOrder_ = noForgettingOrder_;
351 std::reverse(solvabilityOrder_.begin(), solvabilityOrder_.end());
355 solvabilityOrder_.clear();
356 for (
const auto& sen: reversePartialOrder()) {
358 while (!tobetested.empty()) {
359 bool foundOne =
false;
360 for (
const auto& node: tobetested) {
361 const auto us = utilities * reduced_.descendants(node);
363 for (
const auto dec: tobetested)
364 if (dec != node) decs += reduced_.family(dec);
365 if (reduced_.dSeparation(decs, us, reduced_.family(node))) {
366 solvabilityOrder_.push_back(node);
368 tobetested.erase(node);
373 solvabilityOrder_.clear();
380 template <
typename GUM_SCALAR >
381 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_reducingLIMID_() {
382 for (
const auto& sen: reversePartialOrder_) {
384 for (
auto p: nonRequisiteNodes_(n))
385 reduced_.eraseArc(Arc(p, n));
390 template <
typename GUM_SCALAR >
391 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_creatingPartialOrder_(
const NodeSet& utilities) {
392 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
393 NodeProperty< Size > level;
395 for (
const auto& node: utilities)
396 level.insert(node, 0);
400 reversePartialOrder_.clear();
401 reversePartialOrder_.resize(infdiag.size());
403 for (
auto node: infdiag.nodes()) {
404 if (infdiag.isUtilityNode(node))
continue;
405 if (reduced_.children(node).isSubsetOrEqual(utilities)) {
407 currents.insert(node);
408 level.insert(node, 0);
409 while (!currents.empty()) {
410 NodeId elt = *(currents.begin());
413 if (infdiag.isDecisionNode(elt)) reversePartialOrder_[level[elt]].insert(elt);
415 for (
auto parent: reduced_.parents(elt)) {
418 bool ok_to_add =
true;
419 for (
auto child: reduced_.children(parent)) {
420 if (!level.exists(child)) {
425 if (infdiag.isDecisionNode(child)) newl += 1;
426 if (lev < newl) lev = newl;
429 currents.insert(parent);
430 if (level.exists(parent)) {
431 if (level[parent] != lev)
433 "Trying to set level[" << parent <<
"] to level=" << lev
434 <<
" but already is " << level[parent]);
436 level.insert(parent, lev);
439 if (max_level < lev) max_level = lev;
446 for (
const auto& k: reversePartialOrder_) {
447 if (k.empty())
break;
450 reversePartialOrder_.
resize(levmax);
453 template <
typename GUM_SCALAR >
454 std::vector< NodeSet > ShaferShenoyLIMIDInference< GUM_SCALAR >::reversePartialOrder()
const {
455 return reversePartialOrder_;
458 template <
typename GUM_SCALAR >
459 bool ShaferShenoyLIMIDInference< GUM_SCALAR >::hasNoForgettingAssumption()
const {
460 return !noForgettingOrder_.empty();
463 template <
typename GUM_SCALAR >
464 void ShaferShenoyLIMIDInference< GUM_SCALAR >::addNoForgettingAssumption(
465 const std::vector< std::string >& names) {
466 addNoForgettingAssumption(this->influenceDiagram().ids(names));
469 template <
typename GUM_SCALAR >
470 void ShaferShenoyLIMIDInference< GUM_SCALAR >::addNoForgettingAssumption(
471 const std::vector< NodeId >& ids) {
472 const auto& infdiag = this->influenceDiagram();
473 for (
const auto node: ids) {
475 if (!infdiag.isDecisionNode(node))
477 "Node " << node <<
" (" << infdiag.variable(node).name()
478 <<
") is not a decision node");
480 if (infdiag.decisionNodeSize() != ids.size())
483 noForgettingOrder_ = ids;
487 template < typename GUM_SCALAR >
488 NodeSet ShaferShenoyLIMIDInference< GUM_SCALAR >::nonRequisiteNodes_(NodeId d)
const {
489 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
494 if (reduced_.parents(d).empty()) return res;
497 for (const auto n: reduced_.descendants(d))
498 if (infdiag.isUtilityNode(n)) descUs.insert(n);
500 NodeSet cumul{descUs};
502 auto g = reduced_.moralizedAncestralGraph(cumul);
504 NodeSet family{reduced_.parents(d)};
507 for (
const auto p: reduced_.parents(d)) {
509 for (
const auto u: descUs) {
510 if (g.hasUndirectedPath(p, u, family)) {
515 if (notReq) res << p;
520 template <
typename GUM_SCALAR >
521 InfluenceDiagram< GUM_SCALAR > ShaferShenoyLIMIDInference< GUM_SCALAR >::reducedLIMID()
const {
522 const auto& infdiag = this->influenceDiagram();
523 InfluenceDiagram< GUM_SCALAR > res;
524 for (
auto node: infdiag.nodes()) {
525 if (infdiag.isChanceNode(node)) res.addChanceNode(infdiag.variable(node), node);
526 else if (infdiag.isDecisionNode(node)) res.addDecisionNode(infdiag.variable(node), node);
528 res.addUtilityNode(infdiag.variable(node), node);
531 for (
const auto& arc: reduced_.arcs()) {
532 res.addArc(arc.tail(), arc.head());
535 for (
auto node: infdiag.nodes()) {
536 if (infdiag.isChanceNode(node)) res.cpt(node).fillWith(infdiag.cpt(node));
537 else if (infdiag.isUtilityNode(node)) res.utility(node).fillWith(infdiag.utility(node));
544 template <
typename GUM_SCALAR >
545 const JunctionTree* ShaferShenoyLIMIDInference< GUM_SCALAR >::junctionTree()
const {
546 if (!isSolvable()) {
GUM_ERROR(
FatalError,
"This LIMID/Influence Diagram is not solvable.") }
547 return &reducedJunctionTree_;
550 template <
typename GUM_SCALAR >
551 void ShaferShenoyLIMIDInference< GUM_SCALAR >::collectingMessage_(PhiNodeProperty& phi,
553 const NodeId rootClique) {
554 const auto& jt = *junctionTree();
555 GUM_SSLI_TRACE_ON(
"COLLECTING TO " << rootClique <<
":"
556 << this->influenceDiagram().names(jt.clique(rootClique)))
558 std::function< void(NodeId, NodeId) > parcours = [&](NodeId node, NodeId toRoot) {
559 for (
const auto nei: jt.neighbours(node)) {
560 if (nei != toRoot) parcours(nei, node);
562 transmittingMessage_(phi, psi, node, toRoot);
563 GUM_SSLI_TRACE_ON(
" " << node <<
"->" << toRoot <<
" transmitted")
566 for (
const auto nei: jt.neighbours(rootClique)) {
567 parcours(nei, rootClique);
571 template <
typename GUM_SCALAR >
572 void ShaferShenoyLIMIDInference< GUM_SCALAR >::collectingToFollowingRoot_(PhiNodeProperty& phi,
576 GUM_SSLI_TRACE_ON(
"COLLECTING FROM ROOT " << fromClique <<
" TO FOLLOWING ROOT " << toClique)
577 const auto& jt = *junctionTree();
579 std::function<
bool(NodeId, NodeId, NodeId) > revparcours
580 = [&](NodeId node, NodeId from, NodeId target) {
581 if (node == target)
return true;
585 for (
const auto nei: jt.neighbours(node)) {
587 if (revparcours(nei, node, target)) {
593 if (found) { transmittingMessage_(phi, psi, prec, node); }
597 revparcours(toClique, std::numeric_limits< NodeId >::max(), fromClique);
600 template <
typename GUM_SCALAR >
601 void ShaferShenoyLIMIDInference< GUM_SCALAR >::deciding_(PhiNodeProperty& phi,
603 NodeId decisionNode) {
604 const auto& infdiag = this->influenceDiagram();
605 GUM_SSLI_TRACE_ON(
"DECIDING for " << infdiag.variable(decisionNode).name())
607 auto& decision = strategies_.getWithDefault(decisionNode, Tensor< GUM_SCALAR >());
609 if (this->hasHardEvidence(decisionNode)) {
610 decision = *(this->evidence()[decisionNode]);
612 DecisionTensor< double > dp;
613 dp = integrating_(phi, psi, node_to_clique_[decisionNode]);
614 GUM_SSLI_TENSOR_TRACE_ON(dp)
617 sev.insert(&infdiag.variable(decisionNode));
618 for (
const auto parent: reduced_.parents(decisionNode)) {
619 sev.insert(&infdiag.variable(parent));
622 GUM_SSLI_TENSOR_TRACE_ON(dp)
625 sev.erase(&infdiag.variable(decisionNode));
626 if (sev.size() == 0) {
627 unconditionalDecisions_.set(decisionNode, dp);
628 }
else if (dp.probPot.sumIn(sev).normalize().max()
631 unconditionalDecisions_.set(
633 DecisionTensor< double >(dp.probPot.sumOut(sev), dp.utilPot.sumOut(sev)));
635 decision = dp.utilPot.putFirst(&infdiag.variable(decisionNode));
637 binarizingMax_(decision, dp.probPot);
638 GUM_SSLI_TENSOR_TRACE_ON(decision)
640 GUM_SSLI_TENSOR_TRACE_ON(phi[node_to_clique_[decisionNode]])
641 phi[node_to_clique_[decisionNode]].insertProba(decision);
642 GUM_SSLI_TENSOR_TRACE_ON(phi[node_to_clique_[decisionNode]])
645 template <
typename GUM_SCALAR >
646 void ShaferShenoyLIMIDInference< GUM_SCALAR >::binarizingMax_(
647 const Tensor< GUM_SCALAR >& decision,
648 const Tensor< GUM_SCALAR >& proba)
const {
649 Instantiation I(decision);
650 const auto& firstvar = decision.variable(0);
651 for (I.setFirst(); !I.end(); I.incNotVar(firstvar)) {
652 I.setFirstVar(firstvar);
653 while (proba[I] == 0) {
657 I.setFirstVar(firstvar);
662 Idx argm = I.val(firstvar);
663 GUM_SCALAR umax = decision[I];
664 GUM_SCALAR pmax = proba[I];
665 for (I.incVar(firstvar); !I.end(); I.incVar(firstvar)) {
668 if ((umax < decision[I]) || ((umax == decision[I]) && (pmax < proba[I]))) {
671 argm = I.val(firstvar);
675 for (I.setFirstVar(firstvar); !I.end(); I.incVar(firstvar))
677 I.chgVal(firstvar, argm);
682 template <
typename GUM_SCALAR >
683 void ShaferShenoyLIMIDInference< GUM_SCALAR >::distributingMessage_(PhiNodeProperty& phi,
686 const auto& jt = *junctionTree();
687 GUM_SSLI_TRACE_ON(
"DISTRIBUTING FROM " << rootClique <<
":"
688 << this->influenceDiagram().names(jt.clique(rootClique)))
690 std::function< void(NodeId, NodeId) > parcours = [&](NodeId node, NodeId from) {
691 transmittingFinalMessage_(phi, psi, from, node);
692 auto res = integrating_(phi, psi, node);
697 res.utilPot = res.utilPot - psi[
gum::Arc(node, from)].utilPot;
700 GUM_SSLI_TRACE_ON(
" -> phi[" << node <<
"] updated")
701 for (const auto nei: jt.neighbours(node)) {
702 if (nei != from) parcours(nei, node);
706 phi.set(rootClique, integrating_(phi, psi, rootClique));
707 GUM_SSLI_TRACE_ON(
" -> phi[" << rootClique <<
"] updated")
708 GUM_SSLI_TENSOR_TRACE_ON(phi[rootClique])
710 for (const auto nei: jt.neighbours(rootClique)) {
711 parcours(nei, rootClique);
715 template <
typename GUM_SCALAR >
716 void ShaferShenoyLIMIDInference< GUM_SCALAR >::transmittingFinalMessage_(PhiNodeProperty& phi,
720 GUM_SSLI_TRACE_ON(fromClique <<
"->" << toClique <<
" [final]")
722 psi.set(Arc(fromClique, toClique),
723 phi[fromClique] ^ varsSeparator_[Edge(fromClique, toClique)]);
726 template < typename GUM_SCALAR >
727 void ShaferShenoyLIMIDInference< GUM_SCALAR >::transmittingMessage_(PhiNodeProperty& phi,
731 GUM_SSLI_TRACE_ON(fromClique <<
"->" << toClique)
732 psi.set(Arc(fromClique, toClique),
733 integrating_(phi, psi, fromClique, toClique)
734 ^ varsSeparator_[Edge(fromClique, toClique)]);
737 template <
typename GUM_SCALAR >
738 DecisionTensor< double >
739 ShaferShenoyLIMIDInference< GUM_SCALAR >::integrating_(
const PhiNodeProperty& phi,
740 const PsiArcProperty& psi,
742 NodeId except)
const {
743 const auto& jt = *junctionTree();
744 GUM_SSLI_TRACE_ON(
" integrating (except from "
745 << except <<
") in " << inClique <<
":"
746 << this->influenceDiagram().names(jt.clique(inClique)))
747 DecisionTensor< double > res = phi[inClique];
748 for (
const auto nei: jt.neighbours(inClique))
749 if (nei != except) res *= psi[Arc(nei, inClique)];
754 template <
typename GUM_SCALAR >
755 DecisionTensor< double >
756 ShaferShenoyLIMIDInference< GUM_SCALAR >::integrating_(
const PhiNodeProperty& phi,
757 const PsiArcProperty& psi,
758 NodeId inClique)
const {
759 const auto& jt = *junctionTree();
760 GUM_SSLI_TRACE_ON(
" integrating in " << inClique <<
":"
761 << this->influenceDiagram().names(jt.clique(inClique)))
762 DecisionTensor< double > res = phi[inClique];
764 for (
const auto nei: jt.neighbours(inClique))
765 res *= psi[Arc(nei, inClique)];
770 template <
typename GUM_SCALAR >
771 void ShaferShenoyLIMIDInference< GUM_SCALAR >::computingPosteriors_(
const PhiNodeProperty& phi,
772 const PsiArcProperty& psi) {
773 NodeProperty< DecisionTensor< double > > finalphis;
775 const auto& infdiag = this->influenceDiagram();
778 for (
const auto node: infdiag.nodes()) {
779 const auto clik = node_to_clique_[node];
782 const auto& finalphi = phi[clik];
783 GUM_SSLI_TRACE_ON(
"posterior for " << infdiag.variable(node).name())
785 DecisionTensor< GUM_SCALAR > res;
787 if (infdiag.isChanceNode(node)) {
789 sev.insert(&infdiag.variable(node));
790 res = finalphi ^ sev;
791 const auto f = res.probPot.sum();
792 res.probPot.scale(1 / f);
793 }
else if (infdiag.isDecisionNode(node)) {
795 sev.insert(&infdiag.variable(node));
796 SetOfVars family = sev;
797 for (
const auto par: reduced_.parents(node)) {
798 if (infdiag.isChanceNode(par)) family.insert(&infdiag.variable(par));
800 const auto dp = finalphi ^ family;
803 binarizingMax_(decision, dp.probPot);
804 strategies_.insert(node, decision);
806 res.probPot.normalize();
807 if (unconditionalDecisions_.exists(node)) {
808 res.utilPot = unconditionalDecisions_[node].utilPot;
813 family.insert(&infdiag.variable(node));
814 for (
const auto par: reduced_.parents(node)) {
815 family.insert(&infdiag.variable(par));
817 res = finalphi ^ family;
819 res.probPot.normalize();
820 res.utilPot = infdiag.utility(node);
823 posteriors_.set(node, res);
827 template <
typename GUM_SCALAR >
828 const Tensor< GUM_SCALAR >& ShaferShenoyLIMIDInference< GUM_SCALAR >::posterior(NodeId node) {
829 return posteriors_[node].probPot;
832 template <
typename GUM_SCALAR >
833 const Tensor< GUM_SCALAR >&
834 ShaferShenoyLIMIDInference< GUM_SCALAR >::posteriorUtility(NodeId node) {
835 return posteriors_[node].utilPot;
838 template <
typename GUM_SCALAR >
839 std::pair< GUM_SCALAR, GUM_SCALAR >
840 ShaferShenoyLIMIDInference< GUM_SCALAR >::meanVar(NodeId node) {
841 return posteriors_[node].meanVar();
Implementation of an influence diagram inference algorithm based upon Shaffer-Shenoy's one for bayes ...
The base class for all directed edges.
static Tensor< GUM_SCALAR > divideEvenZero(const Tensor< GUM_SCALAR > &p1, const Tensor< GUM_SCALAR > &p2)
Exception : fatal (unknown ?) error.
<agrum/ID/inference/influenceDiagramInference.h>
Class representing an Influence Diagram.
Exception : node does not exist.
Exception : the element we looked for cannot be found.
Exception : operation not allowed.
void resize(Size new_capacity)
Changes the size of the underlying hash table containing the set.
ShaferShenoyLIMIDInference(const InfluenceDiagram< GUM_SCALAR > *infDiag)
Default constructor.
Exception : problem with size.
aGrUM's Tensor is a multi-dimensional array with tensor operators.
Exception : wrong type for this operation.
This file contains abstract class definitions influence diagrams inference classes.
#define GUM_ERROR(type, msg)
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
gum is the global namespace for all aGrUM entities
CliqueGraph JunctionTree
a junction tree is a clique graph satisfying the running intersection property and such that no cliqu...
Header of the Tensor class.