aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
ShaferShenoyInference.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /**
23  * @file
24  * @brief Implementation of Shafer-Shenoy's algorithm for inference
25  * in Bayesian networks.
26  */
27 #ifndef GUM_SHAFER_SHENOY_INFERENCE_H
28 #define GUM_SHAFER_SHENOY_INFERENCE_H
29 
30 #include <utility>
31 
32 #include <agrum/tools/core/math/math_utils.h>
33 #include <agrum/BN/algorithms/barrenNodesFinder.h>
34 #include <agrum/BN/inference/tools/evidenceInference.h>
35 #include <agrum/BN/inference/tools/jointTargetedInference.h>
36 #include <agrum/agrum.h>
37 #include <agrum/tools/graphs/algorithms/triangulations/defaultTriangulation.h>
38 
39 namespace gum {
40 
41 
42  // the function used to combine two tables
43  template < typename GUM_SCALAR >
45  const Potential< GUM_SCALAR >& t2) {
46  return new Potential< GUM_SCALAR >(t1 * t2);
47  }
48 
49  // the function used to combine two tables
50  template < typename GUM_SCALAR >
51  INLINE static Potential< GUM_SCALAR >*
53  const Set< const DiscreteVariable* >& del_vars) {
54  return new Potential< GUM_SCALAR >(t1.margSumOut(del_vars));
55  }
56 
57 
58  /**
59  * @class ShaferShenoyInference ShaferShenoyInference.h
60  * <agrum/BN/inference/ShaferShenoyInference.h>
61  * @brief Implementation of Shafer-Shenoy's propagation algorithm
62  * for inference in Bayesian networks
63  * @ingroup bn_inference
64  */
65  template < typename GUM_SCALAR >
68  public EvidenceInference< GUM_SCALAR > {
69  public:
70  // ############################################################################
71  /// @name Constructors / Destructors
72  // ############################################################################
73  /// @{
74 
75  /// default constructor
76  explicit ShaferShenoyInference(const IBayesNet< GUM_SCALAR >* BN,
79  bool use_binary_join_tree = true);
80 
81  /// destructor
83 
84  /// @}
85 
86 
87  // ############################################################################
88  /// @name Accessors / Modifiers
89  // ############################################################################
90  /// @{
91 
92  /// use a new triangulation algorithm
94 
95  /// sets how we determine barren nodes
96  /** Barren nodes are unnecessary for probability inference, so they can
97  * be safely discarded in this case (type = FIND_BARREN_NODES). This
98  * speeds-up inference. However, there are some cases in which we do not
99  * want to remove barren nodes, typically when we want to answer queries
100  * such as Most Probable Explanations (MPE). */
102 
103  /// returns the current join tree used
104  /** Lazy Propagation does not use a junction tree but a binary join tree
105  * because this may enable faster inferences. So do not be surprised to
106  * see that somes cliques are contained into others in this tree. */
107  const JoinTree* joinTree();
108 
109  /// returns the current junction tree
110  /** Lazy Propagation does not use a junction tree but a binary join tree
111  * because this may enable faster inferences. This method return the junction
112  * tree, before optimizations
113  **/
114  const JunctionTree* junctionTree();
115 
116  /// returns the probability of evidence
118 
119  /// @}
120 
121 
122  protected:
123  /// fired when the stage is changed
125 
126  /// fired after a new evidence is inserted
127  void onEvidenceAdded_(const NodeId id, bool isHardEvidence) final;
128 
129  /// fired before an evidence is removed
130  void onEvidenceErased_(const NodeId id, bool isHardEvidence) final;
131 
132  /// fired before all the evidence are erased
134 
135  /** @brief fired after an evidence is changed, in particular when its status
136  * (soft/hard) changes
137  *
138  * @param nodeId the node of the changed evidence
139  * @param hasChangedSoftHard true if the evidence has changed from Soft to
140  * Hard or from Hard to Soft
141  */
143 
144  /// fired after a new single target is inserted
145  /** @param id The target variable's id. */
147 
148  /// fired before a single target is removed
149  /** @param id The target variable's id. */
151 
152  /// fired after a new Bayes net has been assigned to the engine
153  virtual void onModelChanged_(const GraphicalModel* bn) final;
154 
155  /// fired after a new joint target is inserted
156  /** @param set The set of target variable's ids. */
157  void onJointTargetAdded_(const NodeSet& set) final;
158 
159  /// fired before a joint target is removed
160  /** @param set The set of target variable's ids. */
161  void onJointTargetErased_(const NodeSet& set) final;
162 
163  /// fired after all the nodes of the BN are added as single targets
165 
166  /// fired before a all the single targets are removed
168 
169  /// fired before a all the joint targets are removed
171 
172  /// fired before a all single and joint_targets are removed
173  void onAllTargetsErased_() final;
174 
175  /// prepares inference when the latter is in OutdatedStructure state
176  /** Note that the values of evidence are not necessarily
177  * known and can be changed between updateOutdatedStructure_ and
178  * makeInference_. */
180 
181  /// prepares inference when the latter is in OutdatedPotentials state
182  /** Note that the values of evidence are not necessarily
183  * known and can be changed between updateOutdatedStructure_ and
184  * makeInference_. */
186 
187  /// called when the inference has to be performed effectively
188  /** Once the inference is done, fillPosterior_ can be called. */
189  void makeInference_() final;
190 
191 
192  /// returns the posterior of a given variable
193  /** @param id The variable's id. */
195 
196  /// returns the posterior of a declared target set
197  /** @param set The set of ids of the variables whose joint posterior is
198  * looked for. */
200 
201  /** @brief asks derived classes for the joint posterior of a set of
202  * variables not declared as a joint target
203  *
204  * @param wanted_target The set of ids of the variables whose joint
205  * posterior is looked for.
206  * @param declared_target the joint target declared by the user that
207  * contains set */
209  const NodeSet& declared_target) final;
210 
211  /// returns a fresh potential equal to P(argument,evidence)
213 
214  /// returns a fresh potential equal to P(argument,evidence)
216 
217 
218  private:
219  typedef Set< const Potential< GUM_SCALAR >* > _PotentialSet_;
221 
222 
223  /// the type of barren nodes computation we wish
225 
226  /// the operator for performing the projections
228  const Set< const DiscreteVariable* >&){
230 
231  /// the operator for performing the combinations
233  const Potential< GUM_SCALAR >&){
235 
236  /// the triangulation class creating the junction tree used for inference
238 
239  /** @brief indicates whether we should transform junction trees into
240  * binary join trees */
242 
243  /// the undigraph extracted from the BN and used to construct the join tree
244  /** If all nodes are targets, this graph corresponds to the moral graph
245  * of the BN. Otherwise, it may be a subgraph of this moral graph. For
246  * instance if the BN is A->B->C and only B is a target, _graph_ will be
247  * equal to A-B if we exploit barren nodes (C is a barren node and,
248  * therefore, can be removed for inference). */
250 
251  /// the join (or junction) tree used to answer the last inference query
252  JoinTree* _JT_{nullptr};
253 
254  /// the junction tree to answer the last inference query
256 
257  /// indicates whether a new join tree is needed for the next inference
258  /** when modifying the set of hard evidence, we can determine that
259  * the current JT is no more appropriate for inference. This variable
260  * enables us to keep track of this. */
261  bool _is_new_jt_needed_{true};
262 
263  /// a clique node used as a root in each connected component of _JT_
264  /** For usual probabilistic inference, roots is useless. This is useful
265  * when computing the probability of evidence. In this case, we need to
266  * compute this probability in every connected component and multiply
267  * them to get the overall probability of evidence.
268  * @warning _roots_ should be computed only when evidenceProbability
269  * is called. */
271 
272  /// for each node of _graph_ (~ in the Bayes net), associate an ID in the JT
274 
275  /// for each set target, assign a clique in the JT that contains it
277 
278  /// the list of all potentials stored in the cliques
279  /** This structure contains a list for each clique in the join tree. If
280  * a clique did not received any potential, then its list is empty but
281  * the entry for the clique does exist. Note that clique potentials
282  * contain also soft evidence and the CPTs that were projected to
283  * remove their variables that received hard evidence. The product of all
284  * these potentials is precisely the potential stored into
285  * _clique_ss_potential_ */
287 
288  /// the potentials stored into the cliques by Shafer-Shenoy
289  /** For a given clique, there is an entry in _clique_ss_potential_ if and
290  * only if the clique received some potential(s). In this case, the
291  * potential stored is the combination of all the corresponding list of
292  * potentials in _clique_potentials_. */
294 
295  /// the list of all potentials stored in the separators after inferences
296  /** This structure contains all the arcs of the join tree (edges in both
297  * directions) whether the arc received any potential or not. */
299 
300  /// the set of potentials created for the last inference messages
301  /** This structure contains only the arcs on which potentials have
302  * been created.
303  * @warning Note that the CPTs that were projected due to hard
304  * evidence do not belong to this structure, they are kept in
305  * _hard_ev_projected_CPTs_. */
307 
308  /// the set of single posteriors computed during the last inference
309  /** the posteriors are owned by ShaferShenoyInference. */
311 
312  /// the set of set target posteriors computed during the last inference
313  /** the posteriors are owned by ShaferShenoyInference. */
315 
316  /** @brief the constants resulting from the projections of CPTs defined
317  * over only hard evidence nodes
318  * @TODO remove this constant and insert the notion of a constant into
319  * potentials/multidim arrays */
321 
322  /// indicates whether a message (from one clique to another) has been
323  /// computed
324  /** Here, all the messages, computed or not, are put into the property, only
325  * the Boolean makes the difference between messages computed and those that
326  * were not computed */
328 
329  /// the soft evidence stored in the cliques per their assigned node in the BN
330  /** This variable is useful for method updateOutdatedPotentials_: it
331  * enables to know which soft evidence should be removed/added into the
332  * cliques of the join tree.
333  * @warning These potentials are not owned by ShaferShenoyInference,
334  * they are only referenced by it. Only the cliques that contain evidence
335  * are filled in this structure. */
337 
338  /// the CPTs that were projected due to hard evidence nodes
339  /** For each node whose CPT is defined over some nodes that contain some
340  * hard evidence, assigns a new projected CPT that does not contain
341  * these nodes anymore.
342  * @warning These potentials are owned by LayPropagation. */
344 
345  /// the hard evidence nodes which were projected in CPTs
347 
348  /// the possible types of evidence changes
350  {
354  };
355 
356  /** @brief indicates which nodes of the BN have evidence that changed
357  * since the last inference */
359 
360  /// for comparisons with 1 - epsilon
362 
363 
364  /// check whether a new join tree is really needed for the next inference
365  bool _isNewJTNeeded_() const;
366 
367  /// create a new junction tree as well as its related data structures
368  void _createNewJT_();
369  /// sets the operator for performing the projections
371  *proj)(const Potential< GUM_SCALAR >&, const Set< const DiscreteVariable* >&));
372 
373  /// sets the operator for performing the combinations
375  const Potential< GUM_SCALAR >&));
376 
377  /// invalidate all the messages sent from a given clique
379 
380  /// invalidate all messages, posteriors and created potentials
382 
383  /// compute a root for each connected component of _JT_
384  void _computeJoinTreeRoots_();
385 
386  // remove barren variables and return the newly created projected potentials
388  Set< const DiscreteVariable* >& del_vars);
389 
390  /** @brief removes variables del_vars from a list of potentials and
391  * returns the resulting list */
393  Set< const DiscreteVariable* >& del_vars,
394  Set< const DiscreteVariable* >& kept_vars);
395 
396  /// creates the message sent by clique from_id to clique to_id
398 
399  /// actually perform the collect phase
401 
402  /// avoid copy constructors
404 
405  /// avoid copy operators
407  };
408 
409 
410 #ifndef GUM_NO_EXTERN_TEMPLATE_CLASS
411  extern template class ShaferShenoyInference< double >;
412 #endif
413 
414 
415 } /* namespace gum */
416 
417 #include <agrum/BN/inference/ShaferShenoyInference_tpl.h>
418 
419 #endif /* SHAFER_SHENOY_INFERENCE_H */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643