34 #ifndef DOXYGEN_SHOULD_SKIP_THIS 42 template <
typename GUM_SCALAR >
44 const InfluenceDiagram< GUM_SCALAR >& infDiag) :
45 IInfluenceDiagramInference< GUM_SCALAR >(infDiag),
46 __triangulation(0), __inferencePotential(0), __inferenceUtility(0),
47 __inferenceMade(false) {
51 NodeProperty< Size > __modalitiesMap;
58 partialMoralGraph.eraseNode(node);
60 __modalitiesMap.insert(
65 const List< NodeSet >* partialTemporalOrder =
70 &partialMoralGraph, &__modalitiesMap, partialTemporalOrder);
78 template <
typename GUM_SCALAR >
96 template <
typename GUM_SCALAR >
115 template <
typename GUM_SCALAR >
118 GUM_ERROR(OperationNotAllowed,
"No inference have yet been made");
127 template <
typename GUM_SCALAR >
131 GUM_ERROR(OperationNotAllowed,
"No inference have yet been made");
134 GUM_ERROR(InvalidNode,
"Node is not a decision node");
140 template <
typename GUM_SCALAR >
142 std::stringstream stream;
145 GUM_ERROR(OperationNotAllowed,
"No inference have yet been made");
147 stream <<
"max EU : " << std::endl;
150 stream <<
"Best choices : " << std::endl;
162 template <
typename GUM_SCALAR >
164 const List<
const Potential< GUM_SCALAR >* >& evidenceList) {
165 for (
const auto ev : evidenceList)
173 template <
typename GUM_SCALAR >
175 const Potential< GUM_SCALAR >* evidence) {
176 if (!(evidence->variablesSequence().size() != 1))
178 evidence->variable(0))]]
179 ->removeEvidence(evidence->variable(0));
184 template <
typename GUM_SCALAR >
186 for (
const auto& elt : __cliquePropertiesMap)
187 elt.second->removeAllEvidence();
202 template <
typename GUM_SCALAR >
203 INLINE Triangulation&
210 template <
typename GUM_SCALAR >
221 template <
typename GUM_SCALAR >
223 const std::vector< NodeId >& eliminationOrder,
NodeId id) {
236 for (
size_t i = 0; i < eliminationOrder.size(); ++i)
237 if (idSet.contains(eliminationOrder[i]))
240 GUM_ERROR(FatalError,
"No clique found for node " <<
id);
247 template <
typename GUM_SCALAR >
253 NodeSet potentialsCliquesSet, utilitiesCliqueSet;
257 __cliquePropertiesMap.
insert(cli,
new CliqueProperties< GUM_SCALAR >());
259 potentialsCliquesSet.insert(cli);
260 utilitiesCliqueSet.insert(cli);
264 __cliquePropertiesMap[cli]->addVariable(
268 __cliquePropertiesMap[cli]->makeEliminationOrder(elim,
273 for (
size_t i = 0; i < elim.size(); i++) {
280 __cliquePropertiesMap[cliqueId]->addPotential(
282 potentialsCliquesSet.erase(cliqueId);
289 for (
const auto cliq : potentialsCliquesSet)
300 __cliquePropertiesMap[cliqueId]->addUtility(
302 utilitiesCliqueSet.erase(cliqueId);
306 for (
const auto cliq : utilitiesCliqueSet)
310 template <
typename GUM_SCALAR >
315 __cliquePropertiesMap[cli]->cliqueEliminationOrder();
316 SequenceIterator< NodeId > cliqueNodesIter = eliminationOrder.
begin();
317 bool validIndex =
false;
320 while (cliqueNodesIter != eliminationOrder.
end() && !validIndex) {
321 SequenceIterator< NodeId > cliqueRemainingNodesIter = cliqueNodesIter;
322 ++cliqueRemainingNodesIter;
324 if (cliqueRemainingNodesIter != eliminationOrder.
end()) {
326 *cliqueRemainingNodesIter));
328 while (cliqueRemainingNodesIter != eliminationOrder.
end()
329 && !suspectedNodes.empty()) {
330 NodeSet possiblesNodes(suspectedNodes);
332 for (
const auto possibleNode : possiblesNodes)
336 suspectedNodes.erase(possibleNode);
338 ++cliqueRemainingNodesIter;
341 if (!suspectedNodes.empty())
342 for (
const auto suspectedNode : suspectedNodes)
343 if (!eliminationOrder.
exists(suspectedNode)
350 if (!validIndex) ++cliqueNodesIter;
356 for (std::vector< NodeId >::const_iterator eliminationOrderIter =
359 && *eliminationOrderIter != *cliqueNodesIter;
360 ++eliminationOrderIter, ++index)
368 }
catch (Exception& e) {
throw(e); }
376 template <
typename GUM_SCALAR >
379 for (std::vector< NodeId >::const_iterator eliminationOrderIter =
382 ++eliminationOrderIter) {
383 if (*eliminationOrderIter == currentNode)
return true;
385 if (*eliminationOrderIter == observedNode)
return false;
393 template <
typename GUM_SCALAR >
395 std::ostream& stream) {
396 stream << std::endl <<
"Strong junction tree map : " << std::endl;
400 <<
" - Index : " << elt.first << std::endl;
403 template <
typename GUM_SCALAR >
415 for (
const auto& prop : __cliquePropertiesMap)
416 prop.second->cleanFromInference();
418 __utakenDecisionMap.clear();
423 template <
typename GUM_SCALAR >
433 template <
typename GUM_SCALAR >
437 CliqueProperties< GUM_SCALAR >* absorbedClique =
438 __cliquePropertiesMap[absorbedCliqueId];
444 Potential< GUM_SCALAR >* potentialMarginal = 0;
445 Potential< GUM_SCALAR >* utilityMarginal = 0;
457 __reduceClique(absorbedClique, separator, potentialMarginal, utilityMarginal);
461 __cliquePropertiesMap[absorbingCliqueId]->addPotential(*potentialMarginal,
465 Instantiation utilityMarginalInst(utilityMarginal);
467 for (utilityMarginalInst.setFirst(); !utilityMarginalInst.end();
468 utilityMarginalInst.inc()) {
469 GUM_SCALAR uVal = (GUM_SCALAR)0;
471 if (potentialMarginal->get(utilityMarginalInst) != (GUM_SCALAR)0)
472 uVal = utilityMarginal->get(utilityMarginalInst)
473 / potentialMarginal->get(utilityMarginalInst);
475 utilityMarginal->set(utilityMarginalInst, uVal);
479 __cliquePropertiesMap[absorbingCliqueId]->addUtility(*utilityMarginal,
true);
492 template <
typename GUM_SCALAR >
494 CliqueProperties< GUM_SCALAR >* absorbedClique,
496 Potential< GUM_SCALAR >*& potentialMarginal,
497 Potential< GUM_SCALAR >*& utilityMarginal) {
498 Instantiation cliqueInstance(absorbedClique->cliqueInstantiation());
499 Sequence< const DiscreteVariable* > cliqueRemainVarList(
500 cliqueInstance.variablesSequence());
503 for (
const auto node : absorbedClique->cliqueEliminationOrder()) {
505 if (!separator.contains(node)) {
509 Potential< GUM_SCALAR >* newPotential =
new Potential< GUM_SCALAR >();
510 Potential< GUM_SCALAR >* newUtility =
new Potential< GUM_SCALAR >();
517 for (
const auto remain : cliqueRemainVarList) {
518 newPotential->add(*remain);
519 newUtility->add(*remain);
528 Instantiation newInstantiation(newPotential);
536 for (newInstantiation.setFirst(); !newInstantiation.end();
537 newInstantiation.inc()) {
539 GUM_SCALAR potentialValue = (GUM_SCALAR)0;
540 GUM_SCALAR utilityValue = (GUM_SCALAR)0;
543 utilityValue = -1 * (std::numeric_limits< GUM_SCALAR >::max());
546 cliqueInstance.setVals(newInstantiation);
548 for (cliqueInstance.setFirstOut(newInstantiation); !cliqueInstance.end();
549 cliqueInstance.incOut(newInstantiation)) {
552 GUM_SCALAR currentPotential = (GUM_SCALAR)1;
554 if (potentialMarginal == 0) {
558 for (
const auto& pot : absorbedClique->potentialBucket()) {
559 pot.second->setVals(cliqueInstance);
560 currentPotential *= pot.first->get(*pot.second);
563 Instantiation potentialMarginalInst(potentialMarginal);
564 potentialMarginalInst.setVals(cliqueInstance);
565 currentPotential = potentialMarginal->get(potentialMarginalInst);
570 GUM_SCALAR currentUtility = (GUM_SCALAR)0;
572 if (utilityMarginal == 0) {
573 for (
const auto& uti : absorbedClique->utilityBucket()) {
574 uti.second->setVals(cliqueInstance);
575 currentUtility += uti.first->get(*uti.second);
578 currentUtility *= currentPotential;
580 Instantiation utilityMarginalInst(utilityMarginal);
581 utilityMarginalInst.setVals(cliqueInstance);
582 currentUtility = utilityMarginal->get(utilityMarginalInst);
587 if (potentialValue < currentPotential) {
588 potentialValue = currentPotential;
591 if (utilityValue < currentUtility) {
592 utilityValue = currentUtility;
594 if (__utakenDecisionMap.exists(node))
595 __utakenDecisionMap.erase(node);
597 __utakenDecisionMap.insert(
599 cliqueInstance.val(this->influenceDiagram().variable(node)));
602 potentialValue += currentPotential;
603 utilityValue += currentUtility;
609 newPotential->set(newInstantiation, potentialValue);
610 newUtility->set(newInstantiation, utilityValue);
615 if (potentialMarginal != 0)
delete potentialMarginal;
617 potentialMarginal = newPotential;
619 if (utilityMarginal != 0)
delete utilityMarginal;
621 utilityMarginal = newUtility;
632 template <
typename GUM_SCALAR >
633 INLINE Potential< GUM_SCALAR >*
636 Potential< GUM_SCALAR >* pot =
new Potential< GUM_SCALAR >(
637 new MultiDimSparse< GUM_SCALAR >((GUM_SCALAR)1));
638 __potentialDummies.insert(pot);
641 pot->add(this->influenceDiagram().variable(cliqueNode));
649 template <
typename GUM_SCALAR >
650 INLINE Potential< GUM_SCALAR >*
652 Potential< GUM_SCALAR >* ut =
new Potential< GUM_SCALAR >(
653 new MultiDimSparse< GUM_SCALAR >((GUM_SCALAR)0));
657 ut->add(this->influenceDiagram().variable(cliqueNode));
663 template <
typename GUM_SCALAR >
664 CliqueProperties< GUM_SCALAR >::CliqueProperties() {
665 GUM_CONSTRUCTOR(CliqueProperties);
669 template <
typename GUM_SCALAR >
670 CliqueProperties< GUM_SCALAR >::~CliqueProperties() {
671 GUM_DESTRUCTOR(CliqueProperties);
673 cleanFromInference();
676 for (
const auto& pot : __potentialBucket)
679 for (
const auto& uti : __utilityBucket)
684 template <
typename GUM_SCALAR >
685 void CliqueProperties< GUM_SCALAR >::addVariable(
const DiscreteVariable& v) {
687 __allVarsInst.add(v);
688 }
catch (DuplicateElement&) {
696 template <
typename GUM_SCALAR >
697 INLINE
const Sequence< const DiscreteVariable* >&
698 CliqueProperties< GUM_SCALAR >::cliqueVariables() {
699 return __allVarsInst.variablesSequence();
704 template <
typename GUM_SCALAR >
705 INLINE Instantiation& CliqueProperties< GUM_SCALAR >::cliqueInstantiation() {
706 return __allVarsInst;
713 template <
typename GUM_SCALAR >
714 void CliqueProperties< GUM_SCALAR >::addPotential(
715 const Potential< GUM_SCALAR >& cpt,
bool removable) {
716 __potentialBucket.insert(&cpt,
new Instantiation(cpt));
718 if (removable) __removablePotentialList.insert(&cpt);
720 const auto& vars = cpt.variablesSequence();
721 for (
auto iter = vars.beginSafe(); iter != vars.end(); ++iter) {
722 if (removable && !__allVarsInst.contains(**iter))
try {
723 __removableVarList.insert(*iter);
724 }
catch (DuplicateElement&) {
733 template <
typename GUM_SCALAR >
734 INLINE
const HashTable< const Potential< GUM_SCALAR >*, Instantiation* >&
735 CliqueProperties< GUM_SCALAR >::potentialBucket() {
736 return __potentialBucket;
743 template <
typename GUM_SCALAR >
745 CliqueProperties< GUM_SCALAR >::addUtility(
const Potential< GUM_SCALAR >& ut,
747 __utilityBucket.insert(&ut,
new Instantiation(ut));
749 if (removable) __removableUtilityList.insert(&ut);
751 for (
auto var : ut.variablesSequence()) {
752 if (removable && !__allVarsInst.contains(*var))
try {
753 __removableVarList.insert(var);
754 }
catch (DuplicateElement&) {
763 template <
typename GUM_SCALAR >
764 INLINE
const HashTable< const Potential< GUM_SCALAR >*, Instantiation* >&
765 CliqueProperties< GUM_SCALAR >::utilityBucket() {
766 return __utilityBucket;
774 template <
typename GUM_SCALAR >
775 void CliqueProperties< GUM_SCALAR >::cleanFromInference() {
779 for (
const auto removableVar : __removableVarList)
780 __allVarsInst.erase(*removableVar);
783 for (
const auto removablePot : __removablePotentialList) {
784 delete __potentialBucket[removablePot];
785 __potentialBucket.erase(removablePot);
790 for (
const auto removabledUt : __removableUtilityList) {
791 delete __utilityBucket[removabledUt];
792 __utilityBucket.erase(removabledUt);
796 __removableVarList.clear();
797 __removablePotentialList.clear();
798 __removableUtilityList.clear();
805 template <
typename GUM_SCALAR >
806 void CliqueProperties< GUM_SCALAR >::makeEliminationOrder(
807 const std::vector< NodeId >& elim,
808 const InfluenceDiagram< GUM_SCALAR >& infDiag) {
809 for (
size_t i = 0; i < elim.size(); i++) {
810 if (__allVarsInst.contains(infDiag.variable(elim[i])))
811 __eliminationOrder.insert(elim[i]);
816 template <
typename GUM_SCALAR >
818 CliqueProperties< GUM_SCALAR >::cliqueEliminationOrder() {
819 return __eliminationOrder;
829 template <
typename GUM_SCALAR >
830 void CliqueProperties< GUM_SCALAR >::addEvidence(
831 const Potential< GUM_SCALAR >& evidence) {
833 cleanFromInference();
836 if (evidence.variablesSequence().size() != 1) {
838 "expected evidence on 1 variable, found on " 839 << evidence.variablesSequence().size());
843 if (!__allVarsInst.contains(evidence.variablesSequence().atPos(0))) {
845 evidence.variablesSequence().atPos(0)->name()
846 <<
" not found in clique ");
849 __evidences.insert(evidence.variablesSequence().atPos(0), &evidence);
851 __potentialBucket.insert(&evidence,
new Instantiation(evidence));
855 template <
typename GUM_SCALAR >
857 HashTable< const DiscreteVariable*, const Potential< GUM_SCALAR >* >&
858 CliqueProperties< GUM_SCALAR >::evidences()
const {
863 template <
typename GUM_SCALAR >
865 CliqueProperties< GUM_SCALAR >::removeEvidence(
const DiscreteVariable& v) {
866 const Potential< GUM_SCALAR >* evi = __evidences[&v];
868 delete __potentialBucket[evi];
869 __potentialBucket.erase(evi);
870 __evidences.erase(&v);
874 template <
typename GUM_SCALAR >
875 INLINE
void CliqueProperties< GUM_SCALAR >::removeAllEvidence() {
876 for (
const auto& elt : __evidences)
877 removeEvidence(*elt.first);
const InfluenceDiagram< GUM_SCALAR > & influenceDiagram() const
Returns a constant reference over the InfluenceDiagram on which this class work.
Potential< GUM_SCALAR > * __makeDummyPotential(NodeId cliqueId)
Returns a pointer over a "dummy" potential, which is a CPT filled with one MultiDimSparse filled with...
Set< Potential< GUM_SCALAR > *> __utilityDummies
The set of dummies sparse utilities matrix created.
Set< Potential< GUM_SCALAR > *> __potentialDummies
The set of dummies sparse potential matrix created.
iterator begin() const
Returns an unsafe begin iterator.
bool __IsEliminatedAfter(NodeId observedNode, NodeId currentNode)
Returns true if observed node is eliminated after current node.
Idx getBestDecisionChoice(NodeId decisionId)
const NodeSet & separator(const Edge &edge) const
returns the separator included in a given edge
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
NodeProperty< NodeId > __nodeToCliqueMap
Mapping of the nodes with the clique used to put their CPT.
Triangulation & getTriangulation()
Returns the Triangulation used by this class.
NodeId __getClique(const std::vector< NodeId > &eliminationOrder, NodeId id)
Potential< GUM_SCALAR > * __inferenceUtility
The resulting utility from inference.
gum is the global namespace for all aGrUM entities
Triangulation * __triangulation
The triangulation algorithm.
const NodeSet & neighbours(const NodeId id) const
returns the set of edges adjacent to a given node
void __cleanUp()
Cleans Up remaining stuff due to inference.
bool exists(const Key &k) const
Indicates whether a given elements belong to the set.
std::string displayResult()
displays the result of an inference
void __reduceClique(CliqueProperties< GUM_SCALAR > *absorbedClique, NodeSet &separator, Potential< GUM_SCALAR > *&potentialMarginal, Potential< GUM_SCALAR > *&utilityMarginal)
Reduces a clique down to her separator from another clique elements.
virtual NodeId createdJunctionTreeClique(const NodeId id)=0
returns the Id of the clique created by the elimination of a given node during the triangulation proc...
Implementation of an influence diagram inference algorithm based upon Shaffer-Shenoy's one for bayes ...
void __makeCliquePropertiesMap()
Builds the cliques tables Uses __getCliquesTable to initialize the cliques table, and multiply the ta...
const NodeGraphPart & nodes() const
return *this as a NodeGraphPart
bool exists(const Key &k) const
Check the existence of k in the sequence.
virtual void makeInference()
HashTable< Size, NodeId > __cliqueEliminationMap
Mapping of the nodes with the clique used to put their CPT.
void __collectChild(NodeId parent, NodeId child)
collect child clique for inferences
void __absorbClique(NodeId absorbedCliqueId, NodeId absorbingCliqueId)
Performs the operation of absorption of a clique by another.
InfluenceDiagramInference(const InfluenceDiagram< GUM_SCALAR > &infDiag)
Default constructor.
const NodeSet & clique(const NodeId idClique) const
returns the set of nodes included into a given clique
Potential< GUM_SCALAR > * __inferencePotential
The resulting potential from inference.
virtual ~InfluenceDiagramInference()
Destructor.
virtual void eraseAllEvidence()
NodeProperty< CliqueProperties< GUM_SCALAR > *> __cliquePropertiesMap
Mapping of the nodes with the clique used to put their CPT.
bool __inferenceMade
Mapping of the nodes with the clique used to put their CPT.
virtual const UndiGraph & triangulatedGraph()=0
returns the triangulated graph
void displayStrongJunctionTree(std::ostream &stream=std::cout)
Displays on terminal the result of strong junction tree computation for test purpose only...
std::size_t Size
In aGrUM, hashed values are unsigned long int.
virtual void insertEvidence(const List< const Potential< GUM_SCALAR > * > &evidenceList)
virtual const CliqueGraph & junctionTree()=0
returns a compatible junction tree
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
HashTable< NodeId, Idx > __utakenDecisionMap
Mapping of the nodes with the clique used to put their CPT.
const iterator & end() const noexcept
Returns the unsafe end iterator.
const NodeSet & __getSeparator(NodeId clique_1, NodeId clique_2)
virtual void eraseEvidence(const Potential< GUM_SCALAR > *evidence)
Potential< GUM_SCALAR > * __makeDummyUtility(NodeId cliqueId)
Returns a pointer over a "dummy" utility, which is a utility table filled with one MultiDimSparse fil...
virtual const std::vector< NodeId > & eliminationOrder()=0
returns an elimination ordering compatible with the triangulated graph
Size NodeId
Type for node ids.
void insert(const Key &k)
Inserts a new element into the set.
#define GUM_ERROR(type, msg)
void __makeStrongJunctionTree()
Makes a strong junction tree that make easier elimination.