aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
IBayesNet_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-2025 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-2025 *
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#pragma once
41
42
49
50#include <cmath>
51#include <limits>
52
60#include <agrum/BN/IBayesNet.h>
61
62namespace gum {
63 // IBayesNet
64
65 template < typename GUM_SCALAR >
67 GUM_CONSTRUCTOR(IBayesNet)
68 }
69
70 template < typename GUM_SCALAR >
71 INLINE IBayesNet< GUM_SCALAR >::IBayesNet(std::string name) : DAGmodel() {
72 GUM_CONSTRUCTOR(IBayesNet)
73 this->setProperty("name", name);
74 }
75
76 template < typename GUM_SCALAR >
78 GUM_CONS_CPY(IBayesNet)
79 }
80
81 template < typename GUM_SCALAR >
84 if (this != &source) { DAGmodel::operator=(source); }
86 return *this;
87 }
88
89 template < typename GUM_SCALAR >
93
94 template < typename GUM_SCALAR >
96 Size dim = 0;
97
98 for (auto node: nodes()) {
99 Size q = 1;
100
101 for (auto parent: parents(node))
102 q *= variable(parent).domainSize();
103
104 dim += (variable(node).domainSize() - 1) * q;
105 }
106
107 return dim;
108 }
109
110 template < typename GUM_SCALAR >
112 Size res = 0;
113 for (auto node: nodes()) {
114 auto v = variable(node).domainSize();
115 if (v > res) { res = v; }
116 }
117 return res;
118 }
119
120 template < typename GUM_SCALAR >
122 GUM_SCALAR res = 1.0;
123 for (auto node: nodes()) {
124 auto v = cpt(node).min();
125 if (v < res) { res = v; }
126 }
127 return res;
128 }
129
130 template < typename GUM_SCALAR >
132 GUM_SCALAR res = 1.0;
133 for (auto node: nodes()) {
134 auto v = cpt(node).max();
135 if (v > res) { res = v; }
136 }
137 return res;
138 }
139
140 template < typename GUM_SCALAR >
142 GUM_SCALAR res = 1.0;
143 for (auto node: nodes()) {
144 auto v = cpt(node).minNonZero();
145 if (v < res) { res = v; }
146 }
147 return res;
148 }
149
150 template < typename GUM_SCALAR >
152 GUM_SCALAR res = 0.0;
153 for (auto node: nodes()) {
154 auto v = cpt(node).maxNonOne();
155 if (v > res) { res = v; }
156 }
157 return res;
158 }
160 template < typename GUM_SCALAR >
162 Size usedMem = 0;
163
164 for (auto node: nodes())
165 usedMem += cpt(node).memoryFootprint();
166 return usedMem;
167 }
168
169 template < typename GUM_SCALAR >
170 INLINE std::string IBayesNet< GUM_SCALAR >::toString() const {
171 std::stringstream s;
172 s << "BN{nodes: " << size() << ", arcs: " << dag().sizeArcs() << ", ";
174 s << "}";
175 return s.str();
176 }
177
178 template < typename GUM_SCALAR >
179 std::string IBayesNet< GUM_SCALAR >::toDot() const {
180 std::stringstream output;
181 output << "digraph \"";
182
183 std::string bn_name;
185 try {
186 bn_name = this->property("name");
187 } catch (NotFound const&) { bn_name = "no_name"; }
188
189 output << bn_name << "\" {" << std::endl;
190 output << " graph [bgcolor=transparent,label=\"" << bn_name << "\"];" << std::endl;
191 output << " node [style=filled fillcolor=\"#ffffaa\"];" << std::endl << std::endl;
192
193 for (auto node: nodes())
194 output << "\"" << variable(node).name() << "\" [comment=\"" << node << ":"
195 << variable(node).toStringWithDescription() << "\"];" << std::endl;
197 output << std::endl;
198
199 std::string tab = " ";
200
201 for (auto node: nodes()) {
202 if (children(node).size() > 0) {
203 for (auto child: children(node)) {
204 output << tab << "\"" << variable(node).name() << "\" -> " << "\""
205 << variable(child).name() << "\";" << std::endl;
206 }
207 } else if (parents(node).size() == 0) {
208 output << tab << "\"" << variable(node).name() << "\";" << std::endl;
209 }
210 }
211
212 output << "}" << std::endl;
213
214 return output.str();
215 }
216
220 template < typename GUM_SCALAR >
222 auto value = (GUM_SCALAR)1.0;
223
224 GUM_SCALAR tmp;
225
226 for (auto node: nodes()) {
227 if ((tmp = cpt(node)[i]) == (GUM_SCALAR)0) { return (GUM_SCALAR)0; }
229 value *= tmp;
230 }
232 return value;
233 }
238 template < typename GUM_SCALAR >
240 auto value = (GUM_SCALAR)0.0;
241
242 GUM_SCALAR tmp;
243
244 for (auto node: nodes()) {
245 if ((tmp = cpt(node)[i]) == (GUM_SCALAR)0) {
246 return (GUM_SCALAR)(-std::numeric_limits< double >::infinity());
247 }
248
249 value += std::log2(cpt(node)[i]);
250 }
251
252 return value;
253 }
254
255 template < typename GUM_SCALAR >
257 if (size() != from.size()) { return false; }
258
259 if (sizeArcs() != from.sizeArcs()) { return false; }
260
261 for (auto node: nodes()) {
262 try {
263 const auto& v1 = variable(node);
264 const auto& v2 = from.variableFromName(variable(node).name());
265 if (v1 != v2) { return false; }
266 } catch (NotFound const&) {
267 // a name is not found in from
268 return false;
269 }
270 }
271
272 for (auto node: nodes()) {
273 NodeId fromnode = from.idFromName(variable(node).name());
274
275 if (cpt(node).nbrDim() != from.cpt(fromnode).nbrDim()) { return false; }
276
277 if (cpt(node).domainSize() != from.cpt(fromnode).domainSize()) { return false; }
278
279 for (Idx i = 0; i < cpt(node).nbrDim(); ++i) {
280 if (!from.cpt(fromnode).contains(from.variableFromName(cpt(node).variable(i).name()))) {
281 return false;
282 }
283 }
284
285 Instantiation i(cpt(node));
286 Instantiation j(from.cpt(fromnode));
287
289 for (i.setFirst(); !i.end(); i.inc()) {
290 for (Idx indice = 0; indice < cpt(node).nbrDim(); ++indice) {
291 const DiscreteVariable* p = &(i.variable(indice));
292 j.chgVal(j.pos(from.variableFromName(p->name())), i.val(*p));
293 }
294
295 if (cmp(cpt(node).get(i), from.cpt(fromnode).get(j))) { return false; }
296 }
297 }
298
299 return true;
300 }
301
302 template < typename GUM_SCALAR >
304 return !this->operator==(from);
305 }
306
307 template < typename GUM_SCALAR >
308 INLINE std::ostream& operator<<(std::ostream& output, const IBayesNet< GUM_SCALAR >& bn) {
309 output << bn.toString();
310 return output;
311 }
312
313 template < typename GUM_SCALAR >
314 std::vector< std::string > IBayesNet< GUM_SCALAR >::check() const {
315 std::vector< std::string > comments;
316
317 const double epsilon = 1e-8;
318 const double error_epsilon = 1e-1;
319
320 // CHECKING domain
321 for (const auto i: nodes())
322 if (variable(i).domainSize() < 2) {
323 std::stringstream s;
324 s << "Variable " << variable(i).name() << ": not consistent (domainSize=1).";
325 comments.push_back(s.str());
326 }
327
328 // CHECKING parameters are probabilities
329 // >0
330 for (const auto i: nodes()) {
331 const auto [amin, minval] = cpt(i).argmin();
332 if (minval < (GUM_SCALAR)0.0) {
333 std::stringstream s;
334 s << "Variable " << variable(i).name() << " : P(" << *(amin.begin()) << ") < 0.0";
335 comments.push_back(s.str());
336 }
337 }
338 // <1
339 for (const auto i: nodes()) {
340 const auto [amax, maxval] = cpt(i).argmax();
341 if (maxval > (GUM_SCALAR)1.0) {
342 std::stringstream s;
343 s << "Variable " << variable(i).name() << " : P(" << *(amax.begin()) << ") > 1.0";
344 comments.push_back(s.str());
345 }
346 }
347
348 // CHECKING distributions sum to 1
349 for (const auto i: nodes()) {
350 const auto p = cpt(i).sumOut({&variable(i)});
351 const auto [amin, minval] = p.argmin();
352 if (minval < (GUM_SCALAR)(1.0 - epsilon)) {
353 std::stringstream s;
354 s << "Variable " << variable(i).name() << " : ";
355 if (!parents(i).empty()) s << "with (at least) parents " << *(amin.begin()) << ", ";
356 s << "the CPT sum to less than 1";
357 if (minval > (GUM_SCALAR)(1.0 - error_epsilon)) s << " (normalization problem ?)";
358 s << ".";
359 comments.push_back(s.str());
360 continue;
361 }
362 const auto [amax, maxval] = p.argmax();
363 if (maxval > (GUM_SCALAR)(1.0 + epsilon)) {
364 std::stringstream s;
365 s << "Variable " << variable(i).name() << " : ";
366 if (!parents(i).empty()) s << "with (at least) parents " << *(amax.begin()) << ", ";
367 s << "the CPT sum to more than 1";
368 if (maxval < (GUM_SCALAR)(1.0 + error_epsilon)) s << " (normalization problem ?)";
369 s << ".";
370 comments.push_back(s.str());
371 }
372 }
373
374 return comments;
375 }
376
377 template < typename GUM_SCALAR >
378 Tensor< GUM_SCALAR > IBayesNet< GUM_SCALAR >::evEq(const std::string& name, double value) const {
379 return Tensor< GUM_SCALAR >::evEq(variableFromName(name), value);
380 }
381
382 template < typename GUM_SCALAR >
383 Tensor< GUM_SCALAR >
384 IBayesNet< GUM_SCALAR >::evIn(const std::string& name, double val1, double val2) const {
385 return Tensor< GUM_SCALAR >::evIn(variableFromName(name), val1, val2);
386 }
387
388 template < typename GUM_SCALAR >
389 Tensor< GUM_SCALAR > IBayesNet< GUM_SCALAR >::evGt(const std::string& name, double val) const {
391 }
392
393 template < typename GUM_SCALAR >
394 Tensor< GUM_SCALAR > IBayesNet< GUM_SCALAR >::evLt(const std::string& name, double val) const {
396 }
397} /* namespace gum */
Class representing the minimal interface for Bayesian network with no numerical data.
and aggregator
const DAG & dag() const
Returns a constant reference to the dag of this Bayes Net.
DAGmodel()
Default constructor.
Definition DAGmodel.cpp:49
virtual Size size() const final
Returns the number of variables in this Directed Graphical Model.
const NodeSet & children(const NodeId id) const
DAGmodel & operator=(const DAGmodel &source)
Private copy operator.
Definition DAGmodel.cpp:55
const NodeSet & parents(const NodeId id) const
const NodeGraphPart & nodes() const final
Returns a constant reference to the dag of this Bayes Net.
Base class for discrete random variable.
static void spaceCplxToStream(std::stringstream &s, double dSize, int dim, Size usedMem)
send to the stream the space complexity with 3 parametrs
void setProperty(const std::string &name, const std::string &value)
Add or change a property of this GraphicalModel.
const std::string & property(const std::string &name) const
double log10DomainSize() const
virtual bool empty() const
Return true if this graphical model is empty.
Class representing the minimal interface for Bayesian network with no numerical data.
Definition IBayesNet.h:75
GUM_SCALAR minNonZeroParam() const
GUM_SCALAR jointProbability(const Instantiation &i) const
Compute a parameter of the joint probability for the BN (given an instantiation of the vars).
Size dim() const
Returns the dimension (the number of free parameters) in this bayes net.
Size memoryFootprint() const
compute the (approximated) footprint in memory of the model (the footprints of CPTs)
virtual const DiscreteVariable & variableFromName(const std::string &name) const =0
Getter by name.
GUM_SCALAR maxParam() const
std::string toString() const
std::vector< std::string > check() const
Check if the BayesNet is consistent (variables, CPT).
Tensor< GUM_SCALAR > evIn(const std::string &name, double val1, double val2) const
Size maxVarDomainSize() const
GUM_SCALAR log2JointProbability(const Instantiation &i) const
Compute a parameter of the log joint probability for the BN (given an instantiation of the vars).
GUM_SCALAR maxNonOneParam() const
virtual const DiscreteVariable & variable(NodeId id) const=0
GUM_SCALAR minParam() const
Tensor< GUM_SCALAR > evEq(const std::string &name, double value) const
Tensor< GUM_SCALAR > evGt(const std::string &name, double value) const
IBayesNet< GUM_SCALAR > & operator=(const IBayesNet< GUM_SCALAR > &source)
Copy operator.
Tensor< GUM_SCALAR > evLt(const std::string &name, double value) const
IBayesNet()
Default constructor.
virtual NodeId idFromName(const std::string &name) const =0
Getter by name.
virtual std::string toDot() const
bool operator==(const IBayesNet< GUM_SCALAR > &from) const
This operator compares 2 BNs !
virtual const Tensor< GUM_SCALAR > & cpt(NodeId varId) const =0
Returns the CPT of a variable.
bool operator!=(const IBayesNet< GUM_SCALAR > &from) const
virtual ~IBayesNet()
Destructor.
Class for assigning/browsing values to tuples of discrete variables.
Exception : the element we looked for cannot be found.
static Tensor< GUM_SCALAR > evEq(const DiscreteVariable &v, double val)
numerical evidence generator
static Tensor< GUM_SCALAR > evGt(const DiscreteVariable &v, double val)
numerical evidence generator
static Tensor< GUM_SCALAR > evIn(const DiscreteVariable &v, double val1, double val2)
numerical evidence generator
static Tensor< GUM_SCALAR > evLt(const DiscreteVariable &v, double val)
numerical evidence generator
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
Size Idx
Type for indexes.
Definition types.h:79
Size NodeId
Type for node ids.
class for NoisyAND-net implementation as multiDim
class for multiDimNoisyORCompound
class for NoisyOR-net implementation as multiDim
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
std::ostream & operator<<(std::ostream &stream, const AVLTree< Val, Cmp > &tree)
display the content of a tree
Definition AVLTree.h:913
bool operator==(const HashTableIteratorSafe< Key, Val > &from) const noexcept
Checks whether two iterators are pointing toward equal elements.
or aggregator
Abstract class for generating Conditional Probability Tables.
Indicate whether two elements are (almost) different or not.
Definition utils_misc.h:171
Header of the Tensor class.