51#ifndef DOXYGEN_SHOULD_SKIP_THIS
60# define GUM_SSLI_TRACE_ON(x)
61# define GUM_SSLI_TENSOR_TRACE_ON(x)
65 template < GUM_Numeric GUM_SCALAR >
69 GUM_CONSTRUCTOR(ShaferShenoyLIMIDInference);
73 template < GUM_Numeric GUM_SCALAR >
74 ShaferShenoyLIMIDInference< GUM_SCALAR >::~ShaferShenoyLIMIDInference() {
75 GUM_DESTRUCTOR(ShaferShenoyLIMIDInference);
78 template < GUM_Numeric GUM_SCALAR >
79 void ShaferShenoyLIMIDInference< GUM_SCALAR >::clear() {
80 GraphicalModelInference< GUM_SCALAR >::clear();
81 noForgettingOrder_.clear();
83 reducedJunctionTree_.clear();
84 solvabilityOrder_.clear();
86 unconditionalDecisions_.clear();
88 reversePartialOrder_.clear();
91 template < GUM_Numeric GUM_SCALAR >
92 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onStateChanged_() {}
94 template < GUM_Numeric GUM_SCALAR >
95 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onEvidenceAdded_(
const NodeId
id,
96 bool isHardEvidence) {
97 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
99 if (infdiag.isDecisionNode(
id)) {
104 template < GUM_Numeric GUM_SCALAR >
105 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onEvidenceErased_(
const NodeId
id,
106 bool isHardEvidence) {}
108 template < GUM_Numeric GUM_SCALAR >
109 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onAllEvidenceErased_(
bool contains_hard_evidence) {
112 template < GUM_Numeric GUM_SCALAR >
113 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onEvidenceChanged_(
const NodeId
id,
114 bool hasChangedSoftHard) {}
116 template < GUM_Numeric GUM_SCALAR >
117 void ShaferShenoyLIMIDInference< GUM_SCALAR >::onModelChanged_(
const GraphicalModel* model) {
121 template < GUM_Numeric GUM_SCALAR >
122 void ShaferShenoyLIMIDInference< GUM_SCALAR >::updateOutdatedStructure_() {
126 template < GUM_Numeric GUM_SCALAR >
127 void ShaferShenoyLIMIDInference< GUM_SCALAR >::updateOutdatedTensors_() {}
129 template < GUM_Numeric GUM_SCALAR >
130 void ShaferShenoyLIMIDInference< GUM_SCALAR >::makeInference_() {
131 if (!isSolvable()) {
GUM_ERROR(
FatalError,
"This LIMID/Influence Diagram is not solvable.") }
136 GUM_SSLI_TRACE_ON(
"\n\n")
138 initializingInference_(phi, psi);
141 const auto firstRootIndice = 0;
142 collectingMessage_(phi, psi, node_to_clique_[solvabilityOrder_[firstRootIndice]]);
143 deciding_(phi, psi, solvabilityOrder_[firstRootIndice]);
145 for (Idx nextRootIndice = 1; nextRootIndice < solvabilityOrder_.size(); nextRootIndice++) {
146 if (node_to_clique_[solvabilityOrder_[nextRootIndice - 1]]
147 != node_to_clique_[solvabilityOrder_[nextRootIndice]]) {
148 collectingToFollowingRoot_(phi,
150 node_to_clique_[solvabilityOrder_[nextRootIndice - 1]],
151 node_to_clique_[solvabilityOrder_[nextRootIndice]]);
153 deciding_(phi, psi, solvabilityOrder_[nextRootIndice]);
157 distributingMessage_(phi,
159 node_to_clique_[solvabilityOrder_[solvabilityOrder_.size() - 1]]);
160 computingPosteriors_(phi, psi);
163 template < GUM_Numeric GUM_SCALAR >
164 void ShaferShenoyLIMIDInference< GUM_SCALAR >::initializingInference_(PhiNodeProperty& phi,
165 PsiArcProperty& psi) {
166 const auto& jt = *junctionTree();
167 const auto& infdiag = this->influenceDiagram();
170 for (
const auto node: jt.nodes()) {
171 phi.insert(node, DecisionTensor< GUM_SCALAR >());
172 for (
const auto nei: jt.neighbours(node)) {
173 psi.insert(
Arc(node, nei), DecisionTensor< GUM_SCALAR >());
176 for (
const auto n: jt.clique(node) * jt.clique(nei))
177 varsSeparator_.getWithDefault(
Edge(node, nei), SetOfVars())
178 .insert(&(infdiag.variable(n)));
182 for (
const auto node: infdiag.nodes()) {
183 const auto clik = node_to_clique_[node];
184 if (this->hasEvidence(node)) {
185 auto q = *(this->evidence()[node]);
186 phi[clik].insertProba(q.normalize());
189 if (infdiag.isDecisionNode(node)) {
190 if (!this->hasEvidence(node)) {
191 auto p = (Tensor< GUM_SCALAR >() << infdiag.variable(node)).fillWith(1).normalize();
192 phi[clik].insertProba(p);
194 }
else if (infdiag.isChanceNode(node)) phi[clik].insertProba(infdiag.cpt(node));
195 else if (infdiag.isUtilityNode(node)) phi[clik].insertUtility(infdiag.utility(node));
200 template < GUM_Numeric GUM_SCALAR >
201 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_creatingJunctionTree_() {
202 const auto& infdiag = this->influenceDiagram();
203 auto moral = reduced_.moralGraph();
207 NodeProperty< Size > modalities;
208 for (
const auto node: infdiag.nodes())
209 if (infdiag.isUtilityNode(node)) {
210 moral.eraseNode(node);
212 modalities.insert(node, infdiag.variable(node).domainSize());
214 DefaultTriangulation triangulation(&moral, &modalities);
215 reducedJunctionTree_ = triangulation.junctionTree();
216 _findingCliqueForEachNode_(triangulation);
219 template < GUM_Numeric GUM_SCALAR >
220 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_findingCliqueForEachNode_(
221 DefaultTriangulation& triangulation) {
224 const auto& infdiag = this->influenceDiagram();
225 NodeId first_eliminated_node;
227 node_to_clique_.clear();
228 const std::vector< NodeId >& JT_elim_order = triangulation.eliminationOrder();
229 NodeProperty< Idx > elim_order(Size(JT_elim_order.size()));
230 for (Idx i = Idx(0), size = JT_elim_order.size(); i < size; ++i)
231 elim_order.insert(JT_elim_order[i], (
int)i);
232 for (
const auto node: reduced_.nodes()) {
233 if (infdiag.isUtilityNode(node)) {
236 first_eliminated_node = node;
237 elim_number = std::numeric_limits< NodeId >::max();
240 first_eliminated_node = node;
241 elim_number = elim_order[first_eliminated_node];
244 for (
const auto parent: reduced_.parents(node)) {
245 if (elim_order[parent] < elim_number) {
246 elim_number = elim_order[parent];
247 first_eliminated_node = parent;
255 node_to_clique_.insert(node, triangulation.createdJunctionTreeClique(first_eliminated_node));
259 template < GUM_Numeric GUM_SCALAR >
260 std::pair< GUM_SCALAR, GUM_SCALAR > ShaferShenoyLIMIDInference< GUM_SCALAR >::MEU() {
263 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
265 GUM_SCALAR resmean = 0;
266 GUM_SCALAR resvar = 0;
267 for (auto node: infdiag.nodes()) {
268 if (infdiag.isUtilityNode(node)) {
269 auto p = meanVar(node);
274 return std::pair< GUM_SCALAR, GUM_SCALAR >(resmean, resvar);
277 template < GUM_Numeric GUM_SCALAR >
279 ShaferShenoyLIMIDInference< GUM_SCALAR >::optimalDecision(NodeId decisionId) {
282 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
283 if (!infdiag.isDecisionNode(decisionId))
285 infdiag.variable(decisionId).name()
286 <<
"(" << decisionId <<
") is not a decision node.")
288 return strategies_[decisionId];
291 template < GUM_Numeric GUM_SCALAR >
292 bool ShaferShenoyLIMIDInference< GUM_SCALAR >::isSolvable()
const {
293 return (!solvabilityOrder_.empty());
296 template < GUM_Numeric GUM_SCALAR >
297 void ShaferShenoyLIMIDInference< GUM_SCALAR >::createReduced_() {
300 reducedJunctionTree_.clear();
301 solvabilityOrder_.clear();
302 reversePartialOrder_.clear();
304 unconditionalDecisions_.clear();
306 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
311 for (
auto node: infdiag.nodes()) {
312 reduced_.addNodeWithId(node);
313 if (infdiag.isUtilityNode(node)) { utilities.insert(node); }
316 for (
const auto& arc: infdiag.arcs())
317 reduced_.addArc(arc.tail(), arc.head());
319 _completingNoForgettingAssumption_();
320 _creatingPartialOrder_(utilities);
321 _checkingSolvability_(utilities);
324 _creatingJunctionTree_();
327 this->setState_(GraphicalModelInference< GUM_SCALAR >::StateOfInference::OutdatedStructure);
330 template < GUM_Numeric GUM_SCALAR >
331 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_completingNoForgettingAssumption_() {
333 if (hasNoForgettingAssumption()) {
334 auto last = *(noForgettingOrder_.begin());
335 for (
auto node: noForgettingOrder_)
340 if (!reduced_.existsArc(last, node)) { reduced_.addArc(last, node); }
341 for (
auto par: reduced_.parents(last)) {
342 if (!reduced_.existsArc(par, node)) reduced_.addArc(par, node);
349 template < GUM_Numeric GUM_SCALAR >
350 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_checkingSolvability_(
const NodeSet& utilities) {
351 if (hasNoForgettingAssumption()) {
352 solvabilityOrder_ = noForgettingOrder_;
353 std::reverse(solvabilityOrder_.begin(), solvabilityOrder_.end());
357 solvabilityOrder_.clear();
358 for (
const auto& sen: reversePartialOrder()) {
360 while (!tobetested.empty()) {
361 bool foundOne =
false;
362 for (
const auto& node: tobetested) {
363 const auto us = utilities * reduced_.descendants(node);
365 for (
const auto dec: tobetested)
366 if (dec != node) decs += reduced_.family(dec);
367 if (reduced_.dSeparation(decs, us, reduced_.family(node))) {
368 solvabilityOrder_.push_back(node);
370 tobetested.erase(node);
375 solvabilityOrder_.clear();
382 template < GUM_Numeric GUM_SCALAR >
383 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_reducingLIMID_() {
384 for (
const auto& sen: reversePartialOrder_) {
386 for (
auto p: nonRequisiteNodes_(n))
387 reduced_.eraseArc(
Arc(p, n));
392 template < GUM_Numeric GUM_SCALAR >
393 void ShaferShenoyLIMIDInference< GUM_SCALAR >::_creatingPartialOrder_(
const NodeSet& utilities) {
394 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
395 NodeProperty< Size > level;
397 for (
const auto& node: utilities)
398 level.insert(node, 0);
402 reversePartialOrder_.clear();
403 reversePartialOrder_.resize(infdiag.size());
405 for (
auto node: infdiag.nodes()) {
406 if (infdiag.isUtilityNode(node))
continue;
407 if (reduced_.children(node).isSubsetOrEqual(utilities)) {
409 currents.insert(node);
410 level.insert(node, 0);
411 while (!currents.empty()) {
412 NodeId elt = *(currents.begin());
415 if (infdiag.isDecisionNode(elt)) reversePartialOrder_[level[elt]].insert(elt);
417 for (
auto parent: reduced_.parents(elt)) {
420 bool ok_to_add =
true;
421 for (
auto child: reduced_.children(parent)) {
422 if (!level.exists(child)) {
427 if (infdiag.isDecisionNode(child)) newl += 1;
428 if (lev < newl) lev = newl;
431 currents.insert(parent);
432 if (level.exists(parent)) {
433 if (level[parent] != lev)
435 "Trying to set level[" << parent <<
"] to level=" << lev
436 <<
" but already is " << level[parent]);
438 level.insert(parent, lev);
441 if (max_level < lev) max_level = lev;
448 for (
const auto& k: reversePartialOrder_) {
449 if (k.empty())
break;
452 reversePartialOrder_.
resize(levmax);
455 template < GUM_Numeric GUM_SCALAR >
456 std::vector< NodeSet > ShaferShenoyLIMIDInference< GUM_SCALAR >::reversePartialOrder()
const {
457 return reversePartialOrder_;
460 template < GUM_Numeric GUM_SCALAR >
461 bool ShaferShenoyLIMIDInference< GUM_SCALAR >::hasNoForgettingAssumption()
const {
462 return !noForgettingOrder_.empty();
465 template < GUM_Numeric GUM_SCALAR >
466 void ShaferShenoyLIMIDInference< GUM_SCALAR >::addNoForgettingAssumption(
467 const std::vector< std::string >& names) {
468 addNoForgettingAssumption(this->influenceDiagram().ids(names));
471 template < GUM_Numeric GUM_SCALAR >
472 void ShaferShenoyLIMIDInference< GUM_SCALAR >::addNoForgettingAssumption(
473 const std::vector< NodeId >& ids) {
474 const auto& infdiag = this->influenceDiagram();
475 for (
const auto node: ids) {
477 if (!infdiag.isDecisionNode(node))
479 "Node " << node <<
" (" << infdiag.variable(node).name()
480 <<
") is not a decision node");
482 if (infdiag.decisionNodeSize() != ids.size())
485 noForgettingOrder_ = ids;
489 template < GUM_Numeric GUM_SCALAR >
490 NodeSet ShaferShenoyLIMIDInference< GUM_SCALAR >::nonRequisiteNodes_(NodeId d)
const {
491 const InfluenceDiagram< GUM_SCALAR >& infdiag = this->influenceDiagram();
496 if (reduced_.parents(d).empty()) return res;
499 for (const auto n: reduced_.descendants(d))
500 if (infdiag.isUtilityNode(n)) descUs.insert(n);
502 NodeSet cumul{descUs};
504 auto g = reduced_.moralizedAncestralGraph(cumul);
509 for (
const auto p: reduced_.parents(d)) {
511 for (
const auto u: descUs) {
512 if (g.hasUndirectedPath(p, u, family)) {
517 if (notReq) res << p;
522 template < GUM_Numeric GUM_SCALAR >
523 InfluenceDiagram< GUM_SCALAR > ShaferShenoyLIMIDInference< GUM_SCALAR >::reducedLIMID()
const {
524 const auto& infdiag = this->influenceDiagram();
525 InfluenceDiagram< GUM_SCALAR > res;
526 for (
auto node: infdiag.nodes()) {
527 if (infdiag.isChanceNode(node)) res.addChanceNode(infdiag.variable(node), node);
528 else if (infdiag.isDecisionNode(node)) res.addDecisionNode(infdiag.variable(node), node);
530 res.addUtilityNode(infdiag.variable(node), node);
533 for (
const auto& arc: reduced_.arcs()) {
534 res.addArc(arc.tail(), arc.head());
537 for (
auto node: infdiag.nodes()) {
538 if (infdiag.isChanceNode(node)) res.cpt(node).fillWith(infdiag.cpt(node));
539 else if (infdiag.isUtilityNode(node)) res.utility(node).fillWith(infdiag.utility(node));
546 template < GUM_Numeric GUM_SCALAR >
547 const JunctionTree* ShaferShenoyLIMIDInference< GUM_SCALAR >::junctionTree()
const {
548 if (!isSolvable()) {
GUM_ERROR(
FatalError,
"This LIMID/Influence Diagram is not solvable.") }
549 return &reducedJunctionTree_;
552 template < GUM_Numeric GUM_SCALAR >
553 void ShaferShenoyLIMIDInference< GUM_SCALAR >::collectingMessage_(PhiNodeProperty& phi,
555 const NodeId rootClique) {
556 const auto& jt = *junctionTree();
557 GUM_SSLI_TRACE_ON(
"COLLECTING TO " << rootClique <<
":"
558 << this->influenceDiagram().names(jt.clique(rootClique)))
560 std::function< void(NodeId, NodeId) > parcours = [&](NodeId node, NodeId toRoot) {
561 for (
const auto nei: jt.neighbours(node)) {
562 if (nei != toRoot) parcours(nei, node);
564 transmittingMessage_(phi, psi, node, toRoot);
565 GUM_SSLI_TRACE_ON(
" " << node <<
"->" << toRoot <<
" transmitted")
568 for (
const auto nei: jt.neighbours(rootClique)) {
569 parcours(nei, rootClique);
573 template < GUM_Numeric GUM_SCALAR >
574 void ShaferShenoyLIMIDInference< GUM_SCALAR >::collectingToFollowingRoot_(PhiNodeProperty& phi,
578 GUM_SSLI_TRACE_ON(
"COLLECTING FROM ROOT " << fromClique <<
" TO FOLLOWING ROOT " << toClique)
579 const auto& jt = *junctionTree();
581 std::function<
bool(NodeId, NodeId, NodeId) > revparcours
582 = [&](NodeId node, NodeId from, NodeId target) {
583 if (node == target)
return true;
587 for (
const auto nei: jt.neighbours(node)) {
589 if (revparcours(nei, node, target)) {
595 if (found) { transmittingMessage_(phi, psi, prec, node); }
599 revparcours(toClique, std::numeric_limits< NodeId >::max(), fromClique);
602 template < GUM_Numeric GUM_SCALAR >
603 void ShaferShenoyLIMIDInference< GUM_SCALAR >::deciding_(PhiNodeProperty& phi,
605 NodeId decisionNode) {
606 const auto& infdiag = this->influenceDiagram();
607 GUM_SSLI_TRACE_ON(
"DECIDING for " << infdiag.variable(decisionNode).name())
609 auto& decision = strategies_.getWithDefault(decisionNode, Tensor< GUM_SCALAR >());
611 if (this->hasHardEvidence(decisionNode)) {
612 decision = *(this->evidence()[decisionNode]);
614 DecisionTensor< double > dp;
615 dp = integrating_(phi, psi, node_to_clique_[decisionNode]);
616 GUM_SSLI_TENSOR_TRACE_ON(dp)
619 sev.insert(&infdiag.variable(decisionNode));
620 for (
const auto parent: reduced_.parents(decisionNode)) {
621 sev.insert(&infdiag.variable(parent));
624 GUM_SSLI_TENSOR_TRACE_ON(dp)
627 sev.erase(&infdiag.variable(decisionNode));
628 if (sev.size() == 0) {
629 unconditionalDecisions_.set(decisionNode, dp);
630 }
else if (dp.probPot.sumIn(sev).normalize().max()
633 unconditionalDecisions_.set(
635 DecisionTensor< double >(dp.probPot.sumOut(sev), dp.utilPot.sumOut(sev)));
637 decision = dp.utilPot.putFirst(&infdiag.variable(decisionNode));
639 binarizingMax_(decision, dp.probPot);
640 GUM_SSLI_TENSOR_TRACE_ON(decision)
642 GUM_SSLI_TENSOR_TRACE_ON(phi[node_to_clique_[decisionNode]])
643 phi[node_to_clique_[decisionNode]].insertProba(decision);
644 GUM_SSLI_TENSOR_TRACE_ON(phi[node_to_clique_[decisionNode]])
647 template < GUM_Numeric GUM_SCALAR >
648 void ShaferShenoyLIMIDInference< GUM_SCALAR >::binarizingMax_(
649 const Tensor< GUM_SCALAR >& decision,
650 const Tensor< GUM_SCALAR >& proba)
const {
651 Instantiation I(decision);
652 const auto& firstvar = decision.variable(0);
653 for (I.setFirst(); !I.end(); I.incNotVar(firstvar)) {
654 I.setFirstVar(firstvar);
655 while (proba[I] == 0) {
659 I.setFirstVar(firstvar);
664 Idx argm = I.val(firstvar);
665 GUM_SCALAR umax = decision[I];
666 GUM_SCALAR pmax = proba[I];
667 for (I.incVar(firstvar); !I.end(); I.incVar(firstvar)) {
670 if ((umax < decision[I]) || ((umax == decision[I]) && (pmax < proba[I]))) {
673 argm = I.val(firstvar);
677 for (I.setFirstVar(firstvar); !I.end(); I.incVar(firstvar))
679 I.chgVal(firstvar, argm);
684 template < GUM_Numeric GUM_SCALAR >
685 void ShaferShenoyLIMIDInference< GUM_SCALAR >::distributingMessage_(PhiNodeProperty& phi,
688 const auto& jt = *junctionTree();
689 GUM_SSLI_TRACE_ON(
"DISTRIBUTING FROM " << rootClique <<
":"
690 << this->influenceDiagram().names(jt.clique(rootClique)))
692 std::function< void(NodeId, NodeId) > parcours = [&](NodeId node, NodeId from) {
693 transmittingFinalMessage_(phi, psi, from, node);
694 auto res = integrating_(phi, psi, node);
699 res.utilPot = res.utilPot - psi[
gum::Arc(node, from)].utilPot;
702 GUM_SSLI_TRACE_ON(
" -> phi[" << node <<
"] updated")
703 for (const auto nei: jt.neighbours(node)) {
704 if (nei != from) parcours(nei, node);
708 phi.set(rootClique, integrating_(phi, psi, rootClique));
709 GUM_SSLI_TRACE_ON(
" -> phi[" << rootClique <<
"] updated")
710 GUM_SSLI_TENSOR_TRACE_ON(phi[rootClique])
712 for (const auto nei: jt.neighbours(rootClique)) {
713 parcours(nei, rootClique);
717 template < GUM_Numeric GUM_SCALAR >
718 void ShaferShenoyLIMIDInference< GUM_SCALAR >::transmittingFinalMessage_(PhiNodeProperty& phi,
722 GUM_SSLI_TRACE_ON(fromClique <<
"->" << toClique <<
" [final]")
724 psi.set(Arc(fromClique, toClique),
725 phi[fromClique] ^ varsSeparator_[Edge(fromClique, toClique)]);
728 template < GUM_Numeric GUM_SCALAR >
729 void ShaferShenoyLIMIDInference< GUM_SCALAR >::transmittingMessage_(PhiNodeProperty& phi,
733 GUM_SSLI_TRACE_ON(fromClique <<
"->" << toClique)
734 psi.set(
Arc(fromClique, toClique),
735 integrating_(phi, psi, fromClique, toClique)
736 ^ varsSeparator_[
Edge(fromClique, toClique)]);
739 template < GUM_Numeric GUM_SCALAR >
740 DecisionTensor< double >
741 ShaferShenoyLIMIDInference< GUM_SCALAR >::integrating_(
const PhiNodeProperty& phi,
742 const PsiArcProperty& psi,
744 NodeId except)
const {
745 const auto& jt = *junctionTree();
746 GUM_SSLI_TRACE_ON(
" integrating (except from "
747 << except <<
") in " << inClique <<
":"
748 << this->influenceDiagram().names(jt.clique(inClique)))
749 DecisionTensor< double > res = phi[inClique];
750 for (
const auto nei: jt.neighbours(inClique))
751 if (nei != except) res *= psi[
Arc(nei, inClique)];
756 template < GUM_Numeric GUM_SCALAR >
757 DecisionTensor< double >
758 ShaferShenoyLIMIDInference< GUM_SCALAR >::integrating_(
const PhiNodeProperty& phi,
759 const PsiArcProperty& psi,
760 NodeId inClique)
const {
761 const auto& jt = *junctionTree();
762 GUM_SSLI_TRACE_ON(
" integrating in " << inClique <<
":"
763 << this->influenceDiagram().names(jt.clique(inClique)))
764 DecisionTensor< double > res = phi[inClique];
766 for (
const auto nei: jt.neighbours(inClique))
767 res *= psi[
Arc(nei, inClique)];
772 template < GUM_Numeric GUM_SCALAR >
773 void ShaferShenoyLIMIDInference< GUM_SCALAR >::computingPosteriors_(
const PhiNodeProperty& phi,
774 const PsiArcProperty& psi) {
775 NodeProperty< DecisionTensor< double > > finalphis;
777 const auto& infdiag = this->influenceDiagram();
780 for (
const auto node: infdiag.nodes()) {
781 const auto clik = node_to_clique_[node];
784 const auto& finalphi = phi[clik];
785 GUM_SSLI_TRACE_ON(
"posterior for " << infdiag.variable(node).name())
787 DecisionTensor< GUM_SCALAR > res;
789 if (infdiag.isChanceNode(node)) {
791 sev.insert(&infdiag.variable(node));
792 res = finalphi ^ sev;
793 const auto f = res.probPot.sum();
794 res.probPot.scale(1 / f);
795 }
else if (infdiag.isDecisionNode(node)) {
797 sev.insert(&infdiag.variable(node));
799 for (
const auto par: reduced_.parents(node)) {
800 if (infdiag.isChanceNode(par))
family.
insert(&infdiag.variable(par));
804# pragma GCC diagnostic push
805# pragma GCC diagnostic ignored "-Warray-bounds"
806 const auto dp = finalphi ^
family;
809 binarizingMax_(decision, dp.probPot);
810 strategies_.insert(node, decision);
812# pragma GCC diagnostic pop
813 res.probPot.normalize();
814 if (unconditionalDecisions_.exists(node)) {
815 res.utilPot = unconditionalDecisions_[node].utilPot;
821 for (
const auto par: reduced_.parents(node)) {
826 res.probPot.normalize();
827 res.utilPot = infdiag.utility(node);
830 posteriors_.set(node, res);
834 template < GUM_Numeric GUM_SCALAR >
835 const Tensor< GUM_SCALAR >& ShaferShenoyLIMIDInference< GUM_SCALAR >::posterior(NodeId node) {
836 return posteriors_[node].probPot;
839 template < GUM_Numeric GUM_SCALAR >
840 const Tensor< GUM_SCALAR >&
841 ShaferShenoyLIMIDInference< GUM_SCALAR >::posteriorUtility(NodeId node) {
842 return posteriors_[node].utilPot;
845 template < GUM_Numeric GUM_SCALAR >
846 std::pair< GUM_SCALAR, GUM_SCALAR >
847 ShaferShenoyLIMIDInference< GUM_SCALAR >::meanVar(NodeId node) {
848 return posteriors_[node].meanVar();
851 template < GUM_Numeric GUM_SCALAR >
852 DAG ShaferShenoyLIMIDInference< GUM_SCALAR >::reducedGraph()
const {
856 template < GUM_Numeric GUM_SCALAR >
858 ShaferShenoyLIMIDInference< GUM_SCALAR >::optimalDecision(std::string_view decisionName) {
859 return optimalDecision(this->influenceDiagram().idFromName(decisionName));
862 template < GUM_Numeric GUM_SCALAR >
863 const Tensor< GUM_SCALAR >&
864 ShaferShenoyLIMIDInference< GUM_SCALAR >::posterior(std::string_view name) {
865 return posterior(this->influenceDiagram().idFromName(name));
868 template < GUM_Numeric GUM_SCALAR >
869 const Tensor< GUM_SCALAR >&
870 ShaferShenoyLIMIDInference< GUM_SCALAR >::posteriorUtility(std::string_view name) {
871 return posteriorUtility(this->influenceDiagram().idFromName(name));
874 template < GUM_Numeric GUM_SCALAR >
875 std::pair< GUM_SCALAR, GUM_SCALAR >
876 ShaferShenoyLIMIDInference< GUM_SCALAR >::meanVar(std::string_view name) {
877 return meanVar(this->influenceDiagram().idFromName(name));
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.
void insert(const Key &k)
Inserts a new element into 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 ...
NodeSet family(const G &g, NodeId id)
Returns the family of id : { id } ∪ parents(id).
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.