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