aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
lazyPropagation.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 a Shafer-Shenoy's-like version of lazy propagation
25  * for inference in Bayesian networks.
26  *
27  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
28  */
29 #ifndef GUM_LAZY_PROPAGATION_H
30 #define GUM_LAZY_PROPAGATION_H
31 
32 #include <utility>
33 
34 #include <agrum/tools/core/math/math_utils.h>
35 #include <agrum/BN/algorithms/barrenNodesFinder.h>
36 #include <agrum/BN/inference/tools/evidenceInference.h>
37 #include <agrum/BN/inference/tools/jointTargetedInference.h>
38 #include <agrum/BN/inference/tools/relevantPotentialsFinderType.h>
39 #include <agrum/agrum.h>
40 #include <agrum/tools/graphs/algorithms/triangulations/defaultTriangulation.h>
41 
42 namespace gum {
43 
44 
45  // the function used to combine two tables
46  template < typename GUM_SCALAR >
48  const Potential< GUM_SCALAR >& t2) {
49  return new Potential< GUM_SCALAR >(t1 * t2);
50  }
51 
52  // the function used to combine two tables
53  template < typename GUM_SCALAR >
54  INLINE static Potential< GUM_SCALAR >*
56  const Set< const DiscreteVariable* >& del_vars) {
57  return new Potential< GUM_SCALAR >(t1.margSumOut(del_vars));
58  }
59 
60 
61  /**
62  * @class LazyPropagation lazyPropagation.h
63  * <agrum/BN/inference/lazyPropagation.h>
64  * @brief Implementation of a Shafer-Shenoy's-like version of lazy
65  * propagation for inference in Bayesian networks
66  * @ingroup bn_inference
67  */
68  template < typename GUM_SCALAR >
71  public EvidenceInference< GUM_SCALAR > {
72  public:
73  // ############################################################################
74  /// @name Constructors / Destructors
75  // ############################################################################
76  /// @{
77 
78  /// default constructor
79  explicit LazyPropagation(const IBayesNet< GUM_SCALAR >* BN,
83  bool use_binary_join_tree = true);
84 
85  /// avoid copy constructors
86  LazyPropagation(const LazyPropagation< GUM_SCALAR >&) = delete;
87 
88  /// avoid copy operators
90 
91  /// destructor
93 
94  /// @}
95 
96 
97  // ############################################################################
98  /// @name Accessors / Modifiers
99  // ############################################################################
100  /// @{
101 
102  /// use a new triangulation algorithm
104 
105  /// sets how we determine the relevant potentials to combine
106  /** When a clique sends a message to a separator, it first constitute the
107  * set of the potentials it contains and of the potentials contained in the
108  * messages it received. If RelevantPotentialsFinderType = FIND_ALL,
109  * all these potentials are combined and projected to produce the message
110  * sent to the separator.
111  * If RelevantPotentialsFinderType = DSEP_BAYESBALL_NODES, then only the
112  * set of potentials d-connected to the variables of the separator are kept
113  * for combination and projection. */
115 
116  /// sets how we determine barren nodes
117  /** Barren nodes are unnecessary for probability inference, so they can
118  * be safely discarded in this case (type = FIND_BARREN_NODES). This
119  * speeds-up inference. However, there are some cases in which we do not
120  * want to remove barren nodes, typically when we want to answer queries
121  * such as Most Probable Explanations (MPE). */
123 
124 
125  /// returns the current join tree used
126  /** Lazy Propagation does not use a junction tree but a binary join tree
127  * because this may enable faster inferences. So do not be surprised to
128  * see that somes cliques are contained into others in this tree. */
129  const JoinTree* joinTree();
130 
131  /// returns the current junction tree
132  /** Lazy Propagation does not use a junction tree but a binary join tree
133  * because this may enable faster inferences. This method return the junction
134  * tree, before optimizations
135  **/
136  const JunctionTree* junctionTree();
137  /// returns the probability of evidence
139 
140  /// @}
141 
142 
143  protected:
144  /// fired after a new evidence is inserted
145  void onEvidenceAdded_(const NodeId id, bool isHardEvidence) final;
146 
147  /// fired before an evidence is removed
148  void onEvidenceErased_(const NodeId id, bool isHardEvidence) final;
149 
150  /// fired before all the evidence are erased
152 
153  /** @brief fired after an evidence is changed, in particular when its status
154  * (soft/hard) changes
155  *
156  * @param nodeId the node of the changed evidence
157  * @param hasChangedSoftHard true if the evidence has changed from Soft to
158  * Hard or from Hard to Soft
159  */
161 
162  /// fired after a new single target is inserted
163  /** @param id The target variable's id. */
165 
166  /// fired before a single target is removed
167  /** @param id The target variable's id. */
169 
170  /// fired after a new Bayes net has been assigned to the engine
171  virtual void onModelChanged_(const GraphicalModel* bn) final;
172 
173  /// fired after a new joint target is inserted
174  /** @param set The set of target variable's ids. */
175  void onJointTargetAdded_(const NodeSet& set) final;
176 
177  /// fired before a joint target is removed
178  /** @param set The set of target variable's ids. */
179  void onJointTargetErased_(const NodeSet& set) final;
180 
181  /// fired after all the nodes of the BN are added as single targets
183 
184  /// fired before a all the single targets are removed
186 
187  /// fired before a all the joint targets are removed
189 
190  /// fired before a all single and joint_targets are removed
191  void onAllTargetsErased_() final;
192 
193  /// fired when the stage is changed
195 
196  /// prepares inference when the latter is in OutdatedStructure state
197  /** Note that the values of evidence are not necessarily
198  * known and can be changed between updateOutdatedStructure_ and
199  * makeInference_. */
201 
202  /// prepares inference when the latter is in OutdatedPotentials state
203  /** Note that the values of evidence are not necessarily
204  * known and can be changed between updateOutdatedPotentials_ and
205  * makeInference_. */
207 
208  /// called when the inference has to be performed effectively
209  /** Once the inference is done, fillPosterior_ can be called. */
210  void makeInference_() final;
211 
212 
213  /// returns the posterior of a given variable
214  /** @param id The variable's id. */
216 
217  /// returns the posterior of a declared target set
218  /** @param set The set of ids of the variables whose joint posterior is
219  * looked for. */
221 
222  /** @brief asks derived classes for the joint posterior of a set of
223  * variables not declared as a joint target
224  *
225  * @param wanted_target The set of ids of the variables whose joint
226  * posterior is looked for.
227  * @param declared_target the joint target declared by the user that contains
228  * set */
230  const NodeSet& declared_target) final;
231 
232  /// returns a fresh potential equal to P(argument,evidence)
234 
235  /// returns a fresh potential equal to P(argument,evidence)
237 
238 
239  private:
240  typedef Set< const Potential< GUM_SCALAR >* > _PotentialSet_;
242 
243 
244  /// the type of relevant potential finding algorithm to be used
246 
247  /** @brief update a set of potentials: the remaining are those to be
248  * combined to produce a message on a separator */
250  Set< const Potential< GUM_SCALAR >* >& pot_list,
251  Set< const DiscreteVariable* >& kept_vars);
252 
253  /// the type of barren nodes computation we wish
255 
256  /// the operator for performing the projections
258  const Set< const DiscreteVariable* >&){
260 
261  /// the operator for performing the combinations
263  const Potential< GUM_SCALAR >&){
265 
266  /// the triangulation class creating the junction tree used for inference
268 
269  /** @brief indicates whether we should transform junction trees into
270  * binary join trees */
272 
273  /// the undigraph extracted from the BN and used to construct the join tree
274  /** If all nodes are targets, this graph corresponds to the moral graph
275  * of the BN. Otherwise, it may be a subgraph of this moral graph. For
276  * instance if the BN is A->B->C and only B is a target, _graph_ will be
277  * equal to A-B if we exploit barren nodes (C is a barren node and,
278  * therefore, can be removed for inference). */
280 
281  /// the join (or junction) tree used to answer the last inference query
282  JoinTree* _JT_{nullptr};
283 
284  /// the junction tree to answer the last inference query
286 
287  /// indicates whether a new join tree is needed for the next inference
288  /** when modifying the set of hard evidence, we can determine that
289  * the current JT is no more appropriate for inference. This variable
290  * enables us to keep track of this. */
291  bool _is_new_jt_needed_{true};
292 
293  /// a clique node used as a root in each connected component of _JT_
294  /** For usual probabilistic inference, roots is useless. This is useful
295  * when computing the probability of evidence. In this case, we need to
296  * compute this probability in every connected component and multiply
297  * them to get the overall probability of evidence.
298  * @warning _roots_ should be computed only when evidenceProbability
299  * is called. */
301 
302  /// for each node of _graph_ (~ in the Bayes net), associate an ID in the JT
304 
305  /// for each set target, assign a clique in the JT that contains it
307 
308  /// the list of all potentials stored in the cliques
309  /** This structure contains a list for each clique in the join tree. If
310  * a clique did not received any potential, then its list is empty but
311  * the entry for the clique does exist. Note that clique potentials
312  * contain also soft evidence and the CPTs that were projected to
313  * remove their variables that received hard evidence. */
315 
316  /// the list of all potentials stored in the separators after inferences
317  /** This structure contains all the arcs of the join tree (edges in both
318  * directions) whether the arc received any potential or not. */
320 
321  /// the set of potentials created for the last inference messages
322  /** This structure contains only the arcs on which potentials have
323  * been created.
324  * @warning Note that the CPTs that were projected due to hard
325  * evidence do not belong to this structure, they are kept in
326  * _hard_ev_projected_CPTs_. */
328 
329  /// the set of single posteriors computed during the last inference
330  /** the posteriors are owned by LazyPropagation. */
332 
333  /// the set of set target posteriors computed during the last inference
334  /** the posteriors are owned by LazyPropagation. */
336 
337  /** @brief the constants resulting from the projections of CPTs defined
338  * over only hard evidence nodes
339  * @TODO remove this constant and insert the notion of a constant into
340  * potentials/multidim arrays */
342 
343  /// indicates whether a message (from one clique to another) has been
344  /// computed
345  /** Here, all the messages, computed or not, are put into the property, only
346  * the Boolean makes the difference between messages computed and those that
347  * were not computed */
349 
350  /// the soft evidence stored in the cliques per their assigned node in the BN
351  /** This variable is useful for method updateOutdatedPotentials_: it
352  * enables to know which soft evidence should be removed/added into the
353  * cliques of the join tree.
354  * @warning These potentials are not owned by LazyPropagation, they are only
355  * referenced by it. Only the cliques that contain evidence are
356  * filled in this structure. */
358 
359  /// the CPTs that were projected due to hard evidence nodes
360  /** For each node whose CPT is defined over some nodes that contain some
361  * hard evidence, assigns a new projected CPT that does not contain
362  * these nodes anymore.
363  * @warning These potentials are owned by LayPropagation. */
365 
366  /// the hard evidence nodes which were projected in CPTs
368 
369  /// the possible types of evidence changes
371  {
375  };
376 
377  /** @brief indicates which nodes of the BN have evidence that changed
378  * since the last inference */
380 
381  /// for comparisons with 1 - epsilon
383 
384 
385  /// check whether a new join tree is really needed for the next inference
386  bool _isNewJTNeeded_() const;
387 
388  /// create a new junction tree as well as its related data structures
389  void _createNewJT_();
390  /// sets the operator for performing the projections
392  *proj)(const Potential< GUM_SCALAR >&, const Set< const DiscreteVariable* >&));
393 
394  /// sets the operator for performing the combinations
396  const Potential< GUM_SCALAR >&));
397 
398  /// invalidate all the messages sent from a given clique
400 
401  /// invalidate all messages, posteriors and created potentials
403 
404  /// compute a root for each connected component of _JT_
405  void _computeJoinTreeRoots_();
406 
407  /** @brief update a set of potentials: the remaining are those to be
408  * combined
409  * to produce a message on a separator */
411  Set< const DiscreteVariable* >& kept_vars);
412 
413  /** @brief update a set of potentials: the remaining are those to be
414  * combined
415  * to produce a message on a separator */
417  Set< const DiscreteVariable* >& kept_vars);
418 
419  /** @brief update a set of potentials: the remaining are those to be
420  * combined
421  * to produce a message on a separator */
423  Set< const DiscreteVariable* >& kept_vars);
424 
425  /** @brief update a set of potentials: the remaining are those to be
426  * combined
427  * to produce a message on a separator */
429  Set< const DiscreteVariable* >& kept_vars);
430 
431  /** @brief update a set of potentials: the remaining are those to be
432  * combined
433  * to produce a message on a separator */
435  Set< const DiscreteVariable* >& kept_vars);
436 
437  // remove barren variables and return the newly created projected potentials
439  Set< const DiscreteVariable* >& del_vars);
440 
441  /** @brief removes variables del_vars from a list of potentials and
442  * returns the resulting list */
444  Set< const DiscreteVariable* >& del_vars,
445  Set< const DiscreteVariable* >& kept_vars);
446 
447  /// creates the message sent by clique from_id to clique to_id
449 
450  /// actually perform the collect phase
452  };
453 
454 
455 #ifndef GUM_NO_EXTERN_TEMPLATE_CLASS
456  extern template class LazyPropagation< double >;
457 #endif
458 
459 
460 } /* namespace gum */
461 
462 #include <agrum/BN/inference/lazyPropagation_tpl.h>
463 
464 #endif /* GUM_LAZY_PROPAGATION_H */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643