aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
partialInstantiationPattern4BaseName.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  * @brief the pattern used by all the partial instantiations of multidimensional
25  * tables
26  *
27  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
28  */
29 
30 #include <agrum/tools/multidim/instantiation.h>
31 
32 // check if we allowed these patterns to be used
33 #ifndef GUM_PARTIAL_INSTANTIATION_PATTERN_ALLOWED
34 
35 // #warning To use partialIntantiationPattern, you must define
36 // GUM_PARTIAL_INSTANTIATION_PATTERN_ALLOWED
37 
38 #else
39 namespace gum {
40 
41  // a specialized function instantiating some variables of a table and returning
42  // the result
43 
44 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_NAME
45 # define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE GUM_SCALAR
46  template < typename GUM_SCALAR >
47  MultiDimImplementation< GUM_SCALAR >* GUM_MULTI_DIM_PARTIAL_INSTANTIATION_NAME(
48  const MultiDimImplementation< GUM_SCALAR >* table,
49  const HashTable< const DiscreteVariable*, Idx >& inst_vars)
50 # endif
51 
52  // clang-format off
53 
54 #ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_NAME
55 #define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE GUM_SCALAR *
56 #define GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
57  template <typename GUM_SCALAR>
58  MultiDimImplementation<GUM_SCALAR*>*
59  GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER_NAME(
60  const MultiDimImplementation<GUM_SCALAR*>* table,
61  const HashTable<const DiscreteVariable*, Idx>& inst_vars )
62 #endif
63 
64  // clang-format on
65 
66  {
67 
68  // get the variables of the uninstantiated table
69  const Sequence< const DiscreteVariable* >& table_vars
70  = table->variablesSequence();
71 
72  // Compute the offset of the variables. In addition, get the offset in
73  // table induced by the instantiation inst_var
74  Idx table_alone_offset = 0;
75  Idx offset = 1;
76  HashTable< const DiscreteVariable*, Idx > var1offset(table_vars.size());
77 
78  for (const auto var: table_vars) {
79  if (inst_vars.exists(var)) { table_alone_offset += inst_vars[var] * offset; }
80 
81  var1offset.insert(var, offset);
82  offset *= var->domainSize();
83  }
84 
85  // Compute the sequence of variables in the result table. Compute as
86  // well the offsets and the domain size of the variables that belong to
87  // result. Finally, compute has_before_incr: this is a Boolean indicating
88  // whether the instantiated variables are the last variables in the
89  // variables sequence of table (true) or not (false). If this Boolean is
90  // true, then we can fill result by parsing both table and result using
91  // only 1-increments.
92  Sequence< const DiscreteVariable* > result_varSeq;
93  std::vector< Idx > table_and_result_offset;
94  std::vector< Idx > table_and_result_domain;
95  Idx result_domain_size = 1;
96  bool has_before_incr = true;
97  bool found_inst_var = false;
98 
99  for (const auto var: table_vars) {
100  if (!inst_vars.exists(var)) {
101  table_and_result_domain.push_back(var->domainSize());
102  table_and_result_offset.push_back(var1offset[var]);
103  result_domain_size *= var->domainSize();
104  result_varSeq << var;
105 
106  if (found_inst_var) has_before_incr = false;
107  } else {
108  found_inst_var = true;
109  }
110  }
111 
112  // table_and_result_value is a vector indictating, for each
113  // uninstantiated variable, how many increments we can still perform on
114  // that variable before we must perform a "major" increment: for
115  // instance, let A and B be two variables of size 10. Then, if
116  // table_and_result_value[A] = 3 and table_and_result_value[B] = 2, this
117  // means that the offset they represent is 78 (10^2 - 32). If we still
118  // increment B twice, then the offset should be 80, which means that we
119  // shall increment A once and decrease B by 10. The value by which
120  // variables shall be decreased is indicated in table_and_result_down
121  std::vector< Idx > table_and_result_value = table_and_result_domain;
122  std::vector< Idx > table_and_result_down = table_and_result_offset;
123 
124  for (unsigned int i = 0; i < table_and_result_down.size(); ++i)
125  table_and_result_down[i] *= (table_and_result_domain[i] - 1);
126 
127  // create a table "result" containing only the variables that are not
128  // instantiated: the variables are stored in the order in which they
129  // appear in "table". Hence, ++ operations on an instantiation on table
130  // will more or less correspond to a ++ operation on an instantiation on
131  // result
132  MultiDimArray< GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE >* result
133  = new MultiDimArray< GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE >;
134  result->beginMultipleChanges();
135 
136  for (const auto var: result_varSeq)
137  *result << *var;
138 
139  result->endMultipleChanges();
140 
141 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
142  // fill the matrix with any element
143  {
144  const Instantiation table_inst(table);
145  const GUM_SCALAR& any_element = *(table->get(table_inst));
146 
147  for (Idx i = 0; i < result_domain_size; ++i) {
148  result->unsafeSet(i, new GUM_SCALAR(any_element));
149  }
150  }
151 # endif /* GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER */
152 
153  // compute the result: it is now sufficient to loop over the variables
154  // that were not instantiated. ptable and presult are pointers on the
155  // arrays that are directly used for this loop
156  GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE* presult
157  = const_cast< GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE* >(
158  &(result->unsafeGet(0)));
159  Instantiation table_inst(table);
160  table_inst += table_alone_offset;
161 
162  // but before doing so, check whether the instantiated variables are the
163  // last ones or not. If so, we can optimize the parsing of ptable and
164  // presult as both tables need be parsed using only 1-increments
165  if (has_before_incr) {
166  for (Idx i = 0; i < result_domain_size; ++i) {
167 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
168  **presult = *(table->get(table_inst));
169 # else
170  *presult = table->get(table_inst);
171 # endif
172 
173  // update the offset of result and table
174  ++table_inst;
175  ++presult;
176  }
177  } else {
178  // here, some uninstantiated variables exist after the instantiated
179  // ones in the variables sequence of table. So, we must perform a more
180  // complicated parsing of ptable
181  for (Idx j = 0; j < result_domain_size; ++j) {
182 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
183  **presult = *(table->get(table_inst));
184 # else
185  *presult = table->get(table_inst);
186 # endif
187 
188  // update the offset of table for the outer loop
189  for (unsigned int k = 0; k < table_and_result_value.size(); ++k) {
190  --table_and_result_value[k];
191 
192  if (table_and_result_value[k]) {
193  table_inst += table_and_result_offset[k];
194  break;
195  }
196 
197  table_and_result_value[k] = table_and_result_domain[k];
198  table_inst -= table_and_result_down[k];
199  }
200 
201  // update the offset of result for the outer loop
202  ++presult;
203  }
204  }
205 
206  return result;
207  }
208 
209 # undef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_TYPE
210 
211 # ifdef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
212 # undef GUM_MULTI_DIM_PARTIAL_INSTANTIATION_POINTER
213 # endif
214 
215 } /* End of namespace gum */
216 
217 #endif /* GUM_PARTIAL_INSTANTIATION_PATTERN_ALLOWED */