aGrUM  0.14.2
operatorPattern4BaseName.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  ***************************************************************************/
27 // check if we allowed these patterns to be used
28 #ifndef GUM_OPERATOR_PATTERN_ALLOWED
29 
30 // #warning To use operatorPattern4MultiDimBase.h, you must define
31 // GUM_OPERATOR_PATTERN_ALLOWED
32 
33 #else
34 
35 namespace gum {
36 
37  // a specialized function for combining two multiDimImplementations whose
38  // real data type is unknown to us
39 
40 # ifdef GUM_MULTI_DIM_OPERATOR_NAME
41 # define GUM_MULTI_DIM_OPERATOR_TYPE T
42  template < typename T >
43  MultiDimImplementation< T >*
44  GUM_MULTI_DIM_OPERATOR_NAME(const MultiDimImplementation< T >* t1,
45  const MultiDimImplementation< T >* t2)
46 # endif
47 
48  // clang-format off
49 
50 #ifdef GUM_MULTI_DIM_OPERATOR_POINTER_NAME
51 #define GUM_MULTI_DIM_OPERATOR_TYPE T *
52  template <typename T>
53  MultiDimImplementation<T*>* GUM_MULTI_DIM_OPERATOR_POINTER_NAME(
54  const MultiDimImplementation<T*>* t1,
55  const MultiDimImplementation<T*>* t2 )
56 #endif
57 
58 #ifdef GUM_MULTI_DIM_OPERATOR_NAME_F
59 #define GUM_MULTI_DIM_OPERATOR_TYPE T
60  template <typename T>
61  MultiDimImplementation<T>* GUM_MULTI_DIM_OPERATOR_NAME_F(
62  const MultiDimImplementation<T>* t1,
63  const MultiDimImplementation<T>* t2,
64  const T ( *f )( const T&, const T& ) )
65 #endif
66 
67 #ifdef GUM_MULTI_DIM_OPERATOR_POINTER_NAME_F
68 #define GUM_MULTI_DIM_OPERATOR_TYPE T *
69  template <typename T>
70  MultiDimImplementation<T*>* GUM_MULTI_DIM_OPERATOR_POINTER_NAME_F(
71  const MultiDimImplementation<T*>* t1,
72  const MultiDimImplementation<T*>* t2,
73  const T ( *f )( const T*, const T* ) )
74 #endif
75 
76  // clang-format on
77 
78  {
79 
80  // get the variables of the tables
81  const Sequence< const DiscreteVariable* >& t1_vars = t1->variablesSequence();
82  const Sequence< const DiscreteVariable* >& t2_vars = t2->variablesSequence();
83 
84  // get the domain size of the tables' variables
85  HashTable< const DiscreteVariable*, Idx > t1_offsets;
86  {
87  Idx current_offset = 1;
88 
89  for (const auto var : t1_vars) {
90  t1_offsets.insert(var, current_offset);
91  current_offset *= var->domainSize();
92  }
93  }
94  HashTable< const DiscreteVariable*, Idx > t2_offsets;
95  {
96  Idx current_offset = 1;
97 
98  for (const auto var : t2_vars) {
99  t2_offsets.insert(var, current_offset);
100  current_offset *= var->domainSize();
101  }
102  }
103 
104  // we divide the variables of t1 and t2 into 3 separate sets: those that
105  // belong only to t1 (variables t1_alone_xxx), those that belong only to t2
106  // (variables t2_alone_xxx) and those that belong to both tables (variables
107  // t1_and_t2_xxx). For each set, we get the variables of the table
108  // (txxx_var) and the domain size of the variable (txxx_domain). In
109  // addition, we compute the domain size of the Cartesian product of the
110  // variables in each of the 3 sets. Given these data, we will be able to
111  // parse both t1, t2 and the result table t1+t2.
112  std::vector< const DiscreteVariable* > t1_alone_var;
113  std::vector< Idx > t1_alone_domain;
114  Idx t1_alone_domain_size = 1;
115 
116  std::vector< const DiscreteVariable* > t2_alone_var;
117  std::vector< Idx > t2_alone_domain;
118  Idx t2_alone_domain_size = 1;
119 
120  std::vector< const DiscreteVariable* > t1_and_t2_var;
121  std::vector< Idx > t1_and_t2_domain;
122  Idx t1_and_t2_domain_size = 1;
123 
124  {
125  for (const auto var : t1_vars)
126  if (t2_vars.exists(var)) {
127  t1_and_t2_domain.push_back(var->domainSize());
128  t1_and_t2_var.push_back(var);
129  t1_and_t2_domain_size *= var->domainSize();
130  } else {
131  t1_alone_domain.push_back(var->domainSize());
132  t1_alone_var.push_back(var);
133  t1_alone_domain_size *= var->domainSize();
134  }
135 
136  for (const auto var : t2_vars)
137  if (!t1_vars.exists(var)) {
138  t2_alone_domain.push_back(var->domainSize());
139  t2_alone_var.push_back(var);
140  t2_alone_domain_size *= var->domainSize();
141  }
142  }
143 
144  // a Boolean indicating whether the variables that t1 and t2 have in common
145  // are the first variables and are in the same order. When this is true,
146  // computations can be performed faster
147  bool t1_and_t2_begin_vars = false;
148 
149  if (t1_and_t2_var.size()) {
150  unsigned int nb_t1_t2_vars = 0;
151 
152  for (const auto var : t1_vars) {
153  if (var != t1_and_t2_var[nb_t1_t2_vars]) break;
154  nb_t1_t2_vars += 1;
155  }
156 
157  if (nb_t1_t2_vars == t1_and_t2_var.size()) {
158  nb_t1_t2_vars = 0;
159 
160  for (auto iter = t2_vars.begin(); nb_t1_t2_vars != t1_and_t2_var.size();
161  ++iter, ++nb_t1_t2_vars)
162  if (*iter != t1_and_t2_var[nb_t1_t2_vars]) break;
163 
164  if (nb_t1_t2_vars == t1_and_t2_var.size()) t1_and_t2_begin_vars = true;
165  }
166  }
167 
168  // when we will parse t1 and t2 to fill the result table t1+t2, we will use
169  // variables txxx_value : at the beginning they are initialized to the
170  // domain size of the variables (which are, themselves initialized to 0).
171  // Each time we increment a variable, its corresponding txxx_value is
172  // decreased by 1. When the latter is equal to 0, this means that the
173  // variable itself should be reinitialized to 0 as well and that the next
174  // variable of the table should be increased (that is, this is similar to
175  // increasing 9 to 10).
176  std::vector< Idx > t1_and_t2_value = t1_and_t2_domain;
177  std::vector< Idx > t1_alone_value = t1_alone_domain;
178  std::vector< Idx > t2_alone_value = t2_alone_domain;
179 
180  // create a table "result" containing all the variables: the first
181  // variables are those that belong to both t1 and t2. The next variables
182  // are those that belong to t2 but not to t1. Finally, the last variables
183  // are those that belong to t1 but not t2. This order will be used in the
184  // next for loops.
185  MultiDimArray< GUM_MULTI_DIM_OPERATOR_TYPE >* result =
186  new MultiDimArray< GUM_MULTI_DIM_OPERATOR_TYPE >;
187  result->beginMultipleChanges();
188 
189  for (const auto var : t1_vars)
190  if (t2_vars.exists(var)) *result << *var;
191 
192  for (const auto var : t2_vars)
193  if (!t1_vars.exists(var)) *result << *var;
194 
195  for (const auto var : t1_vars)
196  if (!t2_vars.exists(var)) *result << *var;
197 
198  result->endMultipleChanges();
199 
200  // here we fill result. The idea is to use 3 loops. The innermost loop
201  // corresponds to the variables that belongs both to t1 and t2. The middle
202  // loop to the variables that belong to t2 but not to t1. Finally, the
203  // outer loop corresponds to the variables that belong to t1 but not t2.
204  Idx result_offset = 0;
205  Instantiation t2_inst(t2);
206  Instantiation t1_inst(t1);
207  Instantiation t1_alone_begin_inst(t1);
208 
209  // test if all the variables in common in t1 and t2 are the first variables
210  // and are in the same order. In this case, we can speed-up the
211  // incrementation processes
212  if (t1_and_t2_begin_vars) {
213  for (Idx i = 0; i < t1_alone_domain_size; ++i) {
214  t2_inst.setFirst();
215  t1_alone_begin_inst = t1_inst;
216 
217  for (Idx j = 0; j < t2_alone_domain_size; ++j) {
218  t1_inst = t1_alone_begin_inst;
219 
220  for (Idx z = 0; z < t1_and_t2_domain_size; ++z) {
221  result->unsafeSet(
222  result_offset,
223  GUM_MULTI_DIM_OPERATOR(t1->get(t1_inst), t2->get(t2_inst)));
224 
225  ++result_offset;
226 
227  // update the offset of both t1 and t2
228  ++t1_inst;
229  ++t2_inst;
230  }
231  }
232  }
233  } else {
234  for (Idx i = 0; i < t1_alone_domain_size; ++i) {
235  t2_inst.setFirst();
236  t1_alone_begin_inst = t1_inst;
237 
238  for (Idx j = 0; j < t2_alone_domain_size; ++j) {
239  t1_inst = t1_alone_begin_inst;
240 
241  for (Idx z = 0; z < t1_and_t2_domain_size; ++z) {
242  result->unsafeSet(
243  result_offset,
244  GUM_MULTI_DIM_OPERATOR(t1->get(t1_inst), t2->get(t2_inst)));
245 
246  ++result_offset;
247 
248  // update the offset of both t1 and t2
249  for (unsigned int k = 0; k < t1_and_t2_value.size(); ++k) {
250  --t1_and_t2_value[k];
251 
252  if (t1_and_t2_value[k]) {
253  t1_inst.incVar(*(t1_and_t2_var[k]));
254  t2_inst.incVar(*(t1_and_t2_var[k]));
255  break;
256  }
257 
258  t1_and_t2_value[k] = t1_and_t2_domain[k];
259  t1_inst.setFirstVar(*(t1_and_t2_var[k]));
260  t2_inst.setFirstVar(*(t1_and_t2_var[k]));
261  }
262  }
263 
264  // update the offset of t2 alone
265  for (unsigned int k = 0; k < t2_alone_value.size(); ++k) {
266  --t2_alone_value[k];
267 
268  if (t2_alone_value[k]) {
269  t2_inst.incVar(*(t2_alone_var[k]));
270  break;
271  }
272 
273  t2_alone_value[k] = t2_alone_domain[k];
274  t2_inst.setFirstVar(*(t2_alone_var[k]));
275  }
276  }
277 
278  // update the offset of t1 alone
279  for (unsigned int k = 0; k < t1_alone_value.size(); ++k) {
280  --t1_alone_value[k];
281 
282  if (t1_alone_value[k]) {
283  t1_inst.incVar(*(t1_alone_var[k]));
284  break;
285  }
286 
287  t1_alone_value[k] = t1_alone_domain[k];
288  t1_inst.setFirstVar(*(t1_alone_var[k]));
289  }
290  }
291  }
292 
293  return result;
294  }
295 
296 # undef GUM_MULTI_DIM_OPERATOR_TYPE
297 } // namespace gum
298 #endif /* GUM_OPERATOR_PATTERN_ALLOWED */
gum is the global namespace for all aGrUM entities
Definition: agrum.h:25