aGrUM  0.17.2
a C++ library for (probabilistic) graphical models
multiDimCombinationDefault_tpl.h
Go to the documentation of this file.
1 
30 #ifndef DOXYGEN_SHOULD_SKIP_THIS
31 
32 # include <limits>
33 
34 # include <agrum/agrum.h>
35 
38 
39 namespace gum {
40 
41  // constructor
42  template < typename GUM_SCALAR, template < typename > class TABLE >
44  TABLE< GUM_SCALAR >* (*combine)(const TABLE< GUM_SCALAR >&,
45  const TABLE< GUM_SCALAR >&)) :
46  MultiDimCombination< GUM_SCALAR, TABLE >(),
47  _combine(combine) {
48  // for debugging purposes
49  GUM_CONSTRUCTOR(MultiDimCombinationDefault);
50  }
51 
52  // copy constructor
53  template < typename GUM_SCALAR, template < typename > class TABLE >
55  const MultiDimCombinationDefault< GUM_SCALAR, TABLE >& from) :
56  MultiDimCombination< GUM_SCALAR, TABLE >(),
57  _combine(from._combine) {
58  // for debugging purposes
59  GUM_CONS_CPY(MultiDimCombinationDefault);
60  }
61 
62  // destructor
63  template < typename GUM_SCALAR, template < typename > class TABLE >
65  // for debugging purposes
66  GUM_DESTRUCTOR(MultiDimCombinationDefault);
67  }
68 
69  // virtual constructor
70  template < typename GUM_SCALAR, template < typename > class TABLE >
71  MultiDimCombinationDefault< GUM_SCALAR, TABLE >*
73  return new MultiDimCombinationDefault< GUM_SCALAR, TABLE >(_combine);
74  }
75 
76  // changes the function used for combining two TABLES
77  template < typename GUM_SCALAR, template < typename > class TABLE >
79  TABLE< GUM_SCALAR >* (*combine)(const TABLE< GUM_SCALAR >&,
80  const TABLE< GUM_SCALAR >&)) {
81  _combine = combine;
82  }
83 
84  // returns the combination function currently used by the combinator
85  template < typename GUM_SCALAR, template < typename > class TABLE >
86  INLINE TABLE< GUM_SCALAR >* (
88  const TABLE< GUM_SCALAR >&, const TABLE< GUM_SCALAR >&) {
89  return _combine;
90  }
91 
92  // returns the domain size of the Cartesian product of the union of all the
93  // variables in seq1 and seq2
94  template < typename GUM_SCALAR, template < typename > class TABLE >
96  const Sequence< const DiscreteVariable* >& seq1,
97  const Sequence< const DiscreteVariable* >& seq2) const {
98  if (seq1.empty() && seq2.empty()) return 0;
99 
100  Size size = 1;
101 
102  for (const auto ptrVar : seq1)
103  size *= ptrVar->domainSize();
104 
105  for (const auto ptrVar : seq2)
106  if (!seq1.exists(ptrVar)) size *= ptrVar->domainSize();
107 
108  return size;
109  }
110 
111  // returns the result of the combination
112  template < typename GUM_SCALAR, template < typename > class TABLE >
114  TABLE< GUM_SCALAR >& container,
115  const Set< const TABLE< GUM_SCALAR >* >& set) {
116  TABLE< GUM_SCALAR >* res = combine(set);
117  container = std::move(*res);
118  delete (res);
119  }
120 
121  // returns the result of the combination
122  template < typename GUM_SCALAR, template < typename > class TABLE >
124  const Set< const TABLE< GUM_SCALAR >* >& set) {
125  // check if the set passed in argument is empty. If so, raise an exception
126  if (set.size() < 2) {
127  GUM_ERROR(InvalidArgumentsNumber,
128  "the set passed to a MultiDimCombinationDefault"
129  " should at least contain two elements");
130  }
131 
132  // create a vector with all the tables to combine
133  std::vector< const TABLE< GUM_SCALAR >* > tables(set.size());
134  const Size tabsize = tables.size();
135 
136  {
137  Size i = Size(0);
138  for (auto iter = set.cbegin(); iter != set.cend(); ++iter, ++i) {
139  tables[i] = *iter;
140  }
141  }
142 
143  // create a vector indicating wether the elements in tables are freshly
144  // created TABLE<GUM_SCALAR>* due to the combination of some TABLEs or if
145  // they were added by the user into the combination container
146  std::vector< bool > is_t_new(tabsize, false);
147 
148  // for each pair of tables (i,j), compute the size of the table that would
149  // result from the addition of tables i and j and store the result into a
150  // priorityQueue
151  std::pair< Size, Size > pair;
152  PriorityQueue< std::pair< Size, Size >, Size > queue;
153 
154  for (Size i = Size(0); i < tabsize; ++i) {
155  pair.first = i;
156  const Sequence< const DiscreteVariable* >& seq1 =
157  tables[i]->variablesSequence();
158 
159  for (Size j = i + 1; j < tabsize; ++j) {
160  pair.second = j;
161  queue.insert(pair, _combinedSize(seq1, tables[j]->variablesSequence()));
162  }
163  }
164 
165  // now parse the priority queue: the top element (i,j) gives the combination
166  // to perform. When the result R has been computed, substitute i by R,
167  // remove table j and recompute all the priorities of all the pairs (R,k)
168  // still available.
169  for (Size k = 1; k < tabsize; ++k) {
170  // get the combination to perform and do it
171  pair = queue.pop();
172  const Size ti = pair.first;
173  const Size tj = pair.second;
174 
175  TABLE< GUM_SCALAR >* result = _combine(*(tables[ti]), *(tables[tj]));
176 
177  // substitute tables[pair.first] by the result
178  if (tables[ti] && is_t_new[ti]) delete tables[ti];
179  if (tables[tj] && is_t_new[tj]) delete tables[tj];
180 
181  tables[ti] = result;
182  is_t_new[ti] = true;
183 
184  tables[tj] = nullptr;
185 
186  // remove all the pairs involving tj in the priority queue
187  for (Size ind = 0; ind < tj; ++ind) {
188  if (tables[ind] != nullptr) {
189  pair.first = ind;
190  queue.erase(pair);
191  }
192  }
193 
194  pair.first = tj;
195  for (Size ind = tj + 1; ind < tabsize; ++ind) {
196  if (tables[ind] != nullptr) {
197  pair.second = ind;
198  queue.erase(pair);
199  }
200  }
201 
202  // update the "combinated" size of all the pairs involving "result"
203  {
204  const Sequence< const DiscreteVariable* >& seq1 =
205  tables[ti]->variablesSequence();
206  pair.second = ti;
207  Size newsize;
208 
209  for (Size ind = 0; ind < ti; ++ind) {
210  if (tables[ind] != nullptr) {
211  pair.first = ind;
212  newsize = _combinedSize(seq1, tables[ind]->variablesSequence());
213  queue.setPriority(pair, newsize);
214  }
215  }
216 
217  pair.first = ti;
218 
219  for (Size ind = ti + 1; ind < tabsize; ++ind) {
220  if (tables[ind] != nullptr) {
221  pair.second = ind;
222  newsize = _combinedSize(seq1, tables[ind]->variablesSequence());
223  queue.setPriority(pair, newsize);
224  }
225  }
226  }
227  }
228 
229  // here, there remains only one nonzero pointer in tables:
230  // the result of our combination
231  Size k = 0;
232  while (tables[k] == nullptr)
233  ++k;
234 
235  return const_cast< TABLE< GUM_SCALAR >* >(tables[k]);
236  }
237 
238  // returns the result of the combination
239  template < typename GUM_SCALAR, template < typename > class TABLE >
241  const Set< const Sequence< const DiscreteVariable* >* >& set) const {
242  // check if the set passed in argument is empty.
243  if (set.size() < 2) return 0.0f;
244 
245  float result = 0.0f;
246 
247  // create a vector with all the tables to combine
248  std::vector< const Sequence< const DiscreteVariable* >* > tables(set.size());
249  const Size tabsize = tables.size();
250 
251  {
252  Size i = Size(0);
253  for (auto iter = set.cbegin(); iter != set.cend(); ++iter, ++i) {
254  tables[i] = *iter;
255  }
256  }
257 
258  // create a vector indicating wether the elements in tables are freshly
259  // created Sequence<const DiscreteVariable *>* due to the combination of
260  // some TABLEs or if they were added by the user into the combination
261  // container
262  std::vector< bool > is_t_new(tabsize, false);
263 
264  // for each pair of tables (i,j), compute the size of the table that would
265  // result from the addition of tables i and j and store the result into a
266  // priorityQueue
267  std::pair< Size, Size > pair;
268  PriorityQueue< std::pair< Size, Size >, Size > queue;
269 
270  for (Size i = Size(0); i < tabsize; ++i) {
271  pair.first = i;
272 
273  for (Size j = i + 1; j < tabsize; ++j) {
274  pair.second = j;
275  queue.insert(pair, _combinedSize(*(tables[i]), *(tables[j])));
276  }
277  }
278 
279  // now parse the priority queue: the top element (i,j) gives the combination
280  // to perform. When the result R has been computed, substitute i by R,
281  // remove table j and recompute all the priorities of all the pairs (R,k)
282  // still available.
283  for (Size k = 1; k < tabsize; ++k) {
284  // get the combination to perform and do it
285  pair = queue.pop();
286  const Size ti = pair.first;
287  const Size tj = pair.second;
288 
289  // compute the result
290  Sequence< const DiscreteVariable* >* new_seq =
291  new Sequence< const DiscreteVariable* >;
292  const Sequence< const DiscreteVariable* >& seq1 = *(tables[ti]);
293  const Sequence< const DiscreteVariable* >& seq2 = *(tables[tj]);
294 
295  Size new_size = 1;
296 
297  for (const auto ptrVar : seq1) {
298  new_size *= ptrVar->domainSize();
299  new_seq->insert(ptrVar);
300  }
301 
302  for (const auto ptrVar : seq2) {
303  if (!seq1.exists(ptrVar)) {
304  new_size *= ptrVar->domainSize();
305  new_seq->insert(ptrVar);
306  }
307  }
308 
309  result += new_size;
310 
311  // substitute tables[pair.first] by the result
312  if (tables[ti] && is_t_new[ti]) delete tables[ti];
313  if (tables[tj] && is_t_new[tj]) delete tables[tj];
314 
315  tables[ti] = new_seq;
316  is_t_new[ti] = true;
317 
318  tables[tj] = nullptr;
319 
320  // remove all the pairs involving tj in the priority queue
321  for (Size ind = 0; ind < tj; ++ind) {
322  if (tables[ind] != nullptr) {
323  pair.first = ind;
324  queue.erase(pair);
325  }
326  }
327 
328  pair.first = tj;
329 
330  for (Size ind = tj + 1; ind < tabsize; ++ind) {
331  if (tables[ind] != nullptr) {
332  pair.second = ind;
333  queue.erase(pair);
334  }
335  }
336 
337  // update the "combined" size of all the pairs involving "new_seq"
338  {
339  pair.second = ti;
340  Size newsize;
341 
342  for (Size ind = 0; ind < ti; ++ind) {
343  if (tables[ind] != nullptr) {
344  pair.first = ind;
345  newsize = _combinedSize(*new_seq, *(tables[ind]));
346  queue.setPriority(pair, newsize);
347  }
348  }
349 
350  pair.first = ti;
351 
352  for (Size ind = ti + 1; ind < tabsize; ++ind) {
353  if (tables[ind] != nullptr) {
354  pair.second = ind;
355  newsize = _combinedSize(*new_seq, *(tables[ind]));
356  queue.setPriority(pair, newsize);
357  }
358  }
359  }
360  }
361 
362  // here, there remains only one nonzero pointer in tables:
363  // the result of our combination
364  Size k = 0;
365  while (tables[k] == nullptr)
366  ++k;
367 
368  delete tables[k];
369 
370  return result;
371  }
372 
373  // returns the result of the combination
374  template < typename GUM_SCALAR, template < typename > class TABLE >
376  const Set< const TABLE< GUM_SCALAR >* >& set) const {
377  // check if the set passed in argument is empty.
378  if (set.size() < 2) return 0.0f;
379 
380  // create the set of sets of discrete variables involved in the tables
381  Set< const Sequence< const DiscreteVariable* >* > var_set(set.size());
382 
383  for (const auto ptrTab : set) {
384  var_set << &(ptrTab->variablesSequence());
385  }
386 
387  return nbOperations(var_set);
388  }
389 
390  // returns the memory consumption used during the combination
391  template < typename GUM_SCALAR, template < typename > class TABLE >
392  std::pair< long, long >
394  const Set< const Sequence< const DiscreteVariable* >* >& set) const {
395  // check if the set passed in argument is empty.
396  if (set.size() < 2) return std::pair< long, long >(0, 0);
397 
398  Size max_memory = 0;
399  Size current_memory = 0;
400 
401  // create a vector with all the tables to combine
402  std::vector< const Sequence< const DiscreteVariable* >* > tables(set.size());
403  const Size tabsize = tables.size();
404 
405  std::vector< Size > table_size(set.size());
406 
407  {
408  Size i = Size(0);
409 
410  for (auto iter = set.cbegin(); iter != set.cend(); ++iter, ++i) {
411  const Sequence< const DiscreteVariable* >* vars = *iter;
412  tables[i] = vars;
413 
414  Size size = Size(1);
415  for (const auto ptrVar : *vars) {
416  size *= ptrVar->domainSize();
417  }
418 
419  table_size[i] = size;
420  }
421  }
422 
423  // create a vector indicating wether the elements in tables are freshly
424  // created Sequence<const DiscreteVariable *>* due to the combination of
425  // some TABLEs or if they were added by the user into the combination
426  // container
427  std::vector< bool > is_t_new(tables.size(), false);
428 
429  // for each pair of tables (i,j), compute the size of the table that would
430  // result from the addition of tables i and j and store the result into a
431  // priorityQueue
432  std::pair< Size, Size > pair;
433 
434  PriorityQueue< std::pair< Size, Size >, Size > queue;
435 
436  for (Size i = Size(0); i < tabsize; ++i) {
437  pair.first = i;
438 
439  for (Size j = i + 1; j < tabsize; ++j) {
440  pair.second = j;
441  queue.insert(pair, _combinedSize(*(tables[i]), *(tables[j])));
442  }
443  }
444 
445  // now parse the priority queue: the top element (i,j) gives the combination
446  // to perform. When the result R has been computed, substitute i by R,
447  // remove table j and recompute all the priorities of all the pairs (R,k)
448  // still available.
449  for (Size k = 1; k < tabsize; ++k) {
450  // get the combination to perform and do it
451  pair = queue.pop();
452  const Size ti = pair.first;
453  const Size tj = pair.second;
454 
455  // compute the result
456  Sequence< const DiscreteVariable* >* new_seq =
457  new Sequence< const DiscreteVariable* >;
458  const Sequence< const DiscreteVariable* >& seq1 = *(tables[ti]);
459  const Sequence< const DiscreteVariable* >& seq2 = *(tables[tj]);
460 
461  Size new_size = Size(1);
462 
463  for (const auto ptrVar : seq1) {
464  if (std::numeric_limits< Size >::max() / ptrVar->domainSize()
465  < new_size) {
466  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
467  }
468 
469  new_size *= ptrVar->domainSize();
470 
471  new_seq->insert(ptrVar);
472  }
473 
474  for (const auto ptrVar : seq2) {
475  if (!seq1.exists(ptrVar)) {
476  if (std::numeric_limits< Size >::max() / ptrVar->domainSize()
477  < new_size) {
478  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
479  }
480 
481  new_size *= ptrVar->domainSize();
482 
483  new_seq->insert(ptrVar);
484  }
485  }
486 
487  if (std::numeric_limits< Size >::max() - current_memory < new_size) {
488  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
489  }
490 
491  current_memory += new_size;
492 
493  if (current_memory > max_memory) { max_memory = current_memory; }
494 
495  // substitute tables[pair.first] by the result
496  if (tables[ti] && is_t_new[ti]) {
497  delete tables[ti];
498  current_memory -= table_size[ti];
499  }
500 
501  if (tables[tj] && is_t_new[tj]) {
502  delete tables[tj];
503  current_memory -= table_size[tj];
504  }
505 
506  tables[ti] = new_seq;
507  table_size[ti] = new_size;
508  is_t_new[ti] = true;
509 
510  tables[tj] = nullptr;
511 
512  // remove all the pairs involving tj in the priority queue
513  for (Size ind = 0; ind < tj; ++ind) {
514  if (tables[ind] != nullptr) {
515  pair.first = ind;
516  queue.erase(pair);
517  }
518  }
519 
520  pair.first = tj;
521 
522  for (Size ind = tj + 1; ind < tabsize; ++ind) {
523  if (tables[ind] != nullptr) {
524  pair.second = ind;
525  queue.erase(pair);
526  }
527  }
528 
529  // update the "combined" size of all the pairs involving "new_seq"
530  {
531  pair.second = ti;
532  Size newsize;
533 
534  for (Size ind = Size(0); ind < ti; ++ind) {
535  if (tables[ind] != nullptr) {
536  pair.first = ind;
537  newsize = _combinedSize(*new_seq, *(tables[ind]));
538  queue.setPriority(pair, newsize);
539  }
540  }
541 
542  pair.first = ti;
543 
544  for (Size ind = ti + 1; ind < tabsize; ++ind) {
545  if (tables[ind] != nullptr) {
546  pair.second = ind;
547  newsize = _combinedSize(*new_seq, *(tables[ind]));
548  queue.setPriority(pair, newsize);
549  }
550  }
551  }
552  }
553 
554  // here, there remains only one nonzero pointer in tables:
555  // the result of our combination
556  Size k = Size(0);
557  while (!tables[k])
558  ++k;
559 
560  delete tables[k];
561 
562  return std::pair< long, long >(long(max_memory), long(current_memory));
563  }
564 
565  // returns the memory consumption used during the combination
566  template < typename GUM_SCALAR, template < typename > class TABLE >
567  std::pair< long, long >
569  const Set< const TABLE< GUM_SCALAR >* >& set) const {
570  // check if the set passed in argument is empty.
571  if (set.size() < 2) return std::pair< long, long >(0, 0);
572 
573  // create the set of sets of discrete variables involved in the tables
574  Set< const Sequence< const DiscreteVariable* >* > var_set(set.size());
575 
576  for (const auto ptrTab : set) {
577  var_set << &(ptrTab->variablesSequence());
578  }
579 
580  return memoryUsage(var_set);
581  }
582 
583 } /* namespace gum */
584 
585 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
virtual std::pair< long, long > memoryUsage(const Set< const TABLE< GUM_SCALAR > * > &set) const
Returns the additional memory consumption used during the combination.
MultiDimCombination()
default constructor
virtual TABLE< GUM_SCALAR > *(*)(const TABLE< GUM_SCALAR > &, const TABLE< GUM_SCALAR > &) combineFunction()
Returns the combination function currently used by the combinator.
virtual void setCombineFunction(TABLE< GUM_SCALAR > *(*combine)(const TABLE< GUM_SCALAR > &, const TABLE< GUM_SCALAR > &))
Changes the function used for combining two TABLES.
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
Definition: agrum.h:25
TABLE< GUM_SCALAR > *(* _combine)(const TABLE< GUM_SCALAR > &t1, const TABLE< GUM_SCALAR > &t2)
The function used to combine two tables.
virtual float nbOperations(const Set< const TABLE< GUM_SCALAR > * > &set) const
returns a rough estimate of the number of operations that will be performed to compute the combinatio...
Size _combinedSize(const Sequence< const DiscreteVariable * > &seq1, const Sequence< const DiscreteVariable * > &seq2) const
returns the domain size of the Cartesian product of the union of all the variables in seq1 and seq2...
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
virtual MultiDimCombinationDefault< GUM_SCALAR, TABLE > * newFactory() const
virtual constructor
Copyright 2005-2020 Pierre-Henri WUILLEMIN () et Christophe GONZALES () info_at_agrum_dot_org.
MultiDimCombinationDefault(TABLE< GUM_SCALAR > *(*combine)(const TABLE< GUM_SCALAR > &, const TABLE< GUM_SCALAR > &))
Default constructor.
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
virtual ~MultiDimCombinationDefault()
Destructor.
virtual TABLE< GUM_SCALAR > * combine(const Set< const TABLE< GUM_SCALAR > * > &set)
Creates and returns the result of the combination of the tables within set.
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55