aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
partialInstantiationPattern4MultiDimArray.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
41
50
52
53// check if we allowed these patterns to be used
54#ifndef GUM_PARTIAL_INSTANTIATION_PATTERN_ALLOWED
55
56// #warning To use partialIntantiationPattern, you must define
57// GUM_PARTIAL_INSTANTIATION_PATTERN_ALLOWED
58
59#else
60namespace gum {
61
62 // a specialized function instantiating some variables of a table and returning
63 // the result
64
65# ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_NAME
66# define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE GUM_SCALAR
67
68 template < typename GUM_SCALAR >
70 const MultiDimArray< GUM_SCALAR >* table,
72# endif
73
74 // clang-format off
75
76#ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_NAME
77#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE GUM_SCALAR *
78#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
79 template <typename GUM_SCALAR>
82 const MultiDimArray<GUM_SCALAR*>* table,
84#endif
85
86#ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_IMPL2ARRAY_NAME
87#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE GUM_SCALAR
88 template <typename GUM_SCALAR>
93#endif
94
95#ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_IMPL2ARRAY_NAME
96#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE GUM_SCALAR *
97#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
98 template <typename GUM_SCALAR>
103#endif
104
105 // clang-format on
106
107 {
108# ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_IMPL2ARRAY_NAME
109 const MultiDimArray< GUM_SCALAR >* table
110 = reinterpret_cast< const MultiDimArray< GUM_SCALAR >* >(ttable);
111# endif
112
113# ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_IMPL2ARRAY_NAME
115 = reinterpret_cast< const MultiDimArray< GUM_SCALAR* >* >(ttable);
116# endif
117 // get the variables of the uninstantiated table
118 const Sequence< const DiscreteVariable* >& table_vars = table->variablesSequence();
119
120 // Compute the offset of the variables. In addition, get the offset in
121 // table induced by the instantiation inst_var
122 Idx table_alone_offset = 0;
123 Idx offset = 1;
124 HashTable< const DiscreteVariable*, Idx > var1offset(table_vars.size());
125
126 for (const auto var: table_vars) {
127 if (inst_vars.exists(var)) table_alone_offset += inst_vars[var] * offset;
128
129 var1offset.insert(var, offset);
130 offset *= var->domainSize();
131 }
132
133 // Compute the sequence of variables in the result table. Compute as well
134 // the offsets and the domain size of the variables that belong to result.
135 // Finally, compute has_before_incr: this is a Boolean indicating whether
136 // the instantiated variables are the last variables in the variables
137 // sequence of table (true) or not (false). If this Boolean is true, then
138 // we can fill result by parsing both table and result using only
139 // 1-increments.
141 std::vector< Idx > table_and_result_offset;
142 std::vector< Idx > table_and_result_domain;
143 Idx result_domain_size = 1;
144 bool has_before_incr = true;
145 bool found_inst_var = false;
146
147 for (const auto var: table_vars) {
148 if (!inst_vars.exists(var)) {
149 table_and_result_domain.push_back(var->domainSize());
150 table_and_result_offset.push_back(var1offset[var]);
151 result_domain_size *= var->domainSize();
152 result_varSeq << var;
153
154 if (found_inst_var) has_before_incr = false;
155 } else {
156 found_inst_var = true;
157 }
158 }
159
160 // table_and_result_value is a vector indictating, for each uninstantiated
161 // variable, how many increments we can still perform on that variable
162 // before we must perform a "major" increment: for instance, let A and B be
163 // two variables of size 10. Then, if table_and_result_value[A] = 3 and
164 // table_and_result_value[B] = 2, this means that the offset they represent
165 // is 78 (10^2 - 32). If we still increment B twice, then the offset should
166 // be 80, which means that we shall increment A once and decrease B by 10.
167 // The value by which variables shall be decreased is indicated in
168 // table_and_result_down
169 std::vector< Idx > table_and_result_value = table_and_result_domain;
170 std::vector< Idx > table_and_result_down = table_and_result_offset;
171
172 for (unsigned int i = 0; i < table_and_result_down.size(); ++i) {
173 table_and_result_down[i] *= (table_and_result_domain[i] - 1);
174 }
175
176 // create a table "result" containing only the variables that are not
177 // instantiated: the variables are stored in the order in which they appear
178 // in "table". Hence, ++ operations on an instantiation on table will more
179 // or less correspond to a ++ operation on an instantiation on result
182 result->beginMultipleChanges();
183
184 for (const auto var: result_varSeq)
185 *result << *var;
186
187 result->endMultipleChanges();
188
189# ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
190 // fill the matrix with any element
191 {
192 const GUM_SCALAR& any_element = *(table->unsafeGet(0));
193
194 for (Idx i = 0; i < result_domain_size; ++i) {
195 result->unsafeSet(i, new GUM_SCALAR(any_element));
196 }
197 }
198# endif /* GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER */
199
200 // compute the result: it is now sufficient to loop over the variables that
201 // were not instantiated. ptable and presult are pointers on the arrays
202 // that are directly used for this loop
203 GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE* ptable
204 = const_cast< GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE* >(
205 &(table->unsafeGet(table_alone_offset)));
206 GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE* presult
207 = const_cast< GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE* >(&(result->unsafeGet(0)));
208
209 // but before doing so, check whether the instantiated variables are the
210 // last ones or not. If so, we can optimize the parsing of ptable and
211 // presult as both tables need be parsed using only 1-increments
212 if (has_before_incr) {
213 for (Idx i = 0; i < result_domain_size; ++i) {
214# ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
215 **presult = **ptable;
216# else
217 *presult = *ptable;
218# endif
219
220 // update the offset of result and table
221 ++ptable;
222 ++presult;
223 }
224 } else {
225 // here, some uninstantiated variables exist after the instantiated ones
226 // in the variables sequence of table. So, we must perform a more
227 // complicated parsing of ptable
228 Idx table_offset = 0;
229
230 for (Idx j = 0; j < result_domain_size; ++j) {
231# ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
232 **presult = *(ptable[table_offset]);
233# else
234 *presult = ptable[table_offset];
235# endif
236
237 // update the offset of table
238 for (unsigned int k = 0; k < table_and_result_value.size(); ++k) {
239 --table_and_result_value[k];
240
241 if (table_and_result_value[k]) {
242 table_offset += table_and_result_offset[k];
243 break;
244 }
245
246 table_and_result_value[k] = table_and_result_domain[k];
247 table_offset -= table_and_result_down[k];
248 }
249
250 // update the offset of result
251 ++presult;
252 }
253 }
254
255 return result;
256 }
257
258# undef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE
259
260# ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
261# undef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
262# endif
263
264} /* End of namespace gum */
265
266#endif /* GUM_PARTIAL_INSTANTIATION_PATTERN_ALLOWED */
The class for generic Hash Tables.
Definition hashTable.h:637
Multidimensional matrix stored as an array in memory.
<agrum/base/multidim/multiDimImplementation.h>
void beginMultipleChanges() override
Call this method before doing important changes in this MultiDimContainer.
The generic class for storing (ordered) sequences of objects.
Definition sequence.h:972
Size Idx
Type for indexes.
Definition types.h:79
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_IMPL2ARRAY_NAME
#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_NAME
#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_IMPL2ARRAY_NAME
#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_NAME
a specialized partial instantiation function for multiDimArrays
Header file of gum::Sequence, a class for storing (ordered) sequences of objects.