aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
structuredBayesBall_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2026 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41#pragma once
42
43
50
52
53namespace gum {
54 namespace prm {
55
56 template < GUM_Numeric GUM_SCALAR >
58 GUM_DESTRUCTOR(StructuredBayesBall);
59
60 for (const auto& elt: _reqMap_)
61 delete elt.second.first;
62 }
63
64 template < GUM_Numeric GUM_SCALAR >
66 for (const auto& elt: _reqMap_)
67 delete elt.second.first;
68
69 _keyMap_.clear();
70 _reqMap_.clear();
71 }
72
73 template < GUM_Numeric GUM_SCALAR >
75 NodeId n) {
76 if (!i->exists(n)) return false;
77 typename PRMInference< GUM_SCALAR >::Chain chain = std::make_pair(i, &(i->get(n)));
78
79 if (_inf_->hasEvidence(chain)) {
80 const Tensor< GUM_SCALAR >* e = _inf_->evidence(i)[n];
81 Instantiation inst(e);
82 Size count = 0;
83
84 for (inst.setFirst(); !inst.end(); inst.inc()) {
85 if ((e->get(inst) == (GUM_SCALAR)1.0)) ++count;
86 else if (e->get(inst) != (GUM_SCALAR)0.0) return false;
87 }
88
89 return (count == 1);
90 }
91
92 return false;
93 }
94
95 template < GUM_Numeric GUM_SCALAR >
97 NodeId n) {
98 _clean_();
102 _fromChild_(i, n, marks);
103 _fillMaps_(marks);
104
105 for (const auto& elt: marks)
106 delete elt.second;
107 }
108
109 template < GUM_Numeric GUM_SCALAR >
111 NodeId n,
112 InstanceMap& marks) {
113 auto p_marks = marks.tryGet(i);
114 if (!p_marks) {
116 p_marks = marks.tryGet(i);
117 }
118
119 if (!(*p_marks)->exists(n)) { (*p_marks)->insert(n, std::pair< bool, bool >(false, false)); }
120
121 // Sending message to parents
122 switch (i->type().get(n).elt_type()) {
124 if (!_getMark_(marks, i, n).first) {
125 _getMark_(marks, i, n).first = true;
126
127 for (const auto inst: i->getInstances(n))
128 _fromChild_(inst, inst->get(_getSC_(i, n).lastElt().safeName()).id(), marks);
129 }
130
131 if (!_getMark_(marks, i, n).second) {
132 _getMark_(marks, i, n).second = true;
133
134 for (const auto chi: i->type().containerDag().children(n))
135 _fromParent_(i, chi, marks);
136 }
137
138 break;
139 }
140
143 if (!_getMark_(marks, i, n).first) {
144 _getMark_(marks, i, n).first = true;
145
146 if (!_isHardEvidence_(i, n))
147 for (const auto par: i->type().containerDag().parents(n))
148 _fromChild_(i, par, marks);
149 }
150
151 if (!_getMark_(marks, i, n).second) {
152 _getMark_(marks, i, n).second = true;
153
154 // In i.
155 for (const auto chi: i->type().containerDag().children(n))
156 _fromParent_(i, chi, marks);
157
158 // Out of i.
159 if (i->hasRefAttr(n)) {
160 const auto& refs = i->getRefAttr(n);
161
162 for (auto iter = refs.begin(); iter != refs.end(); ++iter)
163 _fromParent_(iter->first, iter->first->type().get(iter->second).id(), marks);
164 }
165 }
166
167 break;
168 }
169
170 default : {
171 // We shouldn't reach any other PRMClassElement<GUM_DATA> than
172 // PRMAttribute
173 // or
174 // PRMSlotChain<GUM_SCALAR>.
175 GUM_ERROR(FatalError, "This case is impossible.")
176 }
177 }
178 }
179
180 template < GUM_Numeric GUM_SCALAR >
182 NodeId n,
183 InstanceMap& marks) {
184 auto p_marks = marks.tryGet(i);
185 if (!p_marks) {
187 p_marks = marks.tryGet(i);
188 }
189
190 if (!(*p_marks)->exists(n)) { (*p_marks)->insert(n, std::pair< bool, bool >(false, false)); }
191
192 // Concerns only PRMAttribute (because of the hard evidence)
193 if ((_isHardEvidence_(i, n)) && (!_getMark_(marks, i, n).first)) {
194 _getMark_(marks, i, n).first = true;
195
196 for (const auto par: i->type().containerDag().parents(n))
197 _fromChild_(i, par, marks);
198 } else if (!_getMark_(marks, i, n).second) {
199 _getMark_(marks, i, n).second = true;
200
201 // In i.
202 for (const auto chi: i->type().containerDag().children(n))
203 _fromParent_(i, chi, marks);
204
205 // Out of i.
206 if (i->hasRefAttr(n)) {
207 for (auto iter = i->getRefAttr(n).begin(); iter != i->getRefAttr(n).end(); ++iter)
208 _fromParent_(iter->first, iter->first->type().get(iter->second).id(), marks);
209 }
210 }
211 }
212
213 template < GUM_Numeric GUM_SCALAR >
215 // First find for each instance it's requisite nodes
217
218 for (const auto& elt: marks) {
219 Set< NodeId >* req_set = new Set< NodeId >();
220
221 for (const auto& elt2: *elt.second)
222 if (elt2.second.first) req_set->insert(elt2.first);
223
224 req_map.insert(elt.first, req_set);
225 }
226
227 // Remove all instances with 0 requisite nodes
229
230 for (const auto& elt: req_map)
231 if (elt.second->size() == 0) to_remove.insert(elt.first);
232
233 for (const auto remo: to_remove) {
234 delete req_map[remo];
235 req_map.erase(remo);
236 }
237
238 // Fill _reqMap_ and _keyMap_
239 for (const auto& elt: req_map) {
240 std::string key = _buildHashKey_(elt.first, *elt.second);
241
242 if (auto p_req = _reqMap_.tryGet(key)) {
243 _keyMap_.insert(elt.first, std::pair< std::string, Set< NodeId >* >(key, p_req->first));
244 p_req->second += 1;
245 delete elt.second;
246 req_map[elt.first] = 0;
247 } else {
248 _reqMap_.insert(key, std::pair< Set< NodeId >*, Size >(elt.second, 1));
249 _keyMap_.insert(elt.first, std::pair< std::string, Set< NodeId >* >(key, elt.second));
250 }
251 }
252 }
253
254 template < GUM_Numeric GUM_SCALAR >
255 std::string
257 Set< NodeId >& req_nodes) {
258 std::string result(i->type().name());
259
260 for (const auto node: i->type().containerDag().nodes())
261 if (req_nodes.exists(node)) result += std::format("-{}", node);
262
263 return result;
264 }
265
266 template < GUM_Numeric GUM_SCALAR >
268 const PRMInference< GUM_SCALAR >& inference) : _inf_(&inference) {
269 GUM_CONSTRUCTOR(StructuredBayesBall);
270 }
271
272 template < GUM_Numeric GUM_SCALAR >
274 const StructuredBayesBall< GUM_SCALAR >& source) : _inf_(0) {
275 GUM_CONS_CPY(StructuredBayesBall);
276 GUM_ERROR(FatalError, "Not allowed.")
277 }
278
279 template < GUM_Numeric GUM_SCALAR >
280 StructuredBayesBall< GUM_SCALAR >& StructuredBayesBall< GUM_SCALAR >::operator=(
281 const StructuredBayesBall< GUM_SCALAR >& source) {
282 GUM_ERROR(FatalError, "Not allowed.")
283 }
284
285 template < GUM_Numeric GUM_SCALAR >
286 const std::string&
290
291 template < GUM_Numeric GUM_SCALAR >
292 const std::string&
294 return _keyMap_[&i].first;
295 }
296
297 template < GUM_Numeric GUM_SCALAR >
299 const PRMInstance< GUM_SCALAR >* i) const {
300 return *(_keyMap_[i].second);
301 }
302
303 template < GUM_Numeric GUM_SCALAR >
305 const PRMInstance< GUM_SCALAR >& i) const {
306 return *(_keyMap_[&i].second);
307 }
308
309 template < GUM_Numeric GUM_SCALAR >
311 return _reqMap_[std::string{key}].second;
312 }
313
314 template < GUM_Numeric GUM_SCALAR >
316 return ((float)_reqMap_.size()) / ((float)_keyMap_.size());
317 }
318
319 template < GUM_Numeric GUM_SCALAR >
321 return _keyMap_.exists(i);
322 }
323
324 template < GUM_Numeric GUM_SCALAR >
326 return _keyMap_.exists(&i);
327 }
328
329 template < GUM_Numeric GUM_SCALAR >
333
334 template < GUM_Numeric GUM_SCALAR >
338
339 template < GUM_Numeric GUM_SCALAR >
342 return static_cast< const PRMSlotChain< GUM_SCALAR >& >(i->type().get(n));
343 }
344
345 template < GUM_Numeric GUM_SCALAR >
346 std::pair< bool, bool >&
349 NodeId n) {
350 return (*(marks[i]))[n];
351 }
352
353 } /* namespace prm */
354} /* namespace gum */
Exception : fatal (unknown ?) error.
The class for generic Hash Tables.
Definition hashTable.h:640
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
void erase(const Key &key)
Removes a given element from the hash table.
optional_ref< Val > tryGet(const Key &key)
Returns a pointer to the value associated with a given key, or nullptr if the key does not exist.
Class for assigning/browsing values to tuples of discrete variables.
bool end() const
Returns true if the Instantiation reached the end.
void inc()
Operator increment.
void setFirst()
Assign the first values to the tuple of the Instantiation.
bool exists(const Key &k) const
Indicates whether a given elements belong to the set.
Definition set_tpl.h:504
void insert(const Key &k)
Inserts a new element into the set.
Definition set_tpl.h:510
This abstract class is used as base class for all inference class on PRM<GUM_SCALAR>.
std::pair< const PRMInstance< GUM_SCALAR > *, const PRMAttribute< GUM_SCALAR > * > Chain
Code alias.
An PRMInstance is a Bayesian network fragment defined by a Class and used in a PRMSystem.
Definition PRMInstance.h:79
bool exists(NodeId id) const
Returns true if id matches an PRMAttribute<GUM_SCALAR> in this PRMInstance<GUM_SCALAR>.
PRMAttribute< GUM_SCALAR > & get(NodeId id)
Getter on an PRMAttribute<GUM_SCALAR> of this PRMInstance<GUM_SCALAR>.
bool hasRefAttr(NodeId id) const
Returns true if id has at least one referring PRMAttribute<GUM_SCALAR>.
PRMClass< GUM_SCALAR > & type()
Returns the type of this instance.
std::vector< std::pair< PRMInstance< GUM_SCALAR > *, std::string > > & getRefAttr(NodeId id)
Returns a vector of pairs of refering attributes of id.
const Set< PRMInstance< GUM_SCALAR > * > & getInstances(NodeId id) const
Returns the Set of PRMInstance<GUM_SCALAR> referenced by id.
A PRMSlotChain represents a sequence of gum::prm::PRMClassElement<GUM_SCALAR> where the n-1 first gum...
<agrum/PRM/structuredBayesBall.h>
std::pair< bool, bool > & _getMark_(InstanceMap &marks, const PRMInstance< GUM_SCALAR > *i, NodeId n)
Code alias.
HashTable< const PRMInstance< GUM_SCALAR > *, std::pair< std::string, Set< NodeId > * > > _keyMap_
Associate an PRMInstance<GUM_SCALAR> with a unique key w.r.t. d-separation and the set of requisite n...
const PRMSlotChain< GUM_SCALAR > & _getSC_(const PRMInstance< GUM_SCALAR > *i, NodeId n)
Code alias.
Size occurrence(std::string_view key) const
Returns the number of occurrence of the given key, which is the number of PRMInstance<GUM_SCALAR> sha...
const PRMInference< GUM_SCALAR > * _inf_
The PRM at which model belongs.
void compute(const PRMInstance< GUM_SCALAR > *i, NodeId n)
Compute the set or requisite nodes for each required instance given the current set of observations....
bool exists(const PRMInstance< GUM_SCALAR > *i) const
Returns true if i has requisite nodes.
void _clean_()
Cleans this before a new computation.
HashTable< NodeId, std::pair< bool, bool > > MarkMap
Code alias.
const Set< NodeId > & requisiteNodes(const PRMInstance< GUM_SCALAR > *i) const
Returns the set of requisite nodes w.r.t. d-separation for i.
HashTable< std::string, std::pair< Set< NodeId > *, Size > > _reqMap_
Associate a Key with the set of requisite nodes associated with it. The Size value is the number of i...
void _fillMaps_(InstanceMap &marks)
Fill keyMap and reqMap.
void _fromParent_(const PRMInstance< GUM_SCALAR > *i, NodeId n, InstanceMap &marks)
When the ball is receive on i->get(n) from a parent.
void _fromChild_(const PRMInstance< GUM_SCALAR > *i, NodeId n, InstanceMap &marks)
When the ball is received on i->get(n) from a child.
StructuredBayesBall & operator=(const StructuredBayesBall &source)
Copy operator.
void _compute_(const PRMInstance< GUM_SCALAR > *i, NodeId n)
The real compute method.
float liftRatio() const
Returns the ratio between the total number of instances and the number of instances with the same con...
std::string _buildHashKey_(const PRMInstance< GUM_SCALAR > *i, Set< NodeId > &req_nodes)
Builds the HashKey for the given instance and requisite nodes set.
const std::string & key(const PRMInstance< GUM_SCALAR > *i) const
Returns a unique key w.r.t. d-separation for i.
HashTable< const PRMInstance< GUM_SCALAR > *, MarkMap * > InstanceMap
bool _isHardEvidence_(const PRMInstance< GUM_SCALAR > *i, NodeId n)
Returns true if there is a hard evidence on i->get(n).
StructuredBayesBall(const PRMInference< GUM_SCALAR > &inference)
Default Constructor.
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
Size NodeId
Type for node ids.
namespace for all probabilistic relational models entities
Definition agrum.h:68
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
Headers of StructuredBayesBall.