aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
informationTheory_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
49#include <utility>
50
54
56
57#define INFORMATION_THEORY_TEMPLATE \
58 template < template < typename > class INFERENCE_ENGINE, \
59 typename GUM_SCALAR > //@todo when CLANG-compliant for virtual class : requires
60 // JointTargettable< INFERENCE_ENGINE< GUM_SCALAR > >
61
62namespace gum {
65 INFERENCE_ENGINE< GUM_SCALAR >& engine,
68 gum::NodeSet Z) : engine_(engine), X_(std::move(X)), Y_(std::move(Y)), Z_(std::move(Z)) {
69 GUM_CONSTRUCTOR(InformationTheory)
70 if ((!(X_ * Y_).empty()) || (!(X_ * Z_).empty()) || (!(Z_ * Y_).empty()))
71 GUM_ERROR(OperationNotAllowed, "The intersection between the set of variables must be empty")
73 }
74
77 INFERENCE_ENGINE< GUM_SCALAR >& engine,
78 const gum::NodeSet& X,
79 const gum::NodeSet& Y) : InformationTheory(engine, X, Y, NodeSet()) {}
80
83 INFERENCE_ENGINE< GUM_SCALAR >& engine,
84 const std::vector< std::string >& Xnames,
85 const std::vector< std::string >& Ynames) :
86 InformationTheory< INFERENCE_ENGINE, GUM_SCALAR >(engine,
87 engine.model().nodeset(Xnames),
88 engine.model().nodeset(Ynames),
89 NodeSet()) {}
90
93 INFERENCE_ENGINE< GUM_SCALAR >& engine,
94 const std::vector< std::string >& Xnames,
95 const std::vector< std::string >& Ynames,
96 const std::vector< std::string >& Znames) :
97 InformationTheory< INFERENCE_ENGINE, GUM_SCALAR >(engine,
98 engine.model().nodeset(Xnames),
99 engine.model().nodeset(Ynames),
100 engine.model().nodeset(Znames)) {}
101
106
109 vX_.clear();
110 for (const auto x: X_)
111 vX_.insert(&engine_.model().variable(x));
112
113 vY_.clear();
114 for (const auto y: Y_)
115 vY_.insert(&engine_.model().variable(y));
116
117 vZ_.clear();
118 for (const auto z: Z_)
119 vZ_.insert(&engine_.model().variable(z));
120
121 const NodeSet joint_vars = X_ + Y_ + Z_;
122 if (!engine_.isJointTarget(joint_vars)) {
123 // we check if it is not an implicit target : containng a node and some of its parent (could
124 // be better)
125 bool implicit_target = false;
126 for (const auto node: joint_vars)
127 if (engine_.model().family(node).isSupersetOrEqual(joint_vars)) {
128 implicit_target = true;
129 break;
130 }
131 if (!implicit_target) {
132 engine_.eraseAllJointTargets();
133 engine_.addJointTarget(joint_vars);
134 }
135 }
136 engine_.makeInference();
137
138 if (!Z_.empty()) {
139 pXYZ_ = engine_.jointPosterior(joint_vars);
140 pXZ_ = pXYZ_.sumIn(vX_ + vZ_);
141 pYZ_ = pXYZ_.sumIn(vY_ + vZ_);
142 pZ_ = pXZ_.sumIn(vZ_);
143 pXY_ = pXYZ_.sumIn(vX_ + vY_);
144 } else {
145 pXY_ = engine_.jointPosterior(joint_vars);
146 }
147 pX_ = pXY_.sumIn(vX_);
148 pY_ = pXY_.sumIn(vY_);
149 }
150
153
156
159 return pXY_.entropy();
160 }
161
164 return -pXY_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
165 // f(x,y)=log (p(x,y)/p(y))
166 const auto& pxy = pXY_[i];
167 if (pxy == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
168
169 const auto& py = pY_[i];
170 if (py == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
171
172 return GUM_LOG2_OR_0(pxy / py);
173 });
174 }
175
178 return -pXY_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
179 // f(x,y)=log (p(x,y)/p(x))
180 const auto& pxy = pXY_[i];
181 if (pxy == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
182
183 const auto& px = pX_[i];
184 if (px == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
185
186 return GUM_LOG2_OR_0(pxy / px);
187 });
188 }
189
192 if (Z_.empty()) GUM_ERROR(ArgumentError, "Z has not been specified.")
193 return -pXZ_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
194 // f(x,z)=log (p(x,z)/p(z))
195 const auto& pxz = pXZ_[i];
196 if (pxz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
197
198 const auto& pz = pZ_[i];
199 if (pz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
200
201 return GUM_LOG2_OR_0(pxz / pz);
202 });
203 }
204
207 if (Z_.empty()) GUM_ERROR(ArgumentError, "Z has not been specified.")
208 return -pYZ_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
209 // f(y,z)=log (p(y,z)/p(z))
210 const auto& pyz = pYZ_[i];
211 if (pyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
212
213 const auto& pz = pZ_[i];
214 if (pz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
215
216 return GUM_LOG2_OR_0(pyz / pz);
217 });
218 }
219
222 return pXY_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
223 // f(x,y)=log (p(x,y)/p(x)p(y))
224 const auto& pxy = pXY_[i];
225 if (pxy == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
226
227 const auto& pxpy = pY_[i] * pX_[i];
228 if (pxpy == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
229
230 return GUM_LOG2_OR_0(pxy / pxpy);
231 });
232 }
233
236 return -pXY_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
237 // f(x,y)= -log(p(x)*p(y))
238 return GUM_LOG2_OR_0(pY_[i] * pX_[i]);
239 });
240 }
241
244 if (Z_.empty()) GUM_ERROR(ArgumentError, "Z has not been specified.")
245 return pXYZ_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
246 // f(x,y,z)= -log(p(x,y,z)/p(z))
247 const auto& pxyz = pXYZ_[i];
248 if (pxyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
249
250 const auto& pz = pZ_[i];
251 if (pz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
252
253 return -GUM_LOG2_OR_0(pxyz / pz);
254 });
255 }
256
259 if (Z_.empty()) GUM_ERROR(ArgumentError, "Z has not been specified.")
260 return pXYZ_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
261 // f(x,y,z)= -log(p(x,y,z)/p(y,z))
262 const auto& pxyz = pXYZ_[i];
263 if (pxyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
264
265 const auto& pyz = pYZ_[i];
266 if (pyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
267
268 return -GUM_LOG2_OR_0(pxyz / pyz);
269 });
270 }
271
274 if (Z_.empty()) GUM_ERROR(ArgumentError, "Z has not been specified.")
275 return pXYZ_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
276 // f(x,y)=log (p(x,y)/p(x)p(y))
277 const auto& pzpxyz = pXYZ_[i] * pZ_[i];
278 if (pzpxyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
279
280 const auto& pxzpyz = pXZ_[i] * pYZ_[i];
281 if (pxzpyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
282
283 return GUM_LOG2_OR_0(pzpxyz / pxzpyz);
284 });
285 }
286
287#undef INFORMATION_THEORY_TEMPLATE
288} // namespace gum
Exception base for argument error.
Tensor< GUM_SCALAR > pY_
Tensor< GUM_SCALAR > pXYZ_
Tensor< GUM_SCALAR > pX_
InformationTheory(INFERENCE_ENGINE< GUM_SCALAR > &engine, NodeSet X, NodeSet Y, NodeSet Z)
Tensor< GUM_SCALAR > pXZ_
Tensor< GUM_SCALAR > pYZ_
Tensor< GUM_SCALAR > pZ_
INFERENCE_ENGINE< GUM_SCALAR > & engine_
Tensor< GUM_SCALAR > pXY_
Class for assigning/browsing values to tuples of discrete variables.
Exception : operation not allowed.
aGrUM's exceptions
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
Class encapsulating computations of notions from Information Theory.
#define INFORMATION_THEORY_TEMPLATE
Implementation of a Shafer-Shenoy's-like version of lazy propagation for inference in Bayesian networ...
Useful macros for maths.
#define GUM_LOG2_OR_0(x)
Definition math_utils.h:70
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
STL namespace.