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