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