aGrUM 2.3.2
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-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
48#include <utility>
49
53
55
56#define INFORMATION_THEORY_TEMPLATE \
57 template < template < typename > class INFERENCE_ENGINE, \
58 typename GUM_SCALAR > //@todo when CLANG-compliant for virtual class : requires
59 // JointTargettable< INFERENCE_ENGINE< GUM_SCALAR > >
60
61namespace gum {
64 INFERENCE_ENGINE< GUM_SCALAR >& engine,
67 gum::NodeSet Z) : engine_(engine), X_(std::move(X)), Y_(std::move(Y)), Z_(std::move(Z)) {
68 GUM_CONSTRUCTOR(InformationTheory)
69 if ((!(X_ * Y_).empty()) || (!(X_ * Z_).empty()) || (!(Z_ * Y_).empty()))
70 GUM_ERROR(OperationNotAllowed, "The intersection between the set of variables must be empty")
72 }
73
76 INFERENCE_ENGINE< GUM_SCALAR >& engine,
77 const gum::NodeSet& X,
78 const gum::NodeSet& Y) : InformationTheory(engine, X, Y, NodeSet()) {}
79
82 INFERENCE_ENGINE< GUM_SCALAR >& engine,
83 const std::vector< std::string >& Xnames,
84 const std::vector< std::string >& Ynames) :
85 InformationTheory< INFERENCE_ENGINE, GUM_SCALAR >(engine,
86 engine.model().nodeset(Xnames),
87 engine.model().nodeset(Ynames),
88 NodeSet()) {}
89
92 INFERENCE_ENGINE< GUM_SCALAR >& engine,
93 const std::vector< std::string >& Xnames,
94 const std::vector< std::string >& Ynames,
95 const std::vector< std::string >& Znames) :
96 InformationTheory< INFERENCE_ENGINE, GUM_SCALAR >(engine,
97 engine.model().nodeset(Xnames),
98 engine.model().nodeset(Ynames),
99 engine.model().nodeset(Znames)) {}
100
105
108 vX_.clear();
109 for (const auto x: X_)
110 vX_.insert(&engine_.model().variable(x));
111
112 vY_.clear();
113 for (const auto y: Y_)
114 vY_.insert(&engine_.model().variable(y));
115
116 vZ_.clear();
117 for (const auto z: Z_)
118 vZ_.insert(&engine_.model().variable(z));
119
120 const NodeSet joint_vars = X_ + Y_ + Z_;
121 if (!engine_.isJointTarget(joint_vars)) {
122 // we check if it is not an implicit target : containng a node and some of its parent (could
123 // be better)
124 bool implicit_target = false;
125 for (const auto node: joint_vars)
126 if (engine_.model().family(node).isSupersetOrEqual(joint_vars)) {
127 implicit_target = true;
128 break;
129 }
130 if (!implicit_target) {
131 engine_.eraseAllJointTargets();
132 engine_.addJointTarget(joint_vars);
133 }
134 }
135 engine_.makeInference();
136
137 if (!Z_.empty()) {
138 pXYZ_ = engine_.jointPosterior(joint_vars);
139 pXZ_ = pXYZ_.sumIn(vX_ + vZ_);
140 pYZ_ = pXYZ_.sumIn(vY_ + vZ_);
141 pZ_ = pXZ_.sumIn(vZ_);
142 pXY_ = pXYZ_.sumIn(vX_ + vY_);
143 } else {
144 pXY_ = engine_.jointPosterior(joint_vars);
145 }
146 pX_ = pXY_.sumIn(vX_);
147 pY_ = pXY_.sumIn(vY_);
148 }
149
152
155
158 return pXY_.entropy();
159 }
160
163 return -pXY_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
164 // f(x,y)=log (p(x,y)/p(y))
165 const auto& pxy = pXY_[i];
166 if (pxy == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
167
168 const auto& py = pY_[i];
169 if (py == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
170
171 return GUM_LOG2_OR_0(pxy / py);
172 });
173 }
174
177 return -pXY_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
178 // f(x,y)=log (p(x,y)/p(x))
179 const auto& pxy = pXY_[i];
180 if (pxy == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
181
182 const auto& px = pX_[i];
183 if (px == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
184
185 return GUM_LOG2_OR_0(pxy / px);
186 });
187 }
188
191 if (Z_.empty()) GUM_ERROR(ArgumentError, "Z has not been specified.")
192 return -pXZ_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
193 // f(x,z)=log (p(x,z)/p(y))
194 const auto& pxz = pXZ_[i];
195 if (pxz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
196
197 const auto& pz = pZ_[i];
198 if (pz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
199
200 return GUM_LOG2_OR_0(pxz / pz);
201 });
202 }
203
206 if (Z_.empty()) GUM_ERROR(ArgumentError, "Z has not been specified.")
207 return -pYZ_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
208 // f(y,z)=log (p(y,z)/p(z))
209 const auto& pyz = pYZ_[i];
210 if (pyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
211
212 const auto& pz = pZ_[i];
213 if (pz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
214
215 return GUM_LOG2_OR_0(pyz / pz);
216 });
217 }
218
221 return pXY_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
222 // f(x,y)=log (p(x,y)/p(x)p(y))
223 const auto& pxy = pXY_[i];
224 if (pxy == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
225
226 const auto& pxpy = pY_[i] * pX_[i];
227 if (pxpy == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
228
229 return GUM_LOG2_OR_0(pxy / pxpy);
230 });
231 }
232
235 return -pXY_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
236 // f(x,y)= p(x)p(y))
237 return GUM_LOG2_OR_0(pY_[i] * pX_[i]);
238 });
239 }
240
243 if (Z_.empty()) GUM_ERROR(ArgumentError, "Z has not been specified.")
244 return pXYZ_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
245 // f(x,y)=log (p(x,y)/p(y))
246 const auto& pxyz = pXYZ_[i];
247 if (pxyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
248
249 const auto& pz = pZ_[i];
250 if (pz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
251
252 return -GUM_LOG2_OR_0(pxyz / pz);
253 });
254 }
255
258 if (Z_.empty()) GUM_ERROR(ArgumentError, "Z has not been specified.")
259 return pXYZ_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
260 // f(x,y)=log (p(x,y)/p(y))
261 const auto& pxyz = pXYZ_[i];
262 if (pxyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
263
264 const auto& pyz = pYZ_[i];
265 if (pyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
266
267 return -GUM_LOG2_OR_0(pxyz / pyz);
268 });
269 }
270
273 if (Z_.empty()) GUM_ERROR(ArgumentError, "Z has not been specified.")
274 return pXYZ_.expectedValue([this](const gum::Instantiation& i) -> GUM_SCALAR {
275 // f(x,y)=log (p(x,y)/p(x)p(y))
276 const auto& pzpxyz = pXYZ_[i] * pZ_[i];
277 if (pzpxyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
278
279 const auto& pxzpyz = pXZ_[i] * pYZ_[i];
280 if (pxzpyz == GUM_SCALAR(0.0)) return GUM_SCALAR(0.0);
281
282 return GUM_LOG2_OR_0(pzpxyz / pxzpyz);
283 });
284 }
285
286#undef INFORMATION_THEORY_TEMPLATE
287} // 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:72
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.