aGrUM 3.0.0
a C++ library for (probabilistic) graphical models

Implementation of Shachter's Bayes Balls algorithm. More...

#include <agrum/BN/inference/BayesBall.h>

Static Public Member Functions

Accessors / Modifiers
static void requisiteNodes (const DAG &dag, const NodeSet &query, const NodeSet &hardEvidence, const NodeSet &softEvidence, NodeSet &requisite)
 Fill the 'requisite' nodeset with the requisite nodes in dag given a query and evidence.
template<GUM_Numeric GUM_SCALAR, class TABLE>
static void relevantTensors (const IBayesNet< GUM_SCALAR > &bn, const NodeSet &query, const NodeSet &hardEvidence, const NodeSet &softEvidence, Set< const TABLE * > &tensors)
 update a set of tensors, keeping only those d-connected with query variables given evidence

Private Member Functions

Constructors / Destructors
 BayesBall ()
 Default constructor.
 ~BayesBall ()
 Destructor.

Detailed Description

Implementation of Shachter's Bayes Balls algorithm.

Definition at line 67 of file BayesBall.h.

Constructor & Destructor Documentation

◆ BayesBall()

INLINE gum::BayesBall::BayesBall ( )
private

Default constructor.

Definition at line 55 of file BayesBall_inl.h.

55{ GUM_CONSTRUCTOR(BayesBall) }
BayesBall()
Default constructor.

References BayesBall().

Referenced by BayesBall(), and ~BayesBall().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ~BayesBall()

INLINE gum::BayesBall::~BayesBall ( )
private

Destructor.

Definition at line 57 of file BayesBall_inl.h.

57{ GUM_DESTRUCTOR(BayesBall) }

References BayesBall().

Here is the call graph for this function:

Member Function Documentation

◆ relevantTensors()

template<GUM_Numeric GUM_SCALAR, class TABLE>
void gum::BayesBall::relevantTensors ( const IBayesNet< GUM_SCALAR > & bn,
const NodeSet & query,
const NodeSet & hardEvidence,
const NodeSet & softEvidence,
Set< const TABLE * > & tensors )
static

update a set of tensors, keeping only those d-connected with query variables given evidence

Definition at line 56 of file BayesBall_tpl.h.

60 {
61 const DAG& dag = bn.internalDag();
62
63 // create the marks (top = first and bottom = second)
64 NodeProperty< std::pair< bool, bool > > marks(dag.size());
65 const std::pair< bool, bool > empty_mark(false, false);
66
69 HashTable< NodeId, Set< const TABLE* > > node2tensors;
70 for (const auto pot: tensors) {
71 const Sequence< const DiscreteVariable* >& vars = pot->variablesSequence();
72 for (const auto var: vars) {
73 const NodeId id = bn.nodeId(*var);
74 if (!node2tensors.exists(id)) { node2tensors.insert(id, Set< const TABLE* >()); }
75 node2tensors[id].insert(pot);
76 }
77 }
78
79 // indicate that we will send the ball to all the query nodes (as children):
80 // in list nodes_to_visit, the first element is the next node to send the
81 // ball to and the Boolean indicates whether we shall reach it from one of
82 // its children (true) or from one parent (false)
83 List< std::pair< NodeId, bool > > nodes_to_visit;
84 for (const auto node: query) {
85 nodes_to_visit.insert(std::pair< NodeId, bool >(node, true));
86 }
87
88 // perform the bouncing ball until _node2tensors_ becomes empty (which
89 // means that we have reached all the tensors and, therefore, those
90 // are d-connected to query) or until there is no node in the graph to send
91 // the ball to
92 while (!nodes_to_visit.empty() && !node2tensors.empty()) {
93 // get the next node to visit
94 NodeId node = nodes_to_visit.front().first;
95
96 // if the marks of the node do not exist, create them
97 if (!marks.exists(node)) marks.insert(node, empty_mark);
98
99 // if the node belongs to the query, update _node2tensors_: remove all
100 // the tensors containing the node
101 if (node2tensors.exists(node)) {
102 auto& pot_set = node2tensors[node];
103 for (const auto pot: pot_set) {
104 const auto& vars = pot->variablesSequence();
105 for (const auto var: vars) {
106 const NodeId id = bn.nodeId(*var);
107 if (id != node) {
108 node2tensors[id].erase(pot);
109 if (node2tensors[id].empty()) { node2tensors.erase(id); }
110 }
111 }
112 }
113 node2tensors.erase(node);
114
115 // if _node2tensors_ is empty, no need to go on: all the tensors
116 // are d-connected to the query
117 if (node2tensors.empty()) return;
118 }
119
120
121 // bounce the ball toward the neighbors
122 if (nodes_to_visit.front().second) { // visit from a child
123 nodes_to_visit.popFront();
124
125 if (hardEvidence.exists(node)) { continue; }
126
127 if (!marks[node].first) {
128 marks[node].first = true; // top marked
129 for (const auto par: dag.parents(node)) {
130 nodes_to_visit.insert(std::pair< NodeId, bool >(par, true));
131 }
132 }
133
134 if (!marks[node].second) {
135 marks[node].second = true; // bottom marked
136 for (const auto chi: dag.children(node)) {
137 nodes_to_visit.insert(std::pair< NodeId, bool >(chi, false));
138 }
139 }
140 } else { // visit from a parent
141 nodes_to_visit.popFront();
142
143 const bool is_hard_evidence = hardEvidence.exists(node);
144 const bool is_evidence = is_hard_evidence || softEvidence.exists(node);
145
146 if (is_evidence && !marks[node].first) {
147 marks[node].first = true;
148
149 for (const auto par: dag.parents(node)) {
150 nodes_to_visit.insert(std::pair< NodeId, bool >(par, true));
151 }
152 }
153
154 if (!is_hard_evidence && !marks[node].second) {
155 marks[node].second = true;
156
157 for (const auto chi: dag.children(node)) {
158 nodes_to_visit.insert(std::pair< NodeId, bool >(chi, false));
159 }
160 }
161 }
162 }
163
164
165 // here, all the tensors that belong to _node2tensors_ are d-separated
166 // from the query
167 for (const auto& elt: node2tensors) {
168 for (const auto pot: elt.second) {
169 tensors.erase(pot);
170 }
171 }
172 }
Size NodeId
Type for node ids.
HashTable< NodeId, VAL > NodeProperty
Property on graph elements.

References gum::ArcGraphPart::children(), gum::HashTable< Key, Val >::empty(), gum::List< Val >::empty(), gum::HashTable< Key, Val >::erase(), gum::Set< Key >::erase(), gum::HashTable< Key, Val >::exists(), gum::Set< Key >::exists(), gum::List< Val >::front(), gum::HashTable< Key, Val >::insert(), gum::List< Val >::insert(), gum::DAGmodel::internalDag(), gum::DiscreteGraphicalModel::nodeId(), gum::ArcGraphPart::parents(), gum::List< Val >::popFront(), and gum::NodeGraphPart::size().

Here is the call graph for this function:

◆ requisiteNodes()

void gum::BayesBall::requisiteNodes ( const DAG & dag,
const NodeSet & query,
const NodeSet & hardEvidence,
const NodeSet & softEvidence,
NodeSet & requisite )
static

Fill the 'requisite' nodeset with the requisite nodes in dag given a query and evidence.

Requisite nodes are those that are d-connected to at least one of the query nodes given a set of hard and soft evidence

Definition at line 56 of file BayesBall.cpp.

60 {
61 requisite = graph::requisiteNodes(dag, query, hardEvidence, softEvidence);
62 }
NodeSet requisiteNodes(const G &g, const NodeSet &query, const NodeSet &Zhard=NodeSet(), const NodeSet &Zsoft=NodeSet())
Returns the Shachter-requisite nodes for query given evidence.

References gum::graph::requisiteNodes().

Here is the call graph for this function:

The documentation for this class was generated from the following files: