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