aGrUM 3.1.1
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-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
51#include <cmath>
52#include <limits>
53
61#include <agrum/BN/IBayesNet.h>
62
63namespace gum {
64 // IBayesNet
65
66 template < GUM_Numeric GUM_SCALAR >
68 GUM_CONSTRUCTOR(IBayesNet)
69 }
70
71 template < GUM_Numeric GUM_SCALAR >
72 IBayesNet< GUM_SCALAR >::IBayesNet(std::string_view name) : DAGmodel() {
73 GUM_CONSTRUCTOR(IBayesNet)
74 this->setProperty("name", name);
75 }
76
77 template < GUM_Numeric GUM_SCALAR >
79 GUM_CONS_CPY(IBayesNet)
80 }
81
82 template < GUM_Numeric GUM_SCALAR >
84 DAGmodel(std::move(source)) {
85 GUM_CONS_MOV(IBayesNet)
86 }
87
88 template < GUM_Numeric GUM_SCALAR >
91 if (this != &source) {
92 DAGmodel::operator=(source);
93 GUM_OP_CPY(IBayesNet);
94 }
95
96 return *this;
97 }
98
99 template < GUM_Numeric GUM_SCALAR >
101 if (this != &source) {
102 DAGmodel::operator=(std::move(source));
103 GUM_OP_MOV(IBayesNet);
104 }
105 return *this;
106 }
107
108 template < GUM_Numeric GUM_SCALAR >
110 GUM_DESTRUCTOR(IBayesNet)
111 }
112
113 template < GUM_Numeric GUM_SCALAR >
115 Size dim = 0;
116
117 for (auto node: nodes()) {
118 Size q = 1;
119
120 for (auto parent: parents(node))
121 q *= variable(parent).domainSize();
122
123 dim += (variable(node).domainSize() - 1) * q;
124 }
125
126 return dim;
127 }
128
129 template < GUM_Numeric GUM_SCALAR >
131 Size res = 0;
132 for (auto node: nodes()) {
133 auto v = variable(node).domainSize();
134 if (v > res) { res = v; }
135 }
136 return res;
138
139 template < GUM_Numeric GUM_SCALAR >
141 GUM_SCALAR res = 1.0;
142 for (auto node: nodes()) {
143 auto v = cpt(node).min();
144 if (v < res) { res = v; }
145 }
146 return res;
147 }
148
149 template < GUM_Numeric GUM_SCALAR >
151 GUM_SCALAR res = 1.0;
152 for (auto node: nodes()) {
153 auto v = cpt(node).max();
154 if (v > res) { res = v; }
155 }
156 return res;
157 }
158
159 template < GUM_Numeric GUM_SCALAR >
161 GUM_SCALAR res = 1.0;
162 for (auto node: nodes()) {
163 auto v = cpt(node).minNonZero();
164 if (v < res) { res = v; }
165 }
166 return res;
167 }
168
169 template < GUM_Numeric GUM_SCALAR >
171 GUM_SCALAR res = 0.0;
172 for (auto node: nodes()) {
173 auto v = cpt(node).maxNonOne();
174 if (v > res) { res = v; }
175 }
176 return res;
178
179 template < GUM_Numeric GUM_SCALAR >
181 Size usedMem = 0;
182
183 for (auto node: nodes())
184 usedMem += cpt(node).memoryFootprint();
185 return usedMem;
186 }
187
188 template < GUM_Numeric GUM_SCALAR >
190 std::stringstream s;
191 s << std::format("BN{{nodes: {}, arcs: {}, ", size(), dag().sizeArcs());
193 s << "}";
194 return s.str();
195 }
197 template < GUM_Numeric GUM_SCALAR >
198 std::string IBayesNet< GUM_SCALAR >::toDot() const {
199 std::stringstream output;
200
201 std::string bn_name = this->propertyWithDefault("name", "no_name");
202
203 output << std::format("digraph \"{}\" {{\n", bn_name);
204 output << std::format(" graph [bgcolor=transparent,label=\"{}\"];\n", bn_name);
205 output << " node [style=filled fillcolor=\"#ffffaa\"];" << std::endl << std::endl;
207 for (auto node: nodes())
208 output << std::format("\"{}\" [comment=\"{}:{}\"];\n",
209 variable(node).name(),
210 node,
211 variable(node).toStringWithDescription());
212
213 output << std::endl;
214
215 std::string tab = " ";
216
217 for (auto node: nodes()) {
218 if (children(node).size() > 0) {
219 for (auto child: children(node)) {
220 output << std::format(" \"{}\" -> \"{}\";\n",
221 variable(node).name(),
222 variable(child).name());
223 }
224 } else if (parents(node).size() == 0) {
225 output << std::format(" \"{}\";\n", variable(node).name());
226 }
228
229 output << "}" << std::endl;
230
231 return output.str();
232 }
233
234 /// Compute a parameter of the joint probability for the BN (given an
235 /// instantiation
236 /// of the vars)
237 template < GUM_Numeric GUM_SCALAR >
239 auto value = (GUM_SCALAR)1.0;
240
241 GUM_SCALAR tmp;
242
243 for (auto node: nodes()) {
244 if ((tmp = cpt(node)[i]) == (GUM_SCALAR)0) { return (GUM_SCALAR)0; }
245
246 value *= tmp;
247 }
248
249 return value;
250 }
251
255 template < GUM_Numeric GUM_SCALAR >
257 auto value = (GUM_SCALAR)0.0;
258
259 GUM_SCALAR tmp;
260
261 for (auto node: nodes()) {
262 if ((tmp = cpt(node)[i]) == (GUM_SCALAR)0) {
263 return (GUM_SCALAR)(-std::numeric_limits< double >::infinity());
264 }
265
266 value += std::log2(cpt(node)[i]);
267 }
268
269 return value;
270 }
271
272 template < GUM_Numeric GUM_SCALAR >
274 if (size() != from.size()) { return false; }
275
276 if (sizeArcs() != from.sizeArcs()) { return false; }
277
278 for (auto node: nodes()) {
279 const auto& v1 = variable(node);
280 if (!from.exists(v1.name())) { return false; }
281 const auto& v2 = from.variableFromName(v1.name());
282 if (v1 != v2) { return false; }
283 }
284
285 for (auto node: nodes()) {
286 NodeId fromnode = from.idFromName(variable(node).name());
287
288 if (cpt(node).nbrDim() != from.cpt(fromnode).nbrDim()) { return false; }
289
290 if (cpt(node).domainSize() != from.cpt(fromnode).domainSize()) { return false; }
291
292 for (Idx i = 0; i < cpt(node).nbrDim(); ++i) {
293 if (!from.cpt(fromnode).contains(from.variableFromName(cpt(node).variable(i).name()))) {
294 return false;
295 }
296 }
297
298 Instantiation i(cpt(node));
299 Instantiation j(from.cpt(fromnode));
300
302 for (i.setFirst(); !i.end(); i.inc()) {
303 for (Idx indice = 0; indice < cpt(node).nbrDim(); ++indice) {
304 const DiscreteVariable* p = &(i.variable(indice));
305 j.chgVal(j.pos(from.variableFromName(p->name())), i.val(*p));
306 }
307
308 if (cmp(cpt(node).get(i), from.cpt(fromnode).get(j))) { return false; }
309 }
310 }
311
312 return true;
313 }
314
315 template < GUM_Numeric GUM_SCALAR >
316 std::ostream& operator<<(std::ostream& output, const IBayesNet< GUM_SCALAR >& bn) {
317 output << bn.toString();
318 return output;
319 }
320
321 template < GUM_Numeric GUM_SCALAR >
322 std::vector< std::string > IBayesNet< GUM_SCALAR >::check() const {
323 std::vector< std::string > comments;
324
325 const double epsilon = 1e-8;
326 const double error_epsilon = 1e-1;
327
328 // CHECKING domain
329 for (const auto i: nodes())
330 if (variable(i).domainSize() < 2) {
331 std::stringstream s;
332 s << "Variable " << variable(i).name() << ": not consistent (domainSize=1).";
333 comments.push_back(s.str());
334 }
335
336 // CHECKING parameters are probabilities
337 // >0
338 for (const auto i: nodes()) {
339 const auto [amin, minval] = cpt(i).argmin();
340 if (minval < (GUM_SCALAR)0.0) {
341 std::stringstream s;
342 s << "Variable " << variable(i).name() << " : P(" << *(amin.begin()) << ") < 0.0";
343 comments.push_back(s.str());
344 }
345 }
346 // <1
347 for (const auto i: nodes()) {
348 const auto [amax, maxval] = cpt(i).argmax();
349 if (maxval > (GUM_SCALAR)1.0) {
350 std::stringstream s;
351 s << "Variable " << variable(i).name() << " : P(" << *(amax.begin()) << ") > 1.0";
352 comments.push_back(s.str());
353 }
354 }
355
356 // CHECKING distributions sum to 1
357 for (const auto i: nodes()) {
358 const auto p = cpt(i).sumOut({&variable(i)});
359 const auto [amin, minval] = p.argmin();
360 if (minval < (GUM_SCALAR)(1.0 - epsilon)) {
361 std::stringstream s;
362 s << "Variable " << variable(i).name() << " : ";
363 if (!parents(i).empty()) s << "with (at least) parents " << *(amin.begin()) << ", ";
364 s << "the CPT sum to less than 1";
365 if (minval > (GUM_SCALAR)(1.0 - error_epsilon)) s << " (normalization problem ?)";
366 s << ".";
367 comments.push_back(s.str());
368 continue;
369 }
370 const auto [amax, maxval] = p.argmax();
371 if (maxval > (GUM_SCALAR)(1.0 + epsilon)) {
372 std::stringstream s;
373 s << "Variable " << variable(i).name() << " : ";
374 if (!parents(i).empty()) s << "with (at least) parents " << *(amax.begin()) << ", ";
375 s << "the CPT sum to more than 1";
376 if (maxval < (GUM_SCALAR)(1.0 + error_epsilon)) s << " (normalization problem ?)";
377 s << ".";
378 comments.push_back(s.str());
379 }
380 }
381
382 return comments;
383 }
384
385 template < GUM_Numeric GUM_SCALAR >
386 Tensor< GUM_SCALAR > IBayesNet< GUM_SCALAR >::evEq(std::string_view name, double value) const {
387 return Tensor< GUM_SCALAR >::evEq(variableFromName(name), value);
388 }
389
390 template < GUM_Numeric GUM_SCALAR >
391 Tensor< GUM_SCALAR >
392 IBayesNet< GUM_SCALAR >::evIn(std::string_view name, double val1, double val2) const {
393 return Tensor< GUM_SCALAR >::evIn(variableFromName(name), val1, val2);
394 }
395
396 template < GUM_Numeric GUM_SCALAR >
397 Tensor< GUM_SCALAR > IBayesNet< GUM_SCALAR >::evGt(std::string_view name, double val) const {
399 }
400
401 template < GUM_Numeric GUM_SCALAR >
402 Tensor< GUM_SCALAR > IBayesNet< GUM_SCALAR >::evLt(std::string_view name, double val) const {
404 }
405} /* namespace gum */
Class representing the minimal interface for Bayesian network with no numerical data.
and aggregator
const Tensor< GUM_SCALAR > & cpt(NodeId varId) const final
const DiscreteVariable & variable(NodeId id) const override
DAGmodel()
Default constructor.
Definition DAGmodel.cpp:49
Size size() const final
const NodeSet & children(const NodeId id) const
DAGmodel & operator=(const DAGmodel &source)
Private copy operator.
Definition DAGmodel.cpp:62
bool exists(NodeId node) const final
Return true if this node exists in this graphical model.
const NodeSet & parents(const NodeId id) const
returns the set of nodes with arc ingoing to a given node
const NodeGraphPart & nodes() const final
Returns a named copy of the internal DAG: each node id is assigned the name of the corresponding vari...
NodeId idFromName(std::string_view name) const override
Returns the NodeId of a variable given its name.
const DiscreteVariable & variableFromName(std::string_view name) const override
Returns a constant reference over a variable given its name.
const DiscreteVariable & variable(NodeId id) const override
Returns a constant reference over a variable given its node id.
Base class for discrete random variable.
void setProperty(std::string_view name, std::string_view value)
Add or change a property of this GraphicalModel.
virtual bool empty() const
Return true if this graphical model is empty.
static std::string spaceCplxToString(double dSize, int dim, Size usedMem)
const std::string & propertyWithDefault(std::string_view name, const std::string &byDefault) const
Return the value of the property name of this GraphicalModel.
Class representing the minimal interface for Bayesian network with no numerical data.
Definition IBayesNet.h:75
Tensor< GUM_SCALAR > evGt(std::string_view name, double value) const
GUM_SCALAR minNonZeroParam() const
IBayesNet()
Default constructor.
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.
GUM_SCALAR maxParam() const
std::vector< std::string > check() const
Check if the BayesNet is consistent (variables, CPT).
~IBayesNet() override
Destructor.
Tensor< GUM_SCALAR > evIn(std::string_view name, double val1, double val2) const
Tensor< GUM_SCALAR > evLt(std::string_view name, double value) const
Size memoryFootprint() const
compute the (approximated) footprint in memory of the model (the footprints of CPTs)
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
std::string toString() const
GUM_SCALAR minParam() const
IBayesNet< GUM_SCALAR > & operator=(const IBayesNet< GUM_SCALAR > &source)
Copy operator.
virtual std::string toDot() const
Tensor< GUM_SCALAR > evEq(std::string_view name, double value) 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.
Class for assigning/browsing values to tuples of discrete variables.
Instantiation & chgVal(const DiscreteVariable &v, Idx newval)
Assign newval to variable v in the Instantiation.
bool end() const
Returns true if the Instantiation reached the end.
void inc()
Operator increment.
Idx pos(const DiscreteVariable &v) const final
Returns the position of the variable v.
Idx val(Idx i) const
Returns the current value of the variable at position i.
void setFirst()
Assign the first values to the tuple of the Instantiation.
const DiscreteVariable & variable(Idx i) const final
Returns the variable at position i in the tuple.
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
const std::string & name() const
returns the name of the variable
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
STL namespace.
or aggregator
Abstract class for generating Conditional Probability Tables.
Indicate whether two elements are (almost) different or not.
Definition utils_misc.h:164
Header of the Tensor class.