aGrUM  0.16.0
jointTargetedInference_tpl.h
Go to the documentation of this file.
1 
30 
31 namespace gum {
32 
33 
34  // Default Constructor
35  template < typename GUM_SCALAR >
37  const IBayesNet< GUM_SCALAR >* bn) :
38  MarginalTargetedInference< GUM_SCALAR >(bn) {
39  // assign a BN if this has not been done before (due to virtual inheritance)
40  if (this->__bn == nullptr) {
42  }
43  GUM_CONSTRUCTOR(JointTargetedInference);
44  }
45 
46 
47  // Destructor
48  template < typename GUM_SCALAR >
50  GUM_DESTRUCTOR(JointTargetedInference);
51  }
52 
53 
54  // assigns a new BN to the inference engine
55  template < typename GUM_SCALAR >
57  const IBayesNet< GUM_SCALAR >* bn) {
60  __joint_targets.clear();
61  }
62 
63 
64  // ##############################################################################
65  // Targets
66  // ##############################################################################
67 
68  // return true if target is a nodeset target.
69  template < typename GUM_SCALAR >
71  const NodeSet& vars) const {
72  if (this->__bn == nullptr)
74  "No Bayes net has been assigned to the "
75  "inference algorithm");
76 
77  const auto& dag = this->__bn->dag();
78  for (const auto var : vars) {
79  if (!dag.exists(var)) {
80  GUM_ERROR(UndefinedElement, var << " is not a NodeId in the bn");
81  }
82  }
83 
84  return __joint_targets.contains(vars);
85  }
86 
87 
88  // Clear all previously defined single targets
89  template < typename GUM_SCALAR >
92  }
93 
94 
95  // Clear all previously defined targets (single targets and sets of targets)
96  template < typename GUM_SCALAR >
98  if (__joint_targets.size() > 0) {
99  // we already are in target mode. So no this->_setTargetedMode(); is needed
101  __joint_targets.clear();
102  this->__setState(
104  }
105  }
106 
107 
108  // Clear all previously defined targets (single and joint targets)
109  template < typename GUM_SCALAR >
113  }
114 
115 
116  // Add a set of nodes as a new target
117  template < typename GUM_SCALAR >
119  const NodeSet& joint_target) {
120  // check if the nodes in the target belong to the Bayesian network
121  if (this->__bn == nullptr)
123  "No Bayes net has been assigned to the "
124  "inference algorithm");
125 
126  const auto& dag = this->__bn->dag();
127  for (const auto node : joint_target) {
128  if (!dag.exists(node)) {
130  "at least one one in " << joint_target
131  << " does not belong to the bn");
132  }
133  }
134 
135  // check that the joint_target set does not contain the new target
136  if (__joint_targets.contains(joint_target)) return;
137 
138  // check if joint_target is a subset of an already existing target
139  for (const auto& target : __joint_targets) {
140  if (target.isSupersetOf(joint_target)) return;
141  }
142 
143  // check if joint_target is not a superset of an already existing target
144  // in this case, we need to remove old existing target
145  for (auto iter = __joint_targets.beginSafe();
146  iter != __joint_targets.endSafe();
147  ++iter) {
148  if (iter->isSubsetOf(joint_target)) eraseJointTarget(*iter);
149  }
150 
151  this->_setTargetedMode(); // does nothing if already in targeted mode
152  __joint_targets.insert(joint_target);
153  _onJointTargetAdded(joint_target);
154  this->__setState(
156  }
157 
158 
159  // removes an existing set target
160  template < typename GUM_SCALAR >
162  const NodeSet& joint_target) {
163  // check if the nodes in the target belong to the Bayesian network
164  if (this->__bn == nullptr)
166  "No Bayes net has been assigned to the "
167  "inference algorithm");
168 
169  const auto& dag = this->__bn->dag();
170  for (const auto node : joint_target) {
171  if (!dag.exists(node)) {
173  "at least one one in " << joint_target
174  << " does not belong to the bn");
175  }
176  }
177 
178  // check that the joint_target set does not contain the new target
179  if (__joint_targets.contains(joint_target)) {
180  // note that we have to be in target mode when we are here
181  // so, no this->_setTargetedMode(); is necessary
182  _onJointTargetErased(joint_target);
183  __joint_targets.erase(joint_target);
184  this->__setState(
186  }
187  }
188 
189 
191  template < typename GUM_SCALAR >
192  INLINE const Set< NodeSet >&
194  return __joint_targets;
195  }
196 
198  template < typename GUM_SCALAR >
200  noexcept {
201  return __joint_targets.size();
202  }
203 
204 
205  // ##############################################################################
206  // Inference
207  // ##############################################################################
208 
209  // Compute the posterior of a nodeset.
210  template < typename GUM_SCALAR >
213  // try to get the smallest set of targets that contains "nodes"
214  NodeSet set;
215  bool found_exact_target = false;
216 
217  if (__joint_targets.contains(nodes)) {
218  set = nodes;
219  found_exact_target = true;
220  } else {
221  for (const auto& target : __joint_targets) {
222  if (nodes.isSubsetOf(target)) {
223  set = target;
224  break;
225  }
226  }
227  }
228 
229  if (set.empty()) {
231  " no joint target containing " << nodes << " could be found among "
232  << __joint_targets);
233  }
234 
235  if (!this->isDone()) { this->makeInference(); }
236 
237  if (found_exact_target)
238  return _jointPosterior(nodes);
239  else
240  return _jointPosterior(nodes, set);
241  }
242 
243 
244  // Compute the posterior of a node
245  template < typename GUM_SCALAR >
248  if (this->isTarget(node))
250  else
251  return jointPosterior(NodeSet{node});
252  }
253 
254  // Compute the posterior of a node
255  template < typename GUM_SCALAR >
257  JointTargetedInference< GUM_SCALAR >::posterior(const std::string& nodeName) {
258  return posterior(this->BN().idFromName(nodeName));
259  }
260 
261  // ##############################################################################
262  // Entropy
263  // ##############################################################################
264 
265 
266  /* Mutual information between X and Y
267  * @see http://en.wikipedia.org/wiki/Mutual_information
268  *
269  * @warning Due to limitation of @joint, may not be able to compute this value
270  * @throw OperationNotAllowed in these cases
271  */
272  template < typename GUM_SCALAR >
274  Potential< GUM_SCALAR > pX, pY, *pXY = nullptr;
275  if (X == Y) {
276  GUM_ERROR(OperationNotAllowed, "Mutual Information I(X,Y) with X==Y");
277  }
278 
279  try {
280  // here use unnormalized joint posterior rather than just posterior
281  // to avoid saving the posterior in the cache of the inference engines
282  // like LazyPropagation or SahferShenoy.
283  pXY = this->_unnormalizedJointPosterior({X, Y});
284  pXY->normalize();
285  pX = pXY->margSumOut({&(this->BN().variable(Y))});
286  pY = pXY->margSumOut({&(this->BN().variable(X))});
287  } catch (...) {
288  if (pXY != nullptr) { delete pXY; }
289  throw;
290  }
291 
292  Instantiation i(*pXY);
293  auto res = (GUM_SCALAR)0;
294 
295  for (i.setFirst(); !i.end(); ++i) {
296  GUM_SCALAR vXY = (*pXY)[i];
297  GUM_SCALAR vX = pX[i];
298  GUM_SCALAR vY = pY[i];
299 
300  if (vXY > (GUM_SCALAR)0) {
301  if (vX == (GUM_SCALAR)0 || vY == (GUM_SCALAR)0) {
303  "Mutual Information (X,Y) with P(X)=0 or P(Y)=0 "
304  "and P(X,Y)>0");
305  }
306 
307  res += vXY * (log2(vXY) - log2(vX) - log2(vY));
308  }
309  }
310 
311  delete pXY;
312 
313  return res;
314  }
315 
316 
323  template < typename GUM_SCALAR >
325  return this->H(X) + this->H(Y) - 2 * I(X, Y);
326  }
327 
328 
329  template < typename GUM_SCALAR >
332  const NodeSet& targets, const NodeSet& evs) {
333  if (!(evs * targets).empty()) {
335  "Targets (" << targets << ") can not intersect evs (" << evs
336  << ").");
337  }
338  auto condset = this->BN().minimalCondSet(targets, evs);
339 
340  this->eraseAllTargets();
341  this->eraseAllEvidence();
342 
343  Instantiation iTarget;
345  for (const auto& target : targets) {
346  res.add(this->BN().variable(target));
347  iTarget.add(this->BN().variable(target));
348  }
349  this->addJointTarget(targets);
350 
351  for (const auto& n : condset) {
352  res.add(this->BN().variable(n));
353  this->addEvidence(n, 0);
354  }
355 
356  Instantiation inst(res);
357  for (inst.setFirstOut(iTarget); !inst.end(); inst.incOut(iTarget)) {
358  // inferring
359  for (const auto& n : condset)
360  this->chgEvidence(n, inst.val(this->BN().variable(n)));
361  this->makeInference();
362  // populate res
363  for (inst.setFirstIn(iTarget); !inst.end(); inst.incIn(iTarget)) {
364  res.set(inst, this->jointPosterior(targets)[inst]);
365  }
366  inst.setFirstIn(iTarget); // remove inst.end() flag
367  }
368 
369  return res;
370  }
371 
372  template < typename GUM_SCALAR >
375  const std::vector< std::string >& targets,
376  const std::vector< std::string >& evs) {
377  const auto& bn = this->BN();
378 
379  gum::NodeSet targetsId;
380  for (const auto& targetname : targets) {
381  targetsId.insert(bn.idFromName(targetname));
382  }
383 
384  gum::NodeSet evsId;
385  for (const auto& evname : evs) {
386  evsId.insert(bn.idFromName(evname));
387  }
388 
389  return evidenceJointImpact(targetsId, evsId);
390  }
391 
392 
393  template < typename GUM_SCALAR >
395  const NodeSet& targets) {
396  const auto& bn = this->BN();
397  const Size siz = targets.size();
398  if (siz <= 1) {
400  "jointMutualInformation needs at least 2 variables (targets="
401  << targets << ")");
402  }
403 
404  this->eraseAllTargets();
405  this->eraseAllEvidence();
406  this->addJointTarget(targets);
407  this->makeInference();
408  const auto po = this->jointPosterior(targets);
409 
410  gum::Instantiation caracteristic;
411  gum::Instantiation variables;
412  for (const auto nod : targets) {
413  const auto& var = bn.variable(nod);
414  auto pv = new gum::RangeVariable(var.name(), "", 0, 1);
415  caracteristic.add(*pv);
416  variables.add(var);
417  }
418 
420 
421  const GUM_SCALAR start = (siz % 2 == 0) ? GUM_SCALAR(-1.0) : GUM_SCALAR(1.0);
422  GUM_SCALAR sign;
423  GUM_SCALAR res = GUM_SCALAR(0.0);
424 
425  caracteristic.setFirst();
426  for (caracteristic.inc(); !caracteristic.end(); caracteristic.inc()) {
427  sov.clear();
428  sign = start;
429  for (Idx i = 0; i < caracteristic.nbrDim(); i++) {
430  if (caracteristic.val(i) == 1) {
431  sign = -sign;
432  sov.insert(&variables.variable(i));
433  }
434  }
435  res += sign * po.margSumIn(sov).entropy();
436  }
437 
438  for (Idx i = 0; i < caracteristic.nbrDim(); i++) {
439  delete &caracteristic.variable(i);
440  }
441 
442  return res;
443  }
444 
445  template < typename GUM_SCALAR >
447  const std::vector< std::string >& targets) {
448  const auto& bn = this->BN();
449 
450  gum::NodeSet targetsId;
451  for (const auto& targetname : targets) {
452  targetsId.insert(bn.idFromName(targetname));
453  }
454 
455  return jointMutualInformation(targetsId);
456  }
457 
458 } /* namespace gum */
void __setBayesNetDuringConstruction(const IBayesNet< GUM_SCALAR > *bn)
assigns a BN during the inference engine construction
virtual void eraseAllMarginalTargets() final
Clear all the previously defined marginal targets.
virtual void eraseAllTargets()
Clear all previously defined targets (marginal and joint targets)
aGrUM&#39;s Potential is a multi-dimensional array with tensor operators.
Definition: potential.h:60
virtual void addJointTarget(const NodeSet &joint_target) final
Add a set of nodes as a new joint target. As a collateral effect, every node is added as a marginal t...
virtual void __setState(const StateOfInference state) final
set the state of the inference engine and call the notification _onStateChanged when necessary (i...
virtual ~JointTargetedInference()
destructor
virtual void _onBayesNetChanged(const IBayesNet< GUM_SCALAR > *bn)
fired after a new Bayes net has been assigned to the engine
JointTargetedInference(const IBayesNet< GUM_SCALAR > *bn)
default constructor
GUM_SCALAR I(NodeId X, NodeId Y)
Mutual information between X and Y.
virtual GUM_SCALAR H(NodeId X) final
Entropy Compute Shanon&#39;s entropy of a node given the observation.
virtual void _onAllJointTargetsErased()=0
fired before a all the joint targets are removed
Idx nbrDim() const final
Returns the number of variables in the Instantiation.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
virtual bool isJointTarget(const NodeSet &vars) const final
return true if target is a joint target.
const Potential< GUM_SCALAR > & normalize() const
normalisation of this do nothing if sum is 0
bool isSubsetOf(const Set< Key, OtherAlloc > &s) const
const IBayesNet< GUM_SCALAR > * __bn
the Bayes net on which we perform inferences
virtual bool isTarget(NodeId node) const final
return true if variable is a (marginal) target
<agrum/BN/inference/marginalTargetedInference.h>
virtual Potential< GUM_SCALAR > * _unnormalizedJointPosterior(const NodeSet &set)=0
returns a fresh unnormalized joint posterior of a given set of variables
Class representing the minimal interface for Bayesian Network.
Definition: IBayesNet.h:62
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
virtual void _onJointTargetAdded(const NodeSet &set)=0
fired after a new joint target is inserted
virtual void eraseJointTarget(const NodeSet &joint_target) final
removes an existing joint target
Idx val(Idx i) const
Returns the current value of the variable at position i.
Representation of a setA Set is a structure that contains arbitrary elements.
Definition: set.h:165
virtual void makeInference() final
perform the heavy computations needed to compute the targets&#39; posteriors
void incOut(const Instantiation &i)
Operator increment for the variables not in i.
<agrum/BN/inference/BayesNetInference.h>
void setFirstIn(const Instantiation &i)
Assign the first values in the Instantiation for the variables in i.
void inc()
Operator increment.
virtual void chgEvidence(NodeId id, const Idx val) final
change the value of an already existing hard evidence
virtual bool isDone() const noexcept final
returns whether the inference object is in a done state
virtual void addEvidence(NodeId id, const Idx val) final
adds a new hard evidence on node id
virtual void eraseAllJointTargets() final
Clear all previously defined joint targets.
<agrum/BN/inference/jointTargetedInference.h>
virtual const Set< NodeSet > & jointTargets() const noexcept final
returns the list of joint targets
virtual void eraseAllEvidence() final
removes all the evidence entered into the network
virtual const Potential< GUM_SCALAR > & jointPosterior(const NodeSet &nodes) final
Compute the joint posterior of a set of nodes.
virtual const Potential< GUM_SCALAR > & posterior(NodeId node)
Computes and returns the posterior of a node.
Potential< GUM_SCALAR > evidenceJointImpact(const NodeSet &targets, const NodeSet &evs)
Create a gum::Potential for P(joint targets|evs) (for all instanciation of targets and evs) ...
virtual void _onBayesNetChanged(const IBayesNet< GUM_SCALAR > *bn)
fired after a new Bayes net has been assigned to the engine
Defines a discrete random variable over an integer interval.
Definition: rangeVariable.h:54
void incIn(const Instantiation &i)
Operator increment for the variables in i.
Potential< GUM_SCALAR > margSumOut(const Set< const DiscreteVariable * > &del_vars) const
Projection using sum as operation (and implementation-optimized operations)
Class for assigning/browsing values to tuples of discrete variables.
Definition: instantiation.h:83
virtual const Potential< GUM_SCALAR > & _jointPosterior(const NodeSet &set)=0
asks derived classes for the joint posterior of a declared target set
virtual void add(const DiscreteVariable &v) final
Adds a new var to the variables of the multidimensional matrix.
virtual const Potential< GUM_SCALAR > & posterior(NodeId node) final
Computes and returns the posterior of a node.
virtual void set(const Instantiation &i, const GUM_SCALAR &value) const final
Default implementation of MultiDimContainer::set().
void setFirst()
Assign the first values to the tuple of the Instantiation.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
virtual Size nbrJointTargets() const noexcept final
returns the number of joint targets
Size Idx
Type for indexes.
Definition: types.h:53
virtual const NodeSet & targets() const noexcept final
returns the list of marginal targets
GUM_SCALAR jointMutualInformation(const NodeSet &targets)
Mutual information between targets.
virtual void eraseAllTargets()
Clear all previously defined targets.
void add(const DiscreteVariable &v) final
Adds a new variable in the Instantiation.
void clear()
Removes all the elements, if any, from the set.
Definition: set_tpl.h:375
GUM_SCALAR VI(NodeId X, NodeId Y)
Variation of information between X and Y.
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
Size size() const noexcept
Returns the number of elements in the set.
Definition: set_tpl.h:701
virtual void _onJointTargetErased(const NodeSet &set)=0
fired before a joint target is removed
const DiscreteVariable & variable(Idx i) const final
Returns the variable at position i in the tuple.
Set< NodeSet > __joint_targets
the set of joint targets
virtual const IBayesNet< GUM_SCALAR > & BN() const final
Returns a constant reference over the IBayesNet referenced by this class.
Size NodeId
Type for node ids.
Definition: graphElements.h:98
void insert(const Key &k)
Inserts a new element into the set.
Definition: set_tpl.h:613
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55
bool end() const
Returns true if the Instantiation reached the end.
void setFirstOut(const Instantiation &i)
Assign the first values in the Instantiation for the variables not in i.