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