aGrUM  0.16.0
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 
103  seq1.beginSafe();
104  iter != seq1.endSafe();
105  ++iter) {
106  size *= (*iter)->domainSize();
107  }
108 
110  seq2.beginSafe();
111  iter != seq2.endSafe();
112  ++iter) {
113  if (!seq1.exists(*iter)) size *= (*iter)->domainSize();
114  }
115 
116  return size;
117  }
118 
119  // returns the result of the combination
120  template < typename GUM_SCALAR, template < typename > class TABLE >
122  TABLE< GUM_SCALAR >& container,
123  const Set< const TABLE< GUM_SCALAR >* >& set) {
124  TABLE< GUM_SCALAR >* res = combine(set);
125  container = *res;
126  delete (res);
127  }
128 
129  // returns the result of the combination
130  template < typename GUM_SCALAR, template < typename > class TABLE >
132  const Set< const TABLE< GUM_SCALAR >* >& set) {
133  // check if the set passed in argument is empty. If so, raise an exception
134  if (set.size() < 2) {
135  GUM_ERROR(InvalidArgumentsNumber,
136  "the set passed to a MultiDimCombinationDefault"
137  " should at least contain two elements");
138  }
139 
140  // create a vector with all the tables to combine
141  std::vector< const TABLE< GUM_SCALAR >* > tables(set.size());
142 
143  {
144  unsigned int i = 0;
145 
146  for (typename Set< const TABLE< GUM_SCALAR >* >::const_iterator_safe iter =
147  set.beginSafe();
148  iter != set.endSafe();
149  ++iter, ++i) {
150  tables[i] = *iter;
151  }
152  }
153 
154  // create a vector indicating wether the elements in tables are freshly
155  // created TABLE<GUM_SCALAR>* due to the combination of some TABLEs or if
156  // they
157  // were added by the user into the combination container
158  std::vector< bool > is_t_new(tables.size(), false);
159 
160  // for each pair of tables (i,j), compute the size of the table that would
161  // result from the addition of tables i and j and store the result into a
162  // priorityQueue
163  std::pair< unsigned int, unsigned int > pair;
164 
165  PriorityQueue< std::pair< unsigned int, unsigned int >, Size > queue;
166 
167  for (unsigned int i = 0; i < tables.size(); ++i) {
168  pair.first = i;
169  const Sequence< const DiscreteVariable* >& seq1 =
170  tables[i]->variablesSequence();
171 
172  for (unsigned int j = i + 1; j < tables.size(); ++j) {
173  pair.second = j;
174  queue.insert(pair, _combinedSize(seq1, tables[j]->variablesSequence()));
175  }
176  }
177 
178  // now parse the priority queue: the top element (i,j) gives the combination
179  // to perform. When the result R has been computed, substitute i by R,
180  // remove
181  // table j and recompute all the priorities of all the pairs (R,k) still
182  // available.
183  for (unsigned int k = 1; k < tables.size(); ++k) {
184  // get the combination to perform and do it
185  pair = queue.pop();
186  unsigned int ti = pair.first;
187  unsigned int tj = pair.second;
188 
189  TABLE< GUM_SCALAR >* result = _combine(*(tables[ti]), *(tables[tj]));
190 
191  // substitute tables[pair.first] by the result
192 
193  if (tables[ti] && is_t_new[ti]) delete tables[ti];
194 
195  if (tables[tj] && is_t_new[tj]) delete tables[tj];
196 
197  tables[ti] = result;
198 
199  is_t_new[ti] = true;
200 
201  tables[tj] = 0;
202 
203  // remove all the pairs involving tj in the priority queue
204  for (unsigned int ind = 0; ind < tj; ++ind) {
205  if (tables[ind]) {
206  pair.first = ind;
207  queue.erase(pair);
208  }
209  }
210 
211  pair.first = tj;
212 
213  for (unsigned int ind = tj + 1; ind < tables.size(); ++ind) {
214  if (tables[ind]) {
215  pair.second = ind;
216  queue.erase(pair);
217  }
218  }
219 
220  // update the "combinated" size of all the pairs involving "result"
221  {
222  const Sequence< const DiscreteVariable* >& seq1 =
223  tables[ti]->variablesSequence();
224  pair.second = ti;
225  Size newsize;
226 
227  for (unsigned int ind = 0; ind < ti; ++ind) {
228  if (tables[ind]) {
229  pair.first = ind;
230  newsize = _combinedSize(seq1, tables[ind]->variablesSequence());
231  queue.setPriority(pair, newsize);
232  }
233  }
234 
235  pair.first = ti;
236 
237  for (unsigned int ind = ti + 1; ind < tables.size(); ++ind) {
238  if (tables[ind]) {
239  pair.second = ind;
240  newsize = _combinedSize(seq1, tables[ind]->variablesSequence());
241  queue.setPriority(pair, newsize);
242  }
243  }
244  }
245  }
246 
247  // here, there remains only one nonzero pointer in tables:
248  // the result of our combination
249  unsigned int k = 0;
250 
251  while (!tables[k])
252  ++k;
253 
254  return const_cast< TABLE< GUM_SCALAR >* >(tables[k]);
255  }
256 
257  // returns the result of the combination
258  template < typename GUM_SCALAR, template < typename > class TABLE >
260  const Set< const Sequence< const DiscreteVariable* >* >& set) const {
261  // check if the set passed in argument is empty.
262  if (set.size() < 2) return 0.0f;
263 
264  float result = 0.0f;
265 
266  // create a vector with all the tables to combine
267  std::vector< const Sequence< const DiscreteVariable* >* > tables(set.size());
268 
269  {
270  unsigned int i = 0;
271 
272  for (typename Set< const Sequence< const DiscreteVariable* >* >::
273  const_iterator_safe iter = set.beginSafe();
274  iter != set.endSafe();
275  ++iter, ++i) {
276  tables[i] = *iter;
277  }
278  }
279 
280  // create a vector indicating wether the elements in tables are freshly
281  // created Sequence<const DiscreteVariable *>* due to the combination of
282  // some
283  // TABLEs or if they were added by the user into the combination container
284  std::vector< bool > is_t_new(tables.size(), false);
285 
286  // for each pair of tables (i,j), compute the size of the table that would
287  // result from the addition of tables i and j and store the result into a
288  // priorityQueue
289  std::pair< unsigned int, unsigned int > pair;
290 
291  PriorityQueue< std::pair< unsigned int, unsigned int >, Size > queue;
292 
293  for (unsigned int i = 0; i < tables.size(); ++i) {
294  pair.first = i;
295 
296  for (unsigned int j = i + 1; j < tables.size(); ++j) {
297  pair.second = j;
298  queue.insert(pair, _combinedSize(*(tables[i]), *(tables[j])));
299  }
300  }
301 
302  // now parse the priority queue: the top element (i,j) gives the combination
303  // to perform. When the result R has been computed, substitute i by R,
304  // remove
305  // table j and recompute all the priorities of all the pairs (R,k) still
306  // available.
307  for (unsigned int k = 1; k < tables.size(); ++k) {
308  // get the combination to perform and do it
309  pair = queue.pop();
310  unsigned int ti = pair.first;
311  unsigned int tj = pair.second;
312 
313  // compute the result
314  Sequence< const DiscreteVariable* >* new_seq =
315  new Sequence< const DiscreteVariable* >;
316  const Sequence< const DiscreteVariable* >& seq1 = *(tables[ti]);
317  const Sequence< const DiscreteVariable* >& seq2 = *(tables[tj]);
318 
319  Size new_size = 1;
320 
322  seq1.beginSafe();
323  iter != seq1.endSafe();
324  ++iter) {
325  new_size *= (*iter)->domainSize();
326  new_seq->insert(*iter);
327  }
328 
330  seq2.beginSafe();
331  iter != seq2.endSafe();
332  ++iter) {
333  if (!seq1.exists(*iter)) {
334  new_size *= (*iter)->domainSize();
335  new_seq->insert(*iter);
336  }
337  }
338 
339  result += new_size;
340 
341  // substitute tables[pair.first] by the result
342 
343  if (tables[ti] && is_t_new[ti]) delete tables[ti];
344 
345  if (tables[tj] && is_t_new[tj]) delete tables[tj];
346 
347  tables[ti] = new_seq;
348 
349  is_t_new[ti] = true;
350 
351  tables[tj] = 0;
352 
353  // remove all the pairs involving tj in the priority queue
354  for (unsigned int ind = 0; ind < tj; ++ind) {
355  if (tables[ind]) {
356  pair.first = ind;
357  queue.erase(pair);
358  }
359  }
360 
361  pair.first = tj;
362 
363  for (unsigned int ind = tj + 1; ind < tables.size(); ++ind) {
364  if (tables[ind]) {
365  pair.second = ind;
366  queue.erase(pair);
367  }
368  }
369 
370  // update the "combined" size of all the pairs involving "new_seq"
371  {
372  pair.second = ti;
373  Size newsize;
374 
375  for (unsigned int ind = 0; ind < ti; ++ind) {
376  if (tables[ind]) {
377  pair.first = ind;
378  newsize = _combinedSize(*new_seq, *(tables[ind]));
379  queue.setPriority(pair, newsize);
380  }
381  }
382 
383  pair.first = ti;
384 
385  for (unsigned int ind = ti + 1; ind < tables.size(); ++ind) {
386  if (tables[ind]) {
387  pair.second = ind;
388  newsize = _combinedSize(*new_seq, *(tables[ind]));
389  queue.setPriority(pair, newsize);
390  }
391  }
392  }
393  }
394 
395  // here, there remains only one nonzero pointer in tables:
396  // the result of our combination
397  unsigned int k = 0;
398 
399  while (!tables[k])
400  ++k;
401 
402  delete tables[k];
403 
404  return result;
405  }
406 
407  // returns the result of the combination
408  template < typename GUM_SCALAR, template < typename > class TABLE >
410  const Set< const TABLE< GUM_SCALAR >* >& set) const {
411  // check if the set passed in argument is empty.
412  if (set.size() < 2) return 0.0f;
413 
414  // create the set of sets of discrete variables involved in the tables
415  Set< const Sequence< const DiscreteVariable* >* > var_set(set.size());
416 
417  for (typename Set< const TABLE< GUM_SCALAR >* >::const_iterator_safe iter =
418  set.beginSafe();
419  iter != set.endSafe();
420  ++iter) {
421  var_set << &((*iter)->variablesSequence());
422  }
423 
424  return nbOperations(var_set);
425  }
426 
427  // returns the memory consumption used during the combination
428  template < typename GUM_SCALAR, template < typename > class TABLE >
429  std::pair< long, long >
431  const Set< const Sequence< const DiscreteVariable* >* >& set) const {
432  // check if the set passed in argument is empty.
433  if (set.size() < 2) return std::pair< long, long >(0, 0);
434 
435  Size max_memory = 0;
436 
437  Size current_memory = 0;
438 
439  // create a vector with all the tables to combine
440  std::vector< const Sequence< const DiscreteVariable* >* > tables(set.size());
441 
442  std::vector< Size > table_size(set.size());
443 
444  {
445  std::size_t i = std::size_t(0);
446 
447  for (typename Set< const Sequence< const DiscreteVariable* >* >::
448  const_iterator_safe iter = set.beginSafe();
449  iter != set.endSafe();
450  ++iter, ++i) {
451  const Sequence< const DiscreteVariable* >* vars = *iter;
452  tables[i] = vars;
453 
454  Size size = 0;
455 
457  iter2 = vars->beginSafe();
458  iter2 != vars->endSafe();
459  ++iter2) {
460  size *= (*iter2)->domainSize();
461  }
462 
463  table_size[i] = size;
464  }
465  }
466 
467  // create a vector indicating wether the elements in tables are freshly
468  // created Sequence<const DiscreteVariable *>* due to the combination of
469  // some
470  // TABLEs or if they were added by the user into the combination container
471  std::vector< bool > is_t_new(tables.size(), false);
472 
473  // for each pair of tables (i,j), compute the size of the table that would
474  // result from the addition of tables i and j and store the result into a
475  // priorityQueue
476  std::pair< unsigned int, unsigned int > pair;
477 
478  PriorityQueue< std::pair< unsigned int, unsigned int >, Size > queue;
479 
480  for (unsigned int i = 0; i < tables.size(); ++i) {
481  pair.first = i;
482 
483  for (unsigned int j = i + 1; j < tables.size(); ++j) {
484  pair.second = j;
485  queue.insert(pair, _combinedSize(*(tables[i]), *(tables[j])));
486  }
487  }
488 
489  // now parse the priority queue: the top element (i,j) gives the combination
490  // to perform. When the result R has been computed, substitute i by R,
491  // remove
492  // table j and recompute all the priorities of all the pairs (R,k) still
493  // available.
494  for (unsigned int k = 1; k < tables.size(); ++k) {
495  // get the combination to perform and do it
496  pair = queue.pop();
497  unsigned int ti = pair.first;
498  unsigned int tj = pair.second;
499 
500  // compute the result
501  Sequence< const DiscreteVariable* >* new_seq =
502  new Sequence< const DiscreteVariable* >;
503  const Sequence< const DiscreteVariable* >& seq1 = *(tables[ti]);
504  const Sequence< const DiscreteVariable* >& seq2 = *(tables[tj]);
505 
506  Size new_size = 1;
507 
509  seq1.beginSafe();
510  iter != seq1.endSafe();
511  ++iter) {
512  if (std::numeric_limits< Size >::max() / (*iter)->domainSize()
513  < new_size) {
514  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
515  }
516 
517  new_size *= (*iter)->domainSize();
518 
519  new_seq->insert(*iter);
520  }
521 
523  seq2.beginSafe();
524  iter != seq2.endSafe();
525  ++iter) {
526  if (!seq1.exists(*iter)) {
527  if (std::numeric_limits< Size >::max() / (*iter)->domainSize()
528  < new_size) {
529  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
530  }
531 
532  new_size *= (*iter)->domainSize();
533 
534  new_seq->insert(*iter);
535  }
536  }
537 
538  if (std::numeric_limits< Size >::max() - current_memory < new_size) {
539  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
540  }
541 
542  current_memory += new_size;
543 
544  if (current_memory > max_memory) { max_memory = current_memory; }
545 
546  // substitute tables[pair.first] by the result
547  if (tables[ti] && is_t_new[ti]) {
548  delete tables[ti];
549  current_memory -= table_size[ti];
550  }
551 
552  if (tables[tj] && is_t_new[tj]) {
553  delete tables[tj];
554  current_memory -= table_size[tj];
555  }
556 
557  tables[ti] = new_seq;
558 
559  table_size[ti] = new_size;
560  is_t_new[ti] = true;
561  tables[tj] = 0;
562 
563  // remove all the pairs involving tj in the priority queue
564 
565  for (unsigned int ind = 0; ind < tj; ++ind) {
566  if (tables[ind]) {
567  pair.first = ind;
568  queue.erase(pair);
569  }
570  }
571 
572  pair.first = tj;
573 
574  for (unsigned int ind = tj + 1; ind < tables.size(); ++ind) {
575  if (tables[ind]) {
576  pair.second = ind;
577  queue.erase(pair);
578  }
579  }
580 
581  // update the "combined" size of all the pairs involving "new_seq"
582  {
583  pair.second = ti;
584  Size newsize;
585 
586  for (unsigned int ind = 0; ind < ti; ++ind) {
587  if (tables[ind]) {
588  pair.first = ind;
589  newsize = _combinedSize(*new_seq, *(tables[ind]));
590  queue.setPriority(pair, newsize);
591  }
592  }
593 
594  pair.first = ti;
595 
596  for (unsigned int ind = ti + 1; ind < tables.size(); ++ind) {
597  if (tables[ind]) {
598  pair.second = ind;
599  newsize = _combinedSize(*new_seq, *(tables[ind]));
600  queue.setPriority(pair, newsize);
601  }
602  }
603  }
604  }
605 
606  // here, there remains only one nonzero pointer in tables:
607  // the result of our combination
608  unsigned int k = 0;
609 
610  while (!tables[k])
611  ++k;
612 
613  delete tables[k];
614 
615  return std::pair< long, long >(long(max_memory), long(current_memory));
616  }
617 
618  // returns the memory consumption used during the combination
619  template < typename GUM_SCALAR, template < typename > class TABLE >
620  std::pair< long, long >
622  const Set< const TABLE< GUM_SCALAR >* >& set) const {
623  // check if the set passed in argument is empty.
624  if (set.size() < 2) return std::pair< long, long >(0, 0);
625 
626  // create the set of sets of discrete variables involved in the tables
627  Set< const Sequence< const DiscreteVariable* >* > var_set(set.size());
628 
629  for (typename Set< const TABLE< GUM_SCALAR >* >::const_iterator_safe iter =
630  set.beginSafe();
631  iter != set.endSafe();
632  ++iter) {
633  var_set << &((*iter)->variablesSequence());
634  }
635 
636  return memoryUsage(var_set);
637  }
638 
639 } /* namespace gum */
640 
641 #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-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
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-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
virtual MultiDimCombinationDefault< GUM_SCALAR, TABLE > * newFactory() const
virtual constructor
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
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
SequenceIteratorSafe< Key > const_iterator_safe
Types for STL compliance.
Definition: sequence.h:1038