aGrUM  0.14.2
partialInstantiationPattern4MultiDimArray.h
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005 by Pierre-Henri WUILLEMIN et Christophe GONZALES *
3  * {prenom.nom}_at_lip6.fr *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
29 #include <agrum/core/sequence.h>
30 
31 // check if we allowed these patterns to be used
32 #ifndef GUM_PARTIAL_INSTANTIATION_PATTERN_ALLOWED
33 
34 // #warning To use partialIntantiationPattern, you must define
35 // GUM_PARTIAL_INSTANTIATION_PATTERN_ALLOWED
36 
37 #else
38 namespace gum {
39 
40  // a specialized function instantiating some variables of a table and returning
41  // the result
42 
43 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_NAME
44 # define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE GUM_SCALAR
45  template < typename GUM_SCALAR >
46  MultiDimArray< GUM_SCALAR >* GUM_MULTI_DIM_PARTIAL_INSTANTIATION_NAME(
47  const MultiDimArray< GUM_SCALAR >* table,
48  const HashTable< const DiscreteVariable*, Idx >& inst_vars)
49 # endif
50 
51  // clang-format off
52 
53 #ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_NAME
54 #define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE GUM_SCALAR *
55 #define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
56  template <typename GUM_SCALAR>
57  MultiDimArray<GUM_SCALAR*>*
59  const MultiDimArray<GUM_SCALAR*>* table,
60  const HashTable<const DiscreteVariable*, Idx>& inst_vars )
61 #endif
62 
63 #ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_IMPL2ARRAY_NAME
64 #define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE GUM_SCALAR
65  template <typename GUM_SCALAR>
66  MultiDimImplementation<GUM_SCALAR>*
68  const MultiDimImplementation<GUM_SCALAR>* ttable,
69  const HashTable<const DiscreteVariable*, Idx>& inst_vars )
70 #endif
71 
72 #ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_IMPL2ARRAY_NAME
73 #define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE GUM_SCALAR *
74 #define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
75  template <typename GUM_SCALAR>
76  MultiDimImplementation<GUM_SCALAR*>*
78  const MultiDimImplementation<GUM_SCALAR*>* ttable,
79  const HashTable<const DiscreteVariable*, Idx>& inst_vars )
80 #endif
81 
82  // clang-format on
83 
84  {
85 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_IMPL2ARRAY_NAME
86  const MultiDimArray< GUM_SCALAR >* table =
87  reinterpret_cast< const MultiDimArray< GUM_SCALAR >* >(ttable);
88 # endif
89 
90 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_IMPL2ARRAY_NAME
91  const MultiDimArray< GUM_SCALAR* >* table =
92  reinterpret_cast< const MultiDimArray< GUM_SCALAR* >* >(ttable);
93 # endif
94  // get the variables of the uninstantiated table
95  const Sequence< const DiscreteVariable* >& table_vars =
96  table->variablesSequence();
97 
98  // Compute the offset of the variables. In addition, get the offset in
99  // table induced by the instantiation inst_var
100  Idx table_alone_offset = 0;
101  Idx offset = 1;
102  HashTable< const DiscreteVariable*, Idx > var1offset(table_vars.size());
103 
104  for (const auto var : table_vars) {
105  if (inst_vars.exists(var)) table_alone_offset += inst_vars[var] * offset;
106 
107  var1offset.insert(var, offset);
108  offset *= var->domainSize();
109  }
110 
111  // Compute the sequence of variables in the result table. Compute as well
112  // the offsets and the domain size of the variables that belong to result.
113  // Finally, compute has_before_incr: this is a Boolean indicating whether
114  // the instantiated variables are the last variables in the variables
115  // sequence of table (true) or not (false). If this Boolean is true, then
116  // we can fill result by parsing both table and result using only
117  // 1-increments.
118  Sequence< const DiscreteVariable* > result_varSeq;
119  std::vector< Idx > table_and_result_offset;
120  std::vector< Idx > table_and_result_domain;
121  Idx result_domain_size = 1;
122  bool has_before_incr = true;
123  bool found_inst_var = false;
124 
125  for (const auto var : table_vars) {
126  if (!inst_vars.exists(var)) {
127  table_and_result_domain.push_back(var->domainSize());
128  table_and_result_offset.push_back(var1offset[var]);
129  result_domain_size *= var->domainSize();
130  result_varSeq << var;
131 
132  if (found_inst_var) has_before_incr = false;
133  } else {
134  found_inst_var = true;
135  }
136  }
137 
138  // table_and_result_value is a vector indictating, for each uninstantiated
139  // variable, how many increments we can still perform on that variable
140  // before we must perform a "major" increment: for instance, let A and B be
141  // two variables of size 10. Then, if table_and_result_value[A] = 3 and
142  // table_and_result_value[B] = 2, this means that the offset they represent
143  // is 78 (10^2 - 32). If we still increment B twice, then the offset should
144  // be 80, which means that we shall increment A once and decrease B by 10.
145  // The value by which variables shall be decreased is indicated in
146  // table_and_result_down
147  std::vector< Idx > table_and_result_value = table_and_result_domain;
148  std::vector< Idx > table_and_result_down = table_and_result_offset;
149 
150  for (unsigned int i = 0; i < table_and_result_down.size(); ++i) {
151  table_and_result_down[i] *= (table_and_result_domain[i] - 1);
152  }
153 
154  // create a table "result" containing only the variables that are not
155  // instantiated: the variables are stored in the order in which they appear
156  // in "table". Hence, ++ operations on an instantiation on table will more
157  // or less correspond to a ++ operation on an instantiation on result
158  MultiDimArray< GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE >* result =
159  new MultiDimArray< GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE >;
160  result->beginMultipleChanges();
161 
162  for (const auto var : result_varSeq)
163  *result << *var;
164 
165  result->endMultipleChanges();
166 
167 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
168  // fill the matrix with any element
169  {
170  const GUM_SCALAR& any_element = *(table->unsafeGet(0));
171 
172  for (Idx i = 0; i < result_domain_size; ++i) {
173  result->unsafeSet(i, new GUM_SCALAR(any_element));
174  }
175  }
176 # endif /* GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER */
177 
178  // compute the result: it is now sufficient to loop over the variables that
179  // were not instantiated. ptable and presult are pointers on the arrays
180  // that are directly used for this loop
181  GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE* ptable =
182  const_cast< GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE* >(
183  &(table->unsafeGet(table_alone_offset)));
184  GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE* presult =
185  const_cast< GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE* >(
186  &(result->unsafeGet(0)));
187 
188  // but before doing so, check whether the instantiated variables are the
189  // last ones or not. If so, we can optimize the parsing of ptable and
190  // presult as both tables need be parsed using only 1-increments
191  if (has_before_incr) {
192  for (Idx i = 0; i < result_domain_size; ++i) {
193 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
194  **presult = **ptable;
195 # else
196  *presult = *ptable;
197 # endif
198 
199  // update the offset of result and table
200  ++ptable;
201  ++presult;
202  }
203  } else {
204  // here, some uninstantiated variables exist after the instantiated ones
205  // in the variables sequence of table. So, we must perform a more
206  // complicated parsing of ptable
207  Idx table_offset = 0;
208 
209  for (Idx j = 0; j < result_domain_size; ++j) {
210 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
211  **presult = *(ptable[table_offset]);
212 # else
213  *presult = ptable[table_offset];
214 # endif
215 
216  // update the offset of table
217  for (unsigned int k = 0; k < table_and_result_value.size(); ++k) {
218  --table_and_result_value[k];
219 
220  if (table_and_result_value[k]) {
221  table_offset += table_and_result_offset[k];
222  break;
223  }
224 
225  table_and_result_value[k] = table_and_result_domain[k];
226  table_offset -= table_and_result_down[k];
227  }
228 
229  // update the offset of result
230  ++presult;
231  }
232  }
233 
234  return result;
235  }
236 
237 # undef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE
238 
239 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
240 # undef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
241 # endif
242 
243 } /* End of namespace gum */
244 
245 #endif /* GUM_PARTIAL_INSTANTIATION_PATTERN_ALLOWED */
Header file of gum::Sequence, a class for storing (ordered) sequences of objects. ...
#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_NAME
a specialized partial instantiation function for multiDimArrays
#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_NAME
gum is the global namespace for all aGrUM entities
Definition: agrum.h:25
#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_IMPL2ARRAY_NAME
#define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_IMPL2ARRAY_NAME