aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
aggregatorDecomposition_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
51#include <list>
52#include <typeinfo>
53
55
56namespace gum {
57
58 template < GUM_Numeric GUM_SCALAR >
62
63 template < GUM_Numeric GUM_SCALAR >
67
68 template < GUM_Numeric GUM_SCALAR >
69 BayesNet< GUM_SCALAR >&
71 for (NodeId node: bn.nodes().asNodeSet()) {
72 std::string description = bn.cpt(node).toString();
73 if (auto p = dynamic_cast< const gum::aggregator::MultiDimAggregator< GUM_SCALAR >* >(
74 bn.cpt(node).content());
75 p != nullptr && p->isDecomposable()) {
76 decomposeAggregator_(bn, node);
77 }
78 }
79 return bn;
80 }
81
82 template < GUM_Numeric GUM_SCALAR >
84 std::string_view aggType,
85 const DiscreteVariable& var,
86 Idx value) {
87 return bn._addAggregator_(aggType, var, value);
88 }
89
90 template < GUM_Numeric GUM_SCALAR >
91 BayesNet< GUM_SCALAR >&
93 NodeId initialAggregator) {
94 auto p = static_cast< const gum::aggregator::MultiDimAggregator< GUM_SCALAR >* >(
95 bn.cpt(initialAggregator).content());
96 auto newAgg = bn.variable(initialAggregator).clone();
97
98 Set< NodeId > parents = bn.parents(initialAggregator);
99
100 std::list< NodeId > orderedParents = {};
101
102 for (const auto& elt: parents) {
103 orderedParents.push_back(elt);
104 }
105
106 orderedParents.sort();
107
108 auto newAggs = Set< NodeId >();
109 List< NodeId > newAggParents;
110
111 const gum::Size arity = getMaximumArity();
112 gum::Size q = 0;
113 gum::Size i = 0;
114
115 long minVal = 0;
116 long maxVal = 0;
117
118 int j = 1;
119
120 std::string newName
121 = std::string(bn.variable(initialAggregator).name()) + "_" + std::to_string(j);
122 const std::string aggType = p->aggregatorName();
123
124 for (auto parent: parents) {
125 bn.eraseArc(parent, initialAggregator);
126 }
127
128 /*
129 * We are constructing the new aggregator with a clone of the former
130 */
131 newAgg->setName(newName);
132 newAgg->setDescription(aggType);
133
134 // for(Set<NodeId>::iterator it = parents.begin(); it!= parents.end(); ++it){
135 // for (auto it = orderedParents.begin(); it != orderedParents.end(); ++it) {
136 for (const auto& parent: orderedParents) {
137 if (q < parents.size() - parents.size() % arity) {
138 if (i == arity) {
139 i = 0;
140 j++;
141
142 if (newAgg->varType() == VarType::LABELIZED) {
143 addAggregator_(bn, aggType, *newAgg, p->domainSize());
144 } else if (newAgg->varType() == VarType::RANGE) {
145 static_cast< RangeVariable* >(newAgg)->setMinVal(minVal);
146 static_cast< RangeVariable* >(newAgg)->setMaxVal(maxVal);
147 addAggregator_(bn, aggType, *newAgg, 0);
148 } else {
149 GUM_ERROR(OperationNotAllowed, "Decomposition is not available for type : " + aggType)
150 }
151
152 /*
153 * Adding arcs in the new node from its parents and adding thoses into
154 * the temporary tensor
155 */
156 for (NodeId node: newAggParents) {
157 bn.addArc(node, bn.idFromName(newName));
158 }
159
160 /*
161 * Adding the new aggregator in t
162 */
163 newAggs.insert(bn.idFromName(newName));
164
165 newAggParents.clear();
166
167 minVal = 0;
168 maxVal = 0;
169
170 newName = std::string(bn.variable(initialAggregator).name()) + "_" + std::to_string(j);
171
172 delete (newAgg);
173 newAgg = bn.variable(initialAggregator).clone();
174 newAgg->setName(newName);
175 newAgg->setDescription(aggType);
176
177 if (bn.variable(parent).varType() == VarType::RANGE) {
178 minVal += static_cast< const RangeVariable& >(bn.variable(parent)).minVal();
179 maxVal += static_cast< const RangeVariable& >(bn.variable(parent)).maxVal();
180 }
181
182 newAggParents.push_back(parent);
183 i++;
184 } else {
185 if (bn.variable(parent).varType() == VarType::RANGE) {
186 minVal += static_cast< const RangeVariable& >(bn.variable(parent)).minVal();
187 maxVal += static_cast< const RangeVariable& >(bn.variable(parent)).maxVal();
188 }
189
190 newAggParents.push_back(parent);
191 i++;
192 }
193 } else {
194 newAggs.insert(parent);
195 }
196 q++;
197 }
198
199 if (newAgg->varType() == VarType::LABELIZED) {
200 addAggregator_(bn, aggType, *newAgg, p->domainSize());
201 } else if (newAgg->varType() == VarType::RANGE) {
202 static_cast< RangeVariable* >(newAgg)->setMinVal(minVal);
203 static_cast< RangeVariable* >(newAgg)->setMaxVal(maxVal);
204 addAggregator_(bn, aggType, *newAgg, 0);
205 } else {
206 GUM_ERROR(OperationNotAllowed, "Decomposition is not available for type : " + aggType)
207 }
208
209 newAggs.insert(bn.idFromName(newName));
210
211 for (NodeId node: newAggParents) {
212 bn.addArc(node, bn.idFromName(newName));
213 }
214
215 for (auto agg: addDepthLayer_(bn, newAggs, initialAggregator, j)) {
216 bn.addArc(agg, initialAggregator);
217 }
218
219 delete (newAgg);
220 return bn;
221 }
222
223 template < GUM_Numeric GUM_SCALAR >
225 Set< NodeId > nodes,
226 NodeId initialAggregator,
227 int& j) {
228 auto p = static_cast< const gum::aggregator::MultiDimAggregator< GUM_SCALAR >* >(
229 bn.cpt(initialAggregator).content());
230
231 gum::Size arity = getMaximumArity();
232 std::string aggType = p->aggregatorName();
233
234 if (nodes.size() <= arity) {
235 return nodes;
236 } else {
237 auto newAgg = bn.variable(initialAggregator).clone();
238
239 auto newAggs = Set< NodeId >();
240
241 List< NodeId > newAggParents;
242
243 std::list< NodeId > orderedParents = {};
244
245 for (const auto& elt: nodes) {
246 orderedParents.push_back(elt);
247 }
248
249 orderedParents.sort();
250
251 gum::Size i = 0;
252 gum::Size q = 0;
253 long minVal = 0;
254 long maxVal = 0;
255
256 j++;
257
258 std::string newName
259 = std::string(bn.variable(initialAggregator).name()) + "_" + std::to_string(j);
260
261 newAgg->setName(newName);
262 newAgg->setDescription(aggType);
263
264 // for(Set<NodeId>::iterator it = nodes.begin(); it!= nodes.end(); ++it){
265 // for (auto it = orderedParents.begin(); it != orderedParents.end(); ++it) {
266 for (const auto parent: orderedParents) {
267 if (q < nodes.size() - nodes.size() % arity) {
268 if (i == arity) {
269 i = 0;
270 j++;
271
272 if (newAgg->varType() == VarType::LABELIZED) {
273 addAggregator_(bn, aggType, *newAgg, p->domainSize());
274 } else if (newAgg->varType() == VarType::RANGE) {
275 static_cast< RangeVariable* >(newAgg)->setMinVal(minVal);
276 static_cast< RangeVariable* >(newAgg)->setMaxVal(maxVal);
277 addAggregator_(bn, aggType, *newAgg, 0);
278 } else {
279 GUM_ERROR(OperationNotAllowed, "Decomposition is not available for type : " + aggType)
280 }
281
282 for (NodeId node: newAggParents) {
283 bn.addArc(node, bn.idFromName(newName));
284 }
285
286 newAggs.insert(bn.idFromName(newName));
287
288 newAggParents.clear();
289
290 minVal = 0;
291 maxVal = 0;
292
293 newName = std::string(bn.variable(initialAggregator).name()) + "_" + std::to_string(j);
294
295 delete newAgg;
296 newAgg = bn.variable(initialAggregator).clone();
297 newAgg->setName(newName);
298 newAgg->setDescription(aggType);
299
300 if (bn.variable(parent).varType() == VarType::RANGE) {
301 minVal += static_cast< const RangeVariable& >(bn.variable(parent)).minVal();
302 maxVal += static_cast< const RangeVariable& >(bn.variable(parent)).maxVal();
303 }
304
305 newAggParents.push_back(parent);
306 i++;
307 } else {
308 if (bn.variable(parent).varType() == VarType::RANGE) {
309 minVal += static_cast< const RangeVariable& >(bn.variable(parent)).minVal();
310 maxVal += static_cast< const RangeVariable& >(bn.variable(parent)).maxVal();
311 }
312
313 newAggParents.push_back(parent);
314 i++;
315 }
316 } else {
317 newAggs.insert(parent);
318 }
319 q++;
320 }
321
322 if (newAgg->varType() == VarType::LABELIZED) {
323 addAggregator_(bn, aggType, *newAgg, p->domainSize());
324 } else if (newAgg->varType() == VarType::RANGE) {
325 static_cast< RangeVariable* >(newAgg)->setMinVal(minVal);
326 static_cast< RangeVariable* >(newAgg)->setMaxVal(maxVal);
327 addAggregator_(bn, aggType, *newAgg, 0);
328 } else {
329 GUM_ERROR(OperationNotAllowed, "Decomposition is not available for type : " + aggType)
330 }
331
332 newAggs.insert(bn.idFromName(newName));
333
334 for (NodeId node: newAggParents) {
335 bn.addArc(node, bn.idFromName(newName));
336 }
337
338 delete newAgg;
339 return addDepthLayer_(bn, newAggs, initialAggregator, j);
340 }
341 }
342
343 template < GUM_Numeric GUM_SCALAR >
345 if (arity < 2) { GUM_ERROR(OperationNotAllowed, "Maximum arity should be at least 2") }
346 _arity_ = arity;
347 }
348
349 template < GUM_Numeric GUM_SCALAR >
353
354 template < GUM_Numeric GUM_SCALAR >
356 return "aggregator decomposition";
357 }
358
359} /* namespace gum */
Headers of AggregatorDecomposition.
Set< NodeId > addDepthLayer_(BayesNet< GUM_SCALAR > &bn, Set< NodeId > nodes, NodeId initialAggregator, int &j)
BayesNet< GUM_SCALAR > & decomposeAggregator_(BayesNet< GUM_SCALAR > &bn, NodeId node)
BayesNet< GUM_SCALAR > & getDecomposedAggregator(BayesNet< GUM_SCALAR > &bn)
Default constructor.
NodeId addAggregator_(BayesNet< GUM_SCALAR > &bn, std::string_view aggType, const DiscreteVariable &var, Idx value)
Base class for discrete random variable.
Generic doubly linked lists.
Definition list.h:378
Val & push_back(Args &&... args)
An alias for pushBack used for STL compliance.
Definition list_tpl.h:1494
Exception : operation not allowed.
Defines a discrete random variable over an integer interval.
long maxVal() const
Returns the upper bound.
long minVal() const
Returns the lower bound.
Size size() const noexcept
Returns the number of elements in the set.
Definition set_tpl.h:607
#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 Idx
Type for indexes.
Definition types.h:79
Size NodeId
Type for node ids.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46