aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
lazyPropagation.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 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 >
47  INLINE static Potential< GUM_SCALAR >*
49  const Potential< GUM_SCALAR >& t2) {
50  return new Potential< GUM_SCALAR >(t1 * t2);
51  }
52 
53  // the function used to combine two tables
54  template < typename GUM_SCALAR >
55  INLINE static Potential< GUM_SCALAR >*
57  const Set< const DiscreteVariable* >& del_vars) {
58  return new Potential< GUM_SCALAR >(t1.margSumOut(del_vars));
59  }
60 
61 
62  /**
63  * @class LazyPropagation lazyPropagation.h
64  * <agrum/BN/inference/lazyPropagation.h>
65  * @brief Implementation of a Shafer-Shenoy's-like version of lazy
66  * propagation for inference in Bayesian networks
67  * @ingroup bn_inference
68  */
69  template < typename GUM_SCALAR >
72  public EvidenceInference< GUM_SCALAR > {
73  public:
74  // ############################################################################
75  /// @name Constructors / Destructors
76  // ############################################################################
77  /// @{
78 
79  /// default constructor
80  explicit LazyPropagation(
81  const IBayesNet< GUM_SCALAR >* BN,
85  bool use_binary_join_tree = true);
86 
87  /// avoid copy constructors
88  LazyPropagation(const LazyPropagation< GUM_SCALAR >&) = delete;
89 
90  /// avoid copy operators
92  = delete;
93 
94  /// destructor
96 
97  /// @}
98 
99 
100  // ############################################################################
101  /// @name Accessors / Modifiers
102  // ############################################################################
103  /// @{
104 
105  /// use a new triangulation algorithm
107 
108  /// sets how we determine the relevant potentials to combine
109  /** When a clique sends a message to a separator, it first constitute the
110  * set of the potentials it contains and of the potentials contained in the
111  * messages it received. If RelevantPotentialsFinderType = FIND_ALL,
112  * all these potentials are combined and projected to produce the message
113  * sent to the separator.
114  * If RelevantPotentialsFinderType = DSEP_BAYESBALL_NODES, then only the
115  * set of potentials d-connected to the variables of the separator are kept
116  * for combination and projection. */
118 
119  /// sets how we determine barren nodes
120  /** Barren nodes are unnecessary for probability inference, so they can
121  * be safely discarded in this case (type = FIND_BARREN_NODES). This
122  * speeds-up inference. However, there are some cases in which we do not
123  * want to remove barren nodes, typically when we want to answer queries
124  * such as Most Probable Explanations (MPE). */
126 
127 
128  /// returns the current join tree used
129  /** Lazy Propagation does not use a junction tree but a binary join tree
130  * because this may enable faster inferences. So do not be surprised to
131  * see that somes cliques are contained into others in this tree. */
132  const JoinTree* joinTree();
133 
134  /// returns the current junction tree
135  /** Lazy Propagation does not use a junction tree but a binary join tree
136  * because this may enable faster inferences. This method return the junction
137  * tree, before optimizations
138  **/
139  const JunctionTree* junctionTree();
140  /// returns the probability of evidence
142 
143  /// @}
144 
145 
146  protected:
147  /// fired after a new evidence is inserted
148  void onEvidenceAdded_(const NodeId id, bool isHardEvidence) final;
149 
150  /// fired before an evidence is removed
151  void onEvidenceErased_(const NodeId id, bool isHardEvidence) final;
152 
153  /// fired before all the evidence are erased
155 
156  /** @brief fired after an evidence is changed, in particular when its status
157  * (soft/hard) changes
158  *
159  * @param nodeId the node of the changed evidence
160  * @param hasChangedSoftHard true if the evidence has changed from Soft to
161  * Hard or from Hard to Soft
162  */
164 
165  /// fired after a new single target is inserted
166  /** @param id The target variable's id. */
168 
169  /// fired before a single target is removed
170  /** @param id The target variable's id. */
172 
173  /// fired after a new Bayes net has been assigned to the engine
174  virtual void onModelChanged_(const GraphicalModel* bn) final;
175 
176  /// fired after a new joint target is inserted
177  /** @param set The set of target variable's ids. */
178  void onJointTargetAdded_(const NodeSet& set) final;
179 
180  /// fired before a joint target is removed
181  /** @param set The set of target variable's ids. */
182  void onJointTargetErased_(const NodeSet& set) final;
183 
184  /// fired after all the nodes of the BN are added as single targets
186 
187  /// fired before a all the single targets are removed
189 
190  /// fired before a all the joint targets are removed
192 
193  /// fired before a all single and joint_targets are removed
194  void onAllTargetsErased_() final;
195 
196  /// fired when the stage is changed
198 
199  /// prepares inference when the latter is in OutdatedStructure state
200  /** Note that the values of evidence are not necessarily
201  * known and can be changed between updateOutdatedStructure_ and
202  * makeInference_. */
204 
205  /// prepares inference when the latter is in OutdatedPotentials state
206  /** Note that the values of evidence are not necessarily
207  * known and can be changed between updateOutdatedPotentials_ and
208  * makeInference_. */
210 
211  /// called when the inference has to be performed effectively
212  /** Once the inference is done, fillPosterior_ can be called. */
213  void makeInference_() final;
214 
215 
216  /// returns the posterior of a given variable
217  /** @param id The variable's id. */
219 
220  /// returns the posterior of a declared target set
221  /** @param set The set of ids of the variables whose joint posterior is
222  * looked for. */
224 
225  /** @brief asks derived classes for the joint posterior of a set of
226  * variables not declared as a joint target
227  *
228  * @param wanted_target The set of ids of the variables whose joint
229  * posterior is looked for.
230  * @param declared_target the joint target declared by the user that contains
231  * set */
232  const Potential< GUM_SCALAR >&
234  const NodeSet& declared_target) final;
235 
236  /// returns a fresh potential equal to P(argument,evidence)
238 
239  /// returns a fresh potential equal to P(argument,evidence)
241 
242 
243  private:
244  typedef Set< const Potential< GUM_SCALAR >* > PotentialSet__;
245  typedef SetIteratorSafe< const Potential< GUM_SCALAR >* >
247 
248 
249  /// the type of relevant potential finding algorithm to be used
251 
252  /** @brief update a set of potentials: the remaining are those to be
253  * combined to produce a message on a separator */
255  Set< const Potential< GUM_SCALAR >* >& pot_list,
256  Set< const DiscreteVariable* >& kept_vars);
257 
258  /// the type of barren nodes computation we wish
260 
261  /// the operator for performing the projections
263  const Potential< GUM_SCALAR >&,
264  const Set< const DiscreteVariable* >&){LPNewprojPotential};
265 
266  /// the operator for performing the combinations
268  const Potential< GUM_SCALAR >&){
270 
271  /// the triangulation class creating the junction tree used for inference
273 
274  /** @brief indicates whether we should transform junction trees into
275  * binary join trees */
277 
278  /// the undigraph extracted from the BN and used to construct the join tree
279  /** If all nodes are targets, this graph corresponds to the moral graph
280  * of the BN. Otherwise, it may be a subgraph of this moral graph. For
281  * instance if the BN is A->B->C and only B is a target, graph__ will be
282  * equal to A-B if we exploit barren nodes (C is a barren node and,
283  * therefore, can be removed for inference). */
285 
286  /// the join (or junction) tree used to answer the last inference query
287  JoinTree* JT__{nullptr};
288 
289  /// the junction tree to answer the last inference query
291 
292  /// indicates whether a new join tree is needed for the next inference
293  /** when modifying the set of hard evidence, we can determine that
294  * the current JT is no more appropriate for inference. This variable
295  * enables us to keep track of this. */
296  bool is_new_jt_needed__{true};
297 
298  /// a clique node used as a root in each connected component of JT__
299  /** For usual probabilistic inference, roots is useless. This is useful
300  * when computing the probability of evidence. In this case, we need to
301  * compute this probability in every connected component and multiply
302  * them to get the overall probability of evidence.
303  * @warning roots__ should be computed only when evidenceProbability
304  * is called. */
306 
307  /// for each node of graph__ (~ in the Bayes net), associate an ID in the JT
309 
310  /// for each set target, assign a clique in the JT that contains it
312 
313  /// the list of all potentials stored in the cliques
314  /** This structure contains a list for each clique in the join tree. If
315  * a clique did not received any potential, then its list is empty but
316  * the entry for the clique does exist. Note that clique potentials
317  * contain also soft evidence and the CPTs that were projected to
318  * remove their variables that received hard evidence. */
320 
321  /// the list of all potentials stored in the separators after inferences
322  /** This structure contains all the arcs of the join tree (edges in both
323  * directions) whether the arc received any potential or not. */
325 
326  /// the set of potentials created for the last inference messages
327  /** This structure contains only the arcs on which potentials have
328  * been created.
329  * @warning Note that the CPTs that were projected due to hard
330  * evidence do not belong to this structure, they are kept in
331  * hard_ev_projected_CPTs__. */
333 
334  /// the set of single posteriors computed during the last inference
335  /** the posteriors are owned by LazyPropagation. */
337 
338  /// the set of set target posteriors computed during the last inference
339  /** the posteriors are owned by LazyPropagation. */
341 
342  /** @brief the constants resulting from the projections of CPTs defined
343  * over only hard evidence nodes
344  * @TODO remove this constant and insert the notion of a constant into
345  * potentials/multidim arrays */
347 
348  /// indicates whether a message (from one clique to another) has been
349  /// computed
350  /** Here, all the messages, computed or not, are put into the property, only
351  * the Boolean makes the difference between messages computed and those that
352  * were not computed */
354 
355  /// the soft evidence stored in the cliques per their assigned node in the BN
356  /** This variable is useful for method updateOutdatedPotentials_: it
357  * enables to know which soft evidence should be removed/added into the
358  * cliques of the join tree.
359  * @warning These potentials are not owned by LazyPropagation, they are only
360  * referenced by it. Only the cliques that contain evidence are
361  * filled in this structure. */
363 
364  /// the CPTs that were projected due to hard evidence nodes
365  /** For each node whose CPT is defined over some nodes that contain some
366  * hard evidence, assigns a new projected CPT that does not contain
367  * these nodes anymore.
368  * @warning These potentials are owned by LayPropagation. */
370 
371  /// the hard evidence nodes which were projected in CPTs
373 
374  /// the possible types of evidence changes
376  {
380  };
381 
382  /** @brief indicates which nodes of the BN have evidence that changed
383  * since the last inference */
385 
386  /// for comparisons with 1 - epsilon
388 
389 
390  /// check whether a new join tree is really needed for the next inference
391  bool isNewJTNeeded__() const;
392 
393  /// create a new junction tree as well as its related data structures
394  void createNewJT__();
395  /// sets the operator for performing the projections
397  Potential< GUM_SCALAR >* (*proj)(const Potential< GUM_SCALAR >&,
398  const Set< const DiscreteVariable* >&));
399 
400  /// sets the operator for performing the combinations
402  *comb)(const Potential< GUM_SCALAR >&, const Potential< GUM_SCALAR >&));
403 
404  /// invalidate all the messages sent from a given clique
406  NodeId to_id,
408 
409  /// invalidate all messages, posteriors and created potentials
411 
412  /// compute a root for each connected component of JT__
413  void computeJoinTreeRoots__();
414 
415  /** @brief update a set of potentials: the remaining are those to be
416  * combined
417  * to produce a message on a separator */
420  Set< const DiscreteVariable* >& kept_vars);
421 
422  /** @brief update a set of potentials: the remaining are those to be
423  * combined
424  * to produce a message on a separator */
427  Set< const DiscreteVariable* >& kept_vars);
428 
429  /** @brief update a set of potentials: the remaining are those to be
430  * combined
431  * to produce a message on a separator */
434  Set< const DiscreteVariable* >& kept_vars);
435 
436  /** @brief update a set of potentials: the remaining are those to be
437  * combined
438  * to produce a message on a separator */
440  Set< const DiscreteVariable* >& kept_vars);
441 
442  /** @brief update a set of potentials: the remaining are those to be
443  * combined
444  * to produce a message on a separator */
446  Set< const DiscreteVariable* >& kept_vars);
447 
448  // remove barren variables and return the newly created projected potentials
451  Set< const DiscreteVariable* >& del_vars);
452 
453  /** @brief removes variables del_vars from a list of potentials and
454  * returns the resulting list */
456  Set< const DiscreteVariable* >& del_vars,
457  Set< const DiscreteVariable* >& kept_vars);
458 
459  /// creates the message sent by clique from_id to clique to_id
461 
462  /// actually perform the collect phase
464  };
465 
466 
467 #ifndef GUM_NO_EXTERN_TEMPLATE_CLASS
468  extern template class LazyPropagation< double >;
469 #endif
470 
471 
472 } /* namespace gum */
473 
474 #include <agrum/BN/inference/lazyPropagation_tpl.h>
475 
476 #endif /* GUM_LAZY_PROPAGATION_H */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669