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