aGrUM
0.20.3
a C++ library for (probabilistic) graphical models
dSeparation.cpp
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 d-separation analysis (as described in Koller & Friedman 2009)
25
*
26
* @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
27
*/
28
29
#
include
<
agrum
/
BN
/
algorithms
/
dSeparation
.
h
>
30
#
include
<
agrum
/
tools
/
core
/
list
.
h
>
31
32
#
ifdef
GUM_NO_INLINE
33
#
include
<
agrum
/
BN
/
algorithms
/
dSeparation_inl
.
h
>
34
#
endif
// GUM_NO_INLINE
35
36
namespace
gum
{
37
38
// Fill 'requisite' with the requisite nodes in dag given a query and
39
// evidence.
40
void
dSeparation
::
requisiteNodes
(
const
DAG
&
dag
,
41
const
NodeSet
&
query
,
42
const
NodeSet
&
hardEvidence
,
43
const
NodeSet
&
softEvidence
,
44
NodeSet
&
requisite
) {
45
// for the moment, no node is requisite
46
requisite
.
clear
();
47
48
// mark the set of ancestors of the evidence
49
NodeSet
ev_ancestors
(
dag
.
size
());
50
{
51
List
<
NodeId
>
anc_to_visit
;
52
for
(
const
auto
node
:
hardEvidence
)
53
anc_to_visit
.
insert
(
node
);
54
for
(
const
auto
node
:
softEvidence
)
55
anc_to_visit
.
insert
(
node
);
56
while
(!
anc_to_visit
.
empty
()) {
57
const
NodeId
node
=
anc_to_visit
.
front
();
58
anc_to_visit
.
popFront
();
59
60
if
(!
ev_ancestors
.
exists
(
node
)) {
61
ev_ancestors
.
insert
(
node
);
62
for
(
const
auto
par
:
dag
.
parents
(
node
)) {
63
anc_to_visit
.
insert
(
par
);
64
}
65
}
66
}
67
}
68
69
// create the marks indicating that we have visited a node
70
NodeSet
visited_from_child
(
dag
.
size
());
71
NodeSet
visited_from_parent
(
dag
.
size
());
72
73
// indicate that we will send the ball to all the query nodes (as children):
74
// in list nodes_to_visit, the first element is the next node to send the
75
// ball to and the Boolean indicates whether we shall reach it from one of
76
// its children (true) or from one parent (false)
77
List
<
std
::
pair
<
NodeId
,
bool
> >
nodes_to_visit
;
78
for
(
const
auto
node
:
query
) {
79
nodes_to_visit
.
insert
(
std
::
pair
<
NodeId
,
bool
>(
node
,
true
));
80
}
81
82
// perform the bouncing ball until there is no node in the graph to send
83
// the ball to
84
while
(!
nodes_to_visit
.
empty
()) {
85
// get the next node to visit
86
const
NodeId
node
=
nodes_to_visit
.
front
().
first
;
87
const
bool
direction
=
nodes_to_visit
.
front
().
second
;
88
nodes_to_visit
.
popFront
();
89
90
// check if the node has not already been visited in the same direction
91
bool
already_visited
;
92
if
(
direction
) {
93
already_visited
=
visited_from_child
.
exists
(
node
);
94
if
(!
already_visited
) {
visited_from_child
.
insert
(
node
); }
95
}
else
{
96
already_visited
=
visited_from_parent
.
exists
(
node
);
97
if
(!
already_visited
) {
visited_from_parent
.
insert
(
node
); }
98
}
99
100
// if this is the first time we meet the node, then visit it
101
if
(!
already_visited
) {
102
// mark the node as reachable if this is not a hard evidence
103
const
bool
is_hard_evidence
=
hardEvidence
.
exists
(
node
);
104
if
(!
is_hard_evidence
) {
requisite
.
insert
(
node
); }
105
106
// bounce the ball toward the neighbors
107
if
(
direction
&& !
is_hard_evidence
) {
// visit from a child
108
// visit the parents
109
for
(
const
auto
par
:
dag
.
parents
(
node
)) {
110
nodes_to_visit
.
insert
(
std
::
pair
<
NodeId
,
bool
>(
par
,
true
));
111
}
112
113
// visit the children
114
for
(
const
auto
chi
:
dag
.
children
(
node
)) {
115
nodes_to_visit
.
insert
(
std
::
pair
<
NodeId
,
bool
>(
chi
,
false
));
116
}
117
}
else
{
// visit from a parent
118
if
(!
hardEvidence
.
exists
(
node
)) {
119
// visit the children
120
for
(
const
auto
chi
:
dag
.
children
(
node
)) {
121
nodes_to_visit
.
insert
(
std
::
pair
<
NodeId
,
bool
>(
chi
,
false
));
122
}
123
}
124
if
(
ev_ancestors
.
exists
(
node
)) {
125
// visit the parents
126
for
(
const
auto
par
:
dag
.
parents
(
node
)) {
127
nodes_to_visit
.
insert
(
std
::
pair
<
NodeId
,
bool
>(
par
,
true
));
128
}
129
}
130
}
131
}
132
}
133
}
134
135
}
/* namespace gum */
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:643