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.
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
50  {
52  for (const auto node: hardEvidence)
54  for (const auto node: softEvidence)
56  while (!anc_to_visit.empty()) {
57  const NodeId node = anc_to_visit.front();
59 
60  if (!ev_ancestors.exists(node)) {
62  for (const auto par: dag.parents(node)) {
64  }
65  }
66  }
67  }
68 
69  // create the marks indicating that we have visited a node
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
87  const bool direction = nodes_to_visit.front().second;
89 
90  // check if the node has not already been visited in the same direction
91  bool already_visited;
92  if (direction) {
95  } else {
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
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 */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643