aGrUM
0.20.3
a C++ library for (probabilistic) graphical models
ShaferShenoyMNInference.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 Markov Networks.
26
*/
27
#
ifndef
GUM_SHAFER_SHENOY_MN_INFERENCE_H
28
#
define
GUM_SHAFER_SHENOY_MN_INFERENCE_H
29
30
#
include
<
utility
>
31
32
#
include
<
agrum
/
agrum
.
h
>
33
#
include
<
agrum
/
tools
/
core
/
math
/
math_utils
.
h
>
34
#
include
<
agrum
/
MN
/
inference
/
tools
/
evidenceMNInference
.
h
>
35
#
include
<
agrum
/
MN
/
inference
/
tools
/
jointTargetedMNInference
.
h
>
36
#
include
<
agrum
/
tools
/
graphs
/
algorithms
/
triangulations
/
defaultTriangulation
.
h
>
37
38
namespace
gum
{
39
40
41
// the function used to combine two tables
42
template
<
typename
GUM_SCALAR
>
43
INLINE
static
Potential
<
GUM_SCALAR
>*
SSNewMNmultiPotential
(
const
Potential
<
GUM_SCALAR
>&
t1
,
44
const
Potential
<
GUM_SCALAR
>&
t2
) {
45
return
new
Potential
<
GUM_SCALAR
>(
t1
*
t2
);
46
}
47
48
// the function used to combine two tables
49
template
<
typename
GUM_SCALAR
>
50
INLINE
static
Potential
<
GUM_SCALAR
>*
51
SSNewMNprojPotential
(
const
Potential
<
GUM_SCALAR
>&
t1
,
52
const
Set
<
const
DiscreteVariable
* >&
del_vars
) {
53
return
new
Potential
<
GUM_SCALAR
>(
t1
.
margSumOut
(
del_vars
));
54
}
55
56
57
/**
58
* @class ShaferShenoyMNInference ShaferShenoyMNInference.h
59
* <agrum/MN/inference/ShaferShenoyMNInference.h>
60
* @brief Implementation of Shafer-Shenoy's propagation algorithm
61
* for inference in Markov Networks
62
* @ingroup mn_inference
63
*/
64
template
<
typename
GUM_SCALAR
>
65
class
ShaferShenoyMNInference
:
66
public
JointTargetedMNInference
<
GUM_SCALAR
>,
67
public
EvidenceMNInference
<
GUM_SCALAR
> {
68
public
:
69
// ############################################################################
70
/// @name Constructors / Destructors
71
// ############################################################################
72
/// @{
73
74
/// default constructor
75
explicit
ShaferShenoyMNInference
(
const
IMarkovNet
<
GUM_SCALAR
>*
MN
,
76
bool
use_binary_join_tree
=
true
);
77
78
/// destructor
79
~
ShaferShenoyMNInference
()
final
;
80
81
/// @}
82
83
84
// ############################################################################
85
/// @name Accessors / Modifiers
86
// ############################################################################
87
/// @{
88
89
/// use a new triangulation algorithm
90
void
setTriangulation
(
const
Triangulation
&
new_triangulation
);
91
92
/// returns the current join tree used
93
const
JoinTree
*
joinTree
();
94
95
/// returns the current junction tree
96
const
JunctionTree
*
junctionTree
();
97
98
/// returns the probability of evidence
99
GUM_SCALAR
evidenceProbability
();
100
101
/// @}
102
103
104
protected
:
105
/// check if the vars form a possible computable joint (can be redefined by
106
/// subclass)
107
virtual
bool
isExactJointComputable_
(
const
NodeSet
&
vars
)
final
;
108
virtual
NodeSet
superForJointComputable_
(
const
NodeSet
&
vars
)
final
;
109
110
/// fired when the stage is changed
111
void
onStateChanged_
()
final
{};
112
113
/// fired after a new evidence is inserted
114
void
onEvidenceAdded_
(
const
NodeId
id
,
bool
isHardEvidence
)
final
;
115
116
/// fired before an evidence is removed
117
void
onEvidenceErased_
(
const
NodeId
id
,
bool
isHardEvidence
)
final
;
118
119
/// fired before all the evidence are erased
120
void
onAllEvidenceErased_
(
bool
contains_hard_evidence
)
final
;
121
122
/** @brief fired after an evidence is changed, in particular when its status
123
* (soft/hard) changes
124
*
125
* @param nodeId the node of the changed evidence
126
* @param hasChangedSoftHard true if the evidence has changed from Soft to
127
* Hard or from Hard to Soft
128
*/
129
void
onEvidenceChanged_
(
const
NodeId
id
,
bool
hasChangedSoftHard
)
final
;
130
131
/// fired after a new single target is inserted
132
/** @param id The target variable's id. */
133
void
onMarginalTargetAdded_
(
const
NodeId
id
)
final
;
134
135
/// fired before a single target is removed
136
/** @param id The target variable's id. */
137
void
onMarginalTargetErased_
(
const
NodeId
id
)
final
;
138
139
/// fired after a new Markov net has been assigned to the engine
140
virtual
void
onMarkovNetChanged_
(
const
IMarkovNet
<
GUM_SCALAR
>*
mn
)
final
;
141
142
/// fired after a new joint target is inserted
143
/** @param set The set of target variable's ids. */
144
void
onJointTargetAdded_
(
const
NodeSet
&
set
)
final
;
145
146
/// fired before a joint target is removed
147
/** @param set The set of target variable's ids. */
148
void
onJointTargetErased_
(
const
NodeSet
&
set
)
final
;
149
150
/// fired after all the nodes of the MN are added as single targets
151
void
onAllMarginalTargetsAdded_
()
final
;
152
153
/// fired before a all the single targets are removed
154
void
onAllMarginalTargetsErased_
()
final
;
155
156
/// fired before a all the joint targets are removed
157
void
onAllJointTargetsErased_
()
final
;
158
159
/// fired before a all single and joint_targets are removed
160
void
onAllTargetsErased_
()
final
;
161
162
/// prepares inference when the latter is in OutdatedStructure state
163
/** Note that the values of evidence are not necessarily
164
* known and can be changed between updateOutdatedStructure_ and
165
* makeMNInference_. */
166
void
updateOutdatedStructure_
()
final
;
167
168
/// prepares inference when the latter is in OutdatedPotentials state
169
/** Note that the values of evidence are not necessarily
170
* known and can be changed between updateOutdatedStructure_ and
171
* makeMNInference_. */
172
void
updateOutdatedPotentials_
()
final
;
173
174
/// called when the inference has to be performed effectively
175
/** Once the inference is done, fillPosterior_ can be called. */
176
void
makeInference_
()
final
;
177
178
179
/// returns the posterior of a given variable
180
/** @param id The variable's id. */
181
const
Potential
<
GUM_SCALAR
>&
posterior_
(
NodeId
id
)
final
;
182
183
/// returns the posterior of a declared target set
184
/** @param set The set of ids of the variables whose joint posterior is
185
* looked for. */
186
const
Potential
<
GUM_SCALAR
>&
jointPosterior_
(
const
NodeSet
&
set
)
final
;
187
188
/** @brief asks derived classes for the joint posterior of a set of
189
* variables not declared as a joint target
190
*
191
* @param wanted_target The set of ids of the variables whose joint
192
* posterior is looked for.
193
* @param declared_target the joint target declared by the user that
194
* contains set */
195
const
Potential
<
GUM_SCALAR
>&
jointPosterior_
(
const
NodeSet
&
wanted_target
,
196
const
NodeSet
&
declared_target
)
final
;
197
198
/// returns a fresh potential equal to P(argument,evidence)
199
Potential
<
GUM_SCALAR
>*
unnormalizedJointPosterior_
(
NodeId
id
)
final
;
200
201
/// returns a fresh potential equal to P(argument,evidence)
202
Potential
<
GUM_SCALAR
>*
unnormalizedJointPosterior_
(
const
NodeSet
&
set
)
final
;
203
204
205
private
:
206
typedef
Set
<
const
Potential
<
GUM_SCALAR
>* >
_PotentialSet_
;
207
typedef
SetIteratorSafe
<
const
Potential
<
GUM_SCALAR
>* >
_PotentialSetIterator_
;
208
209
/// the operator for performing the projections
210
Potential
<
GUM_SCALAR
>* (*
_projection_op_
)(
const
Potential
<
GUM_SCALAR
>&,
211
const
Set
<
const
DiscreteVariable
* >&){
212
SSNewMNprojPotential
};
213
214
/// the operator for performing the combinations
215
Potential
<
GUM_SCALAR
>* (*
_combination_op_
)(
const
Potential
<
GUM_SCALAR
>&,
216
const
Potential
<
GUM_SCALAR
>&){
217
SSNewMNmultiPotential
};
218
219
/// the triangulation class creating the junction tree used for inference
220
Triangulation
*
_triangulation_
;
221
222
/** @brief indicates whether we should transform junction trees into
223
* binary join trees */
224
bool
_use_binary_join_tree_
{
true
};
225
226
/// the undigraph extracted from the MN and used to construct the join tree
227
/** If all nodes are targets, this graph corresponds to the graph
228
* of the MN. Otherwise, it may be a subgraph of this moral graph. */
229
UndiGraph
_reduced_graph_
;
230
231
/// the join (or junction) tree used to answer the last inference query
232
JoinTree
*
_propagator_
{
nullptr
};
233
234
/// the junction tree to answer the last inference query
235
JunctionTree
*
_junctionTree_
{
nullptr
};
236
237
/// indicates whether a new join tree is needed for the next inference
238
/** when modifying the set of hard evidence, we can determine that
239
* the current JT is no more appropriate for inference. This variable
240
* enables us to keep track of this. */
241
bool
_is_new_jt_needed_
{
true
};
242
243
/// a clique node used as a root in each connected component of _propagator_
244
/** For usual probabilistic inference, roots is useless. This is useful
245
* when computing the probability of evidence. In this case, we need to
246
* compute this probability in every connected component and multiply
247
* them to get the overall probability of evidence.
248
* @warning _roots_ should be computed only when evidenceProbability
249
* is called. */
250
NodeSet
_roots_
;
251
252
/// for each node of _reduced_graph_ (~ in the Markov net), associate an ID in
253
/// the JT
254
HashTable
<
NodeSet
,
NodeId
>
_factor_to_clique_
;
255
256
NodeProperty
<
NodeId
>
_node_to_clique_
;
257
258
/// for each joint target, assign a clique in the JT that contains it
259
HashTable
<
NodeSet
,
NodeId
>
_joint_target_to_clique_
;
260
261
/// the list of all potentials stored in the cliques
262
/** This structure contains a list for each clique in the join tree. If
263
* a clique did not received any potential, then its list is empty but
264
* the entry for the clique does exist. Note that clique potentials
265
* contain also soft evidence and the factors that were projected to
266
* remove their variables that received hard evidence. The product of all
267
* these potentials is precisely the potential stored into
268
* _clique_potentials_ */
269
NodeProperty
<
_PotentialSet_
>
_clique_potentials_list_
;
270
271
/// the potentials stored into the cliques by Shafer-Shenoy
272
/** For a given clique, there is an entry in _clique_potentials_ if and
273
* only if the clique received some potential(s). In this case, the
274
* potential stored is the combination of all the corresponding list of
275
* potentials in _clique_potentials_list_. */
276
NodeProperty
<
const
Potential
<
GUM_SCALAR
>* >
_clique_potentials_
;
277
278
/// the list of all potentials stored in the separators after inferences
279
/** This structure contains all the arcs of the join tree (edges in both
280
* directions) whether the arc received any potential or not. */
281
ArcProperty
<
_PotentialSet_
>
_separator_potentials_
;
282
283
/// the set of potentials created for the last inference messages
284
/** This structure contains only the arcs on which potentials have
285
* been created.
286
* @warning Note that the factors that were projected due to hard
287
* evidence do not belong to this structure, they are kept in
288
* _hard_ev_projected_factors_. */
289
ArcProperty
<
_PotentialSet_
>
_created_messages_
;
290
291
/// the set of single posteriors computed during the last inference
292
/** the posteriors are owned by ShaferShenoyMNInference. */
293
NodeProperty
<
const
Potential
<
GUM_SCALAR
>* >
_target_posteriors_
;
294
295
/// the set of set target posteriors computed during the last inference
296
/** the posteriors are owned by ShaferShenoyMNInference. */
297
HashTable
<
NodeSet
,
const
Potential
<
GUM_SCALAR
>* >
_joint_target_posteriors_
;
298
299
/** @brief the constants resulting from the projections of CPTs defined
300
* over only hard evidence nodes
301
* @TODO remove this constant and insert the notion of a constant into
302
* potentials/multidim arrays */
303
// NodeProperty< GUM_SCALAR > _constants_;
304
305
/// indicates whether a message (from one clique to another) has been
306
/// computed
307
/** Here, all the messages, computed or not, are put into the property, only
308
* the Boolean makes the difference between messages computed and those that
309
* were not computed */
310
ArcProperty
<
bool
>
_messages_computed_
;
311
312
/// the soft evidence stored in the cliques per their assigned node in the MN
313
/** This variable is useful for method updateOutdatedPotentials_: it
314
* enables to know which soft evidence should be removed/added into the
315
* cliques of the join tree.
316
* @warning These potentials are not owned by ShaferShenoyMNInference,
317
* they are only referenced by it. Only the cliques that contain evidence
318
* are filled in this structure. */
319
NodeProperty
<
const
Potential
<
GUM_SCALAR
>* >
_node_to_soft_evidence_
;
320
321
/// the factors that were projected due to hard evidence nodes
322
/** For each factor containing the nodes that contain some
323
* hard evidence, assigns a new projected factor that does not contain
324
* these nodes anymore.
325
* @warning These potentials are owned by the inference class. */
326
HashTable
<
NodeSet
,
const
Potential
<
GUM_SCALAR
>* >
_hard_ev_projected_factors_
;
327
328
/// the hard evidence nodes which were projected in factors
329
NodeSet
_hard_ev_nodes_
;
330
331
/// the possible types of evidence changes
332
enum
EvidenceChangeType
333
{
334
EVIDENCE_ADDED
,
335
EVIDENCE_ERASED
,
336
EVIDENCE_MODIFIED
337
};
338
339
/** @brief indicates which nodes of the MN have evidence that changed
340
* since the last inference */
341
NodeProperty
<
EvidenceChangeType
>
_evidence_changes_
;
342
343
/// for comparisons with 1 - epsilon
344
const
GUM_SCALAR
_one_minus_epsilon_
{
GUM_SCALAR
(1.0 - 1e-6)};
345
346
347
/// check whether a new join tree is really needed for the next inference
348
bool
_isNewJTNeeded_
()
const
;
349
350
/// create a new junction tree as well as its related data structures
351
void
_createNewJT_
();
352
353
/// sets the operator for performing the projections
354
void
_setProjectionFunction_
(
Potential
<
GUM_SCALAR
>* (
355
*
proj
)(
const
Potential
<
GUM_SCALAR
>&,
const
Set
<
const
DiscreteVariable
* >&));
356
357
/// sets the operator for performing the combinations
358
void
_setCombinationFunction_
(
Potential
<
GUM_SCALAR
>* (*
comb
)(
const
Potential
<
GUM_SCALAR
>&,
359
const
Potential
<
GUM_SCALAR
>&));
360
361
/// invalidate all the messages sent from a given clique
362
void
_diffuseMessageInvalidations_
(
NodeId
from
,
NodeId
to
,
NodeSet
&
cliques_invalidated
);
363
364
/// invalidate all messages, posteriors and created potentials
365
void
_invalidateAllMessages_
();
366
367
/// compute a root for each connected component of _propagator_
368
void
_computeJoinTreeRoots_
();
369
370
/** @brief removes variables del_vars from a list of potentials and
371
* returns the resulting list */
372
_PotentialSet_
_marginalizeOut_
(
_PotentialSet_
pot_list
,
373
Set
<
const
DiscreteVariable
* >&
del_vars
,
374
Set
<
const
DiscreteVariable
* >&
kept_vars
);
375
376
/// creates the message sent by clique from_id to clique to_id
377
void
_produceMessage_
(
NodeId
from_id
,
NodeId
to_id
);
378
379
/// actually perform the collect phase
380
void
_collectMessage_
(
NodeId
id
,
NodeId
from
);
381
382
/// avoid copy constructors
383
ShaferShenoyMNInference
(
const
ShaferShenoyMNInference
<
GUM_SCALAR
>&);
384
385
/// avoid copy operators
386
ShaferShenoyMNInference
<
GUM_SCALAR
>&
operator
=(
const
ShaferShenoyMNInference
<
GUM_SCALAR
>&);
387
};
388
389
390
#
ifndef
GUM_NO_EXTERN_TEMPLATE_CLASS
391
extern
template
class
ShaferShenoyMNInference<
double
>;
392
#
endif
393
394
}
/* namespace gum */
395
396
#
include
<
agrum
/
MN
/
inference
/
ShaferShenoyMNInference_tpl
.
h
>
397
398
#
endif
/* SHAFER_SHENOY_INFERENCE_H */
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:643