37 #ifndef DOXYGEN_SHOULD_SKIP_THIS 45 template <
typename GUM_SCALAR >
47 const InfluenceDiagram< GUM_SCALAR >& infDiag) :
48 IInfluenceDiagramInference< GUM_SCALAR >(infDiag),
49 __triangulation(0), __inferencePotential(0), __inferenceUtility(0),
50 __inferenceMade(false) {
54 NodeProperty< Size > __modalitiesMap;
61 partialMoralGraph.eraseNode(node);
63 __modalitiesMap.insert(
68 const List< NodeSet >* partialTemporalOrder =
73 &partialMoralGraph, &__modalitiesMap, partialTemporalOrder);
81 template <
typename GUM_SCALAR >
99 template <
typename GUM_SCALAR >
118 template <
typename GUM_SCALAR >
121 GUM_ERROR(OperationNotAllowed,
"No inference have yet been made");
130 template <
typename GUM_SCALAR >
134 GUM_ERROR(OperationNotAllowed,
"No inference have yet been made");
137 GUM_ERROR(InvalidNode,
"Node is not a decision node");
143 template <
typename GUM_SCALAR >
145 std::stringstream stream;
148 GUM_ERROR(OperationNotAllowed,
"No inference have yet been made");
150 stream <<
"max EU : " << std::endl;
153 stream <<
"Best choices : " << std::endl;
165 template <
typename GUM_SCALAR >
167 const List<
const Potential< GUM_SCALAR >* >& evidenceList) {
168 for (
const auto ev : evidenceList)
176 template <
typename GUM_SCALAR >
178 const Potential< GUM_SCALAR >* evidence) {
179 if (!(evidence->variablesSequence().size() != 1))
181 evidence->variable(0))]]
182 ->removeEvidence(evidence->variable(0));
187 template <
typename GUM_SCALAR >
189 for (
const auto& elt : __cliquePropertiesMap)
190 elt.second->removeAllEvidence();
205 template <
typename GUM_SCALAR >
206 INLINE Triangulation&
213 template <
typename GUM_SCALAR >
224 template <
typename GUM_SCALAR >
226 const std::vector< NodeId >& eliminationOrder,
NodeId id) {
239 for (
size_t i = 0; i < eliminationOrder.size(); ++i)
240 if (idSet.contains(eliminationOrder[i]))
243 GUM_ERROR(FatalError,
"No clique found for node " <<
id);
250 template <
typename GUM_SCALAR >
256 NodeSet potentialsCliquesSet, utilitiesCliqueSet;
260 __cliquePropertiesMap.
insert(cli,
new CliqueProperties< GUM_SCALAR >());
262 potentialsCliquesSet.insert(cli);
263 utilitiesCliqueSet.insert(cli);
267 __cliquePropertiesMap[cli]->addVariable(
271 __cliquePropertiesMap[cli]->makeEliminationOrder(elim,
276 for (
size_t i = 0; i < elim.size(); i++) {
283 __cliquePropertiesMap[cliqueId]->addPotential(
285 potentialsCliquesSet.erase(cliqueId);
292 for (
const auto cliq : potentialsCliquesSet)
303 __cliquePropertiesMap[cliqueId]->addUtility(
305 utilitiesCliqueSet.erase(cliqueId);
309 for (
const auto cliq : utilitiesCliqueSet)
313 template <
typename GUM_SCALAR >
318 __cliquePropertiesMap[cli]->cliqueEliminationOrder();
319 SequenceIterator< NodeId > cliqueNodesIter = eliminationOrder.
begin();
320 bool validIndex =
false;
323 while (cliqueNodesIter != eliminationOrder.
end() && !validIndex) {
324 SequenceIterator< NodeId > cliqueRemainingNodesIter = cliqueNodesIter;
325 ++cliqueRemainingNodesIter;
327 if (cliqueRemainingNodesIter != eliminationOrder.
end()) {
329 *cliqueRemainingNodesIter));
331 while (cliqueRemainingNodesIter != eliminationOrder.
end()
332 && !suspectedNodes.empty()) {
333 NodeSet possiblesNodes(suspectedNodes);
335 for (
const auto possibleNode : possiblesNodes)
339 suspectedNodes.erase(possibleNode);
341 ++cliqueRemainingNodesIter;
344 if (!suspectedNodes.empty())
345 for (
const auto suspectedNode : suspectedNodes)
346 if (!eliminationOrder.
exists(suspectedNode)
353 if (!validIndex) ++cliqueNodesIter;
359 for (std::vector< NodeId >::const_iterator eliminationOrderIter =
362 && *eliminationOrderIter != *cliqueNodesIter;
363 ++eliminationOrderIter, ++index)
371 }
catch (Exception& e) {
throw(e); }
379 template <
typename GUM_SCALAR >
382 for (std::vector< NodeId >::const_iterator eliminationOrderIter =
385 ++eliminationOrderIter) {
386 if (*eliminationOrderIter == currentNode)
return true;
388 if (*eliminationOrderIter == observedNode)
return false;
396 template <
typename GUM_SCALAR >
398 std::ostream& stream) {
399 stream << std::endl <<
"Strong junction tree map : " << std::endl;
403 <<
" - Index : " << elt.first << std::endl;
406 template <
typename GUM_SCALAR >
418 for (
const auto& prop : __cliquePropertiesMap)
419 prop.second->cleanFromInference();
421 __utakenDecisionMap.clear();
426 template <
typename GUM_SCALAR >
436 template <
typename GUM_SCALAR >
440 CliqueProperties< GUM_SCALAR >* absorbedClique =
441 __cliquePropertiesMap[absorbedCliqueId];
447 Potential< GUM_SCALAR >* potentialMarginal = 0;
448 Potential< GUM_SCALAR >* utilityMarginal = 0;
460 __reduceClique(absorbedClique, separator, potentialMarginal, utilityMarginal);
464 __cliquePropertiesMap[absorbingCliqueId]->addPotential(*potentialMarginal,
468 Instantiation utilityMarginalInst(utilityMarginal);
470 for (utilityMarginalInst.setFirst(); !utilityMarginalInst.end();
471 utilityMarginalInst.inc()) {
472 GUM_SCALAR uVal = (GUM_SCALAR)0;
474 if (potentialMarginal->get(utilityMarginalInst) != (GUM_SCALAR)0)
475 uVal = utilityMarginal->get(utilityMarginalInst)
476 / potentialMarginal->get(utilityMarginalInst);
478 utilityMarginal->set(utilityMarginalInst, uVal);
482 __cliquePropertiesMap[absorbingCliqueId]->addUtility(*utilityMarginal,
true);
495 template <
typename GUM_SCALAR >
497 CliqueProperties< GUM_SCALAR >* absorbedClique,
499 Potential< GUM_SCALAR >*& potentialMarginal,
500 Potential< GUM_SCALAR >*& utilityMarginal) {
501 Instantiation cliqueInstance(absorbedClique->cliqueInstantiation());
502 Sequence< const DiscreteVariable* > cliqueRemainVarList(
503 cliqueInstance.variablesSequence());
506 for (
const auto node : absorbedClique->cliqueEliminationOrder()) {
508 if (!separator.contains(node)) {
512 Potential< GUM_SCALAR >* newPotential =
new Potential< GUM_SCALAR >();
513 Potential< GUM_SCALAR >* newUtility =
new Potential< GUM_SCALAR >();
520 for (
const auto remain : cliqueRemainVarList) {
521 newPotential->add(*remain);
522 newUtility->add(*remain);
531 Instantiation newInstantiation(newPotential);
539 for (newInstantiation.setFirst(); !newInstantiation.end();
540 newInstantiation.inc()) {
542 GUM_SCALAR potentialValue = (GUM_SCALAR)0;
543 GUM_SCALAR utilityValue = (GUM_SCALAR)0;
546 utilityValue = -1 * (std::numeric_limits< GUM_SCALAR >::max());
549 cliqueInstance.setVals(newInstantiation);
551 for (cliqueInstance.setFirstOut(newInstantiation); !cliqueInstance.end();
552 cliqueInstance.incOut(newInstantiation)) {
555 GUM_SCALAR currentPotential = (GUM_SCALAR)1;
557 if (potentialMarginal == 0) {
561 for (
const auto& pot : absorbedClique->potentialBucket()) {
562 pot.second->setVals(cliqueInstance);
563 currentPotential *= pot.first->get(*pot.second);
566 Instantiation potentialMarginalInst(potentialMarginal);
567 potentialMarginalInst.setVals(cliqueInstance);
568 currentPotential = potentialMarginal->get(potentialMarginalInst);
573 GUM_SCALAR currentUtility = (GUM_SCALAR)0;
575 if (utilityMarginal == 0) {
576 for (
const auto& uti : absorbedClique->utilityBucket()) {
577 uti.second->setVals(cliqueInstance);
578 currentUtility += uti.first->get(*uti.second);
581 currentUtility *= currentPotential;
583 Instantiation utilityMarginalInst(utilityMarginal);
584 utilityMarginalInst.setVals(cliqueInstance);
585 currentUtility = utilityMarginal->get(utilityMarginalInst);
590 if (potentialValue < currentPotential) {
591 potentialValue = currentPotential;
594 if (utilityValue < currentUtility) {
595 utilityValue = currentUtility;
597 if (__utakenDecisionMap.exists(node))
598 __utakenDecisionMap.erase(node);
600 __utakenDecisionMap.insert(
602 cliqueInstance.val(this->influenceDiagram().variable(node)));
605 potentialValue += currentPotential;
606 utilityValue += currentUtility;
612 newPotential->set(newInstantiation, potentialValue);
613 newUtility->set(newInstantiation, utilityValue);
618 if (potentialMarginal != 0)
delete potentialMarginal;
620 potentialMarginal = newPotential;
622 if (utilityMarginal != 0)
delete utilityMarginal;
624 utilityMarginal = newUtility;
635 template <
typename GUM_SCALAR >
636 INLINE Potential< GUM_SCALAR >*
639 Potential< GUM_SCALAR >* pot =
new Potential< GUM_SCALAR >(
640 new MultiDimSparse< GUM_SCALAR >((GUM_SCALAR)1));
641 __potentialDummies.insert(pot);
644 pot->add(this->influenceDiagram().variable(cliqueNode));
652 template <
typename GUM_SCALAR >
653 INLINE Potential< GUM_SCALAR >*
655 Potential< GUM_SCALAR >* ut =
new Potential< GUM_SCALAR >(
656 new MultiDimSparse< GUM_SCALAR >((GUM_SCALAR)0));
660 ut->add(this->influenceDiagram().variable(cliqueNode));
666 template <
typename GUM_SCALAR >
667 CliqueProperties< GUM_SCALAR >::CliqueProperties() {
668 GUM_CONSTRUCTOR(CliqueProperties);
672 template <
typename GUM_SCALAR >
673 CliqueProperties< GUM_SCALAR >::~CliqueProperties() {
674 GUM_DESTRUCTOR(CliqueProperties);
676 cleanFromInference();
679 for (
const auto& pot : __potentialBucket)
682 for (
const auto& uti : __utilityBucket)
687 template <
typename GUM_SCALAR >
688 void CliqueProperties< GUM_SCALAR >::addVariable(
const DiscreteVariable& v) {
690 __allVarsInst.add(v);
691 }
catch (DuplicateElement&) {
699 template <
typename GUM_SCALAR >
700 INLINE
const Sequence< const DiscreteVariable* >&
701 CliqueProperties< GUM_SCALAR >::cliqueVariables() {
702 return __allVarsInst.variablesSequence();
707 template <
typename GUM_SCALAR >
708 INLINE Instantiation& CliqueProperties< GUM_SCALAR >::cliqueInstantiation() {
709 return __allVarsInst;
716 template <
typename GUM_SCALAR >
717 void CliqueProperties< GUM_SCALAR >::addPotential(
718 const Potential< GUM_SCALAR >& cpt,
bool removable) {
719 __potentialBucket.insert(&cpt,
new Instantiation(cpt));
721 if (removable) __removablePotentialList.insert(&cpt);
723 const auto& vars = cpt.variablesSequence();
724 for (
auto iter = vars.beginSafe(); iter != vars.end(); ++iter) {
725 if (removable && !__allVarsInst.contains(**iter))
try {
726 __removableVarList.insert(*iter);
727 }
catch (DuplicateElement&) {
736 template <
typename GUM_SCALAR >
737 INLINE
const HashTable< const Potential< GUM_SCALAR >*, Instantiation* >&
738 CliqueProperties< GUM_SCALAR >::potentialBucket() {
739 return __potentialBucket;
746 template <
typename GUM_SCALAR >
748 CliqueProperties< GUM_SCALAR >::addUtility(
const Potential< GUM_SCALAR >& ut,
750 __utilityBucket.insert(&ut,
new Instantiation(ut));
752 if (removable) __removableUtilityList.insert(&ut);
754 for (
auto var : ut.variablesSequence()) {
755 if (removable && !__allVarsInst.contains(*var))
try {
756 __removableVarList.insert(var);
757 }
catch (DuplicateElement&) {
766 template <
typename GUM_SCALAR >
767 INLINE
const HashTable< const Potential< GUM_SCALAR >*, Instantiation* >&
768 CliqueProperties< GUM_SCALAR >::utilityBucket() {
769 return __utilityBucket;
777 template <
typename GUM_SCALAR >
778 void CliqueProperties< GUM_SCALAR >::cleanFromInference() {
782 for (
const auto removableVar : __removableVarList)
783 __allVarsInst.erase(*removableVar);
786 for (
const auto removablePot : __removablePotentialList) {
787 delete __potentialBucket[removablePot];
788 __potentialBucket.erase(removablePot);
793 for (
const auto removabledUt : __removableUtilityList) {
794 delete __utilityBucket[removabledUt];
795 __utilityBucket.erase(removabledUt);
799 __removableVarList.clear();
800 __removablePotentialList.clear();
801 __removableUtilityList.clear();
808 template <
typename GUM_SCALAR >
809 void CliqueProperties< GUM_SCALAR >::makeEliminationOrder(
810 const std::vector< NodeId >& elim,
811 const InfluenceDiagram< GUM_SCALAR >& infDiag) {
812 for (
size_t i = 0; i < elim.size(); i++) {
813 if (__allVarsInst.contains(infDiag.variable(elim[i])))
814 __eliminationOrder.insert(elim[i]);
819 template <
typename GUM_SCALAR >
821 CliqueProperties< GUM_SCALAR >::cliqueEliminationOrder() {
822 return __eliminationOrder;
832 template <
typename GUM_SCALAR >
833 void CliqueProperties< GUM_SCALAR >::addEvidence(
834 const Potential< GUM_SCALAR >& evidence) {
836 cleanFromInference();
839 if (evidence.variablesSequence().size() != 1) {
841 "expected evidence on 1 variable, found on " 842 << evidence.variablesSequence().size());
846 if (!__allVarsInst.contains(evidence.variablesSequence().atPos(0))) {
848 evidence.variablesSequence().atPos(0)->name()
849 <<
" not found in clique ");
852 __evidences.insert(evidence.variablesSequence().atPos(0), &evidence);
854 __potentialBucket.insert(&evidence,
new Instantiation(evidence));
858 template <
typename GUM_SCALAR >
860 HashTable< const DiscreteVariable*, const Potential< GUM_SCALAR >* >&
861 CliqueProperties< GUM_SCALAR >::evidences()
const {
866 template <
typename GUM_SCALAR >
868 CliqueProperties< GUM_SCALAR >::removeEvidence(
const DiscreteVariable& v) {
869 const Potential< GUM_SCALAR >* evi = __evidences[&v];
871 delete __potentialBucket[evi];
872 __potentialBucket.erase(evi);
873 __evidences.erase(&v);
877 template <
typename GUM_SCALAR >
878 INLINE
void CliqueProperties< GUM_SCALAR >::removeAllEvidence() {
879 for (
const auto& elt : __evidences)
880 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.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
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...
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
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.