aGrUM  0.16.0
scheduleCombinationBasic_tpl.h
Go to the documentation of this file.
1 
29 #ifndef DOXYGEN_SHOULD_SKIP_THIS
30 
31 # include <agrum/agrum.h>
32 # include <limits>
33 
35 
36 namespace gum {
37 
39  template < typename GUM_SCALAR >
41  MultiDimImplementation< GUM_SCALAR >* (*combine)(
42  const MultiDimImplementation< GUM_SCALAR >&,
43  const MultiDimImplementation< GUM_SCALAR >&)) :
44  ScheduleCombination< GUM_SCALAR >(),
45  _combine(combine) {
47  GUM_CONSTRUCTOR(ScheduleCombinationBasic);
48  }
49 
51  template < typename GUM_SCALAR >
53  const ScheduleCombinationBasic< GUM_SCALAR >& from) :
54  ScheduleCombination< GUM_SCALAR >(from),
55  _combine(from._combine) {
57  GUM_CONS_CPY(ScheduleCombinationBasic);
58  }
59 
61  template < typename GUM_SCALAR >
64  GUM_DESTRUCTOR(ScheduleCombinationBasic);
65  }
66 
68  template < typename GUM_SCALAR >
69  ScheduleCombinationBasic< GUM_SCALAR >*
71  return new ScheduleCombinationBasic< GUM_SCALAR >(*this);
72  }
73 
75  template < typename GUM_SCALAR >
77  MultiDimImplementation< GUM_SCALAR >* (*combine)(
78  const MultiDimImplementation< GUM_SCALAR >&,
79  const MultiDimImplementation< GUM_SCALAR >&)) {
80  _combine = combine;
81  }
82 
84  template < typename GUM_SCALAR >
85  MultiDimImplementation< GUM_SCALAR >* (
87  const MultiDimImplementation< GUM_SCALAR >&,
88  const MultiDimImplementation< GUM_SCALAR >&) {
89  return _combine;
90  }
91 
94  template < typename GUM_SCALAR >
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 var : seq1)
103  size *= var->domainSize();
104 
105  for (const auto var : seq2)
106  if (!seq1.exists(var)) size *= var->domainSize();
107 
108  return size;
109  }
110 
111  // adds operations to an already created schedule
112  template < typename GUM_SCALAR >
113  ScheduleMultiDim< GUM_SCALAR > ScheduleCombinationBasic< GUM_SCALAR >::combine(
114  const Set< const ScheduleMultiDim< GUM_SCALAR >* >& set,
115  Schedule< GUM_SCALAR >& schedule) {
116  // check if the set passed in argument is empty. If so, raise an exception
117  if (set.size() < 2) {
118  GUM_ERROR(InvalidArgumentsNumber,
119  "the set passed to a ScheduleCombinationBasic"
120  " should at least contain two elements");
121  }
122 
123  // create a vector with all the tables to combine
124  std::vector< const ScheduleMultiDim< GUM_SCALAR >* > tables(set.size());
125 
126  {
127  Idx i = 0;
128 
129  for (const auto sched : set) {
130  tables[i] = sched;
131  i += 1;
132  }
133  }
134 
135  // create a vector indicating wether the elements in tables are freshly
136  // created ScheduleMultiDim<GUM_SCALAR>* due to the combination of some
137  // ScheduleMultiDims or if they were added by the user into the
138  // combination container
139  std::vector< bool > is_t_new(tables.size(), false);
140 
141  // for each pair of tables (i,j), compute the size of the table that would
142  // result from the addition of tables i and j and store the result into a
143  // priorityQueue
144  std::pair< Idx, Idx > pair;
145 
146  PriorityQueue< std::pair< Idx, Idx >, Size > queue;
147 
148  for (Idx i = 0; i < tables.size(); ++i) {
149  pair.first = i;
150  const Sequence< const DiscreteVariable* >& seq1 =
151  tables[i]->variablesSequence();
152 
153  for (Idx j = i + 1; j < tables.size(); ++j) {
154  pair.second = j;
155  queue.insert(pair, _combinedSize(seq1, tables[j]->variablesSequence()));
156  }
157  }
158 
159  // now parse the priority queue: the top element (i,j) gives the combination
160  // to perform. When the result R has been computed, substitute i by R,
161  // remove
162  // table j and recompute all the priorities of all the pairs (R,k) still
163  // available.
164  // Timer timer;
165  for (Idx k = 1; k < tables.size(); ++k) {
166  // get the combination to perform and do it
167  pair = queue.pop();
168  Idx ti = pair.first;
169  Idx tj = pair.second;
170 
171  // create the combination that will be performed later on and put it into
172  // the schedule
173  ScheduleCombine< GUM_SCALAR > comb(*(tables[ti]), *(tables[tj]), _combine);
174  NodeId comb_id = schedule.insert(comb);
175 
176  // substitute tables[pair.first] by the result and delete the temporary
177  // multidim tables
178 
179  if (tables[ti] && is_t_new[ti]) {
180  ScheduleDeleteMultiDim< GUM_SCALAR > del(*(tables[ti]));
181  NodeId del_id = schedule.insert(del);
182  const NodeSet& set_i = schedule.operationsInvolving(*(tables[ti]));
183  schedule.forceAfter(del_id, set_i);
184  }
185 
186  if (tables[tj] && is_t_new[tj]) {
187  ScheduleDeleteMultiDim< GUM_SCALAR > del(*(tables[tj]));
188  NodeId del_id = schedule.insert(del);
189  const NodeSet& set_j = schedule.operationsInvolving(*(tables[tj]));
190  schedule.forceAfter(del_id, set_j);
191  }
192 
193  tables[ti] = &(static_cast< const ScheduleCombine< GUM_SCALAR >& >
194 
195  (schedule.operation(comb_id))
196  .result());
197  is_t_new[ti] = true;
198  tables[tj] = 0;
199 
200  // remove all the pairs involving tj in the priority queue
201 
202  for (Idx ind = 0; ind < tj; ++ind) {
203  if (tables[ind]) {
204  pair.first = ind;
205  queue.erase(pair);
206  }
207  }
208 
209  pair.first = tj;
210 
211  for (Idx ind = tj + 1; ind < tables.size(); ++ind) {
212  if (tables[ind]) {
213  pair.second = ind;
214  queue.erase(pair);
215  }
216  }
217 
218  // update the "combinated" size of all the pairs involving "result"
219  {
220  const Sequence< const DiscreteVariable* >& seq1 =
221  tables[ti]->variablesSequence();
222  pair.second = ti;
223  Size newsize;
224 
225  for (Idx ind = 0; ind < ti; ++ind) {
226  if (tables[ind]) {
227  pair.first = ind;
228  newsize = _combinedSize(seq1, tables[ind]->variablesSequence());
229  queue.setPriority(pair, newsize);
230  }
231  }
232 
233  pair.first = ti;
234 
235  for (Idx ind = ti + 1; ind < tables.size(); ++ind) {
236  if (tables[ind]) {
237  pair.second = ind;
238  newsize = _combinedSize(seq1, tables[ind]->variablesSequence());
239  queue.setPriority(pair, newsize);
240  }
241  }
242  }
243  }
244 
245  // here, there remains only one nonzero pointer in tables:
246  // the result of our combination
247  Idx k = 0;
248 
249  while (!tables[k])
250  ++k;
251 
252  return *(tables[k]);
253  }
254 
255  // adds operations to an already created schedule
256  template < typename GUM_SCALAR >
257  INLINE ScheduleMultiDim< GUM_SCALAR >
259  const Set< const MultiDimImplementation< GUM_SCALAR >* >& set,
260  Schedule< GUM_SCALAR >& schedule) {
261  return ScheduleCombination< GUM_SCALAR >::combine(set, schedule);
262  }
263 
264  // adds operations to an already created schedule
265  template < typename GUM_SCALAR >
266  template < template < typename > class TABLE >
267  INLINE ScheduleMultiDim< GUM_SCALAR >
269  const Set< const TABLE< GUM_SCALAR >* >& set,
270  Schedule< GUM_SCALAR >& schedule) {
271  return ScheduleCombination< GUM_SCALAR >::combine(set, schedule);
272  }
273 
275  template < typename GUM_SCALAR >
277  const Set< const ScheduleMultiDim< GUM_SCALAR >* >& set,
278  const Schedule< GUM_SCALAR >& schedule) {
279  // check if the set passed in argument is empty.
280  if (set.size() < 2) return 0.0f;
281 
282  float result = 0.0f;
283 
284  // create a vector with all the tables to combine
285  std::vector< const Sequence< const DiscreteVariable* >* > tables(set.size());
286 
287  {
288  Idx i = 0;
289 
290  for (const auto sched : set) {
291  tables[i] = &(sched->variablesSequence());
292  i += 1;
293  }
294  }
295 
296  // create a vector indicating wether the elements in tables are freshly
297  // created Sequence<const DiscreteVariable *>* due to the combination of
298  // some
299  // ScheduleMultiDims or if they were added by the user into the combination
300  // container
301  std::vector< bool > is_t_new(tables.size(), false);
302 
303  // for each pair of tables (i,j), compute the size of the table that would
304  // result from the addition of tables i and j and store the result into a
305  // priorityQueue
306  std::pair< Idx, Idx > pair;
307  PriorityQueue< std::pair< Idx, Idx >, Size > queue;
308 
309  for (Idx i = 0; i < tables.size(); ++i) {
310  pair.first = i;
311 
312  for (Idx j = i + 1; j < tables.size(); ++j) {
313  pair.second = j;
314  queue.insert(pair, _combinedSize(*(tables[i]), *(tables[j])));
315  }
316  }
317 
318  // now parse the priority queue: the top element (i,j) gives the combination
319  // to perform. When the result R has been computed, substitute i by R,
320  // remove
321  // table j and recompute all the priorities of all the pairs (R,k) still
322  // available.
323  for (Idx k = 1; k < tables.size(); ++k) {
324  // get the combination to perform and do it
325  pair = queue.pop();
326  Idx ti = pair.first;
327  Idx tj = pair.second;
328 
329  // compute the result
330  Sequence< const DiscreteVariable* >* new_seq =
331  new Sequence< const DiscreteVariable* >;
332  const Sequence< const DiscreteVariable* >& seq1 = *(tables[ti]);
333  const Sequence< const DiscreteVariable* >& seq2 = *(tables[tj]);
334 
335  Size new_size = 1;
336 
337  for (const auto var : seq1) {
338  new_size *= var->domainSize();
339  new_seq->insert(var);
340  }
341 
342  for (const auto var : seq2)
343  if (!seq1.exists(var)) {
344  new_size *= var->domainSize();
345  new_seq->insert(var);
346  }
347 
348  result += new_size;
349 
350  // substitute tables[pair.first] by the result
351 
352  if (tables[ti] && is_t_new[ti]) delete tables[ti];
353 
354  if (tables[tj] && is_t_new[tj]) delete tables[tj];
355 
356  tables[ti] = new_seq;
357 
358  is_t_new[ti] = true;
359 
360  tables[tj] = 0;
361 
362  // remove all the pairs involving tj in the priority queue
363  for (Idx ind = 0; ind < tj; ++ind) {
364  if (tables[ind]) {
365  pair.first = ind;
366  queue.erase(pair);
367  }
368  }
369 
370  pair.first = tj;
371 
372  for (Idx ind = tj + 1; ind < tables.size(); ++ind) {
373  if (tables[ind]) {
374  pair.second = ind;
375  queue.erase(pair);
376  }
377  }
378 
379  // update the "combined" size of all the pairs involving "new_seq"
380  {
381  pair.second = ti;
382  Size newsize;
383 
384  for (Idx ind = 0; ind < ti; ++ind) {
385  if (tables[ind]) {
386  pair.first = ind;
387  newsize = _combinedSize(*new_seq, *(tables[ind]));
388  queue.setPriority(pair, newsize);
389  }
390  }
391 
392  pair.first = ti;
393 
394  for (Idx ind = ti + 1; ind < tables.size(); ++ind) {
395  if (tables[ind]) {
396  pair.second = ind;
397  newsize = _combinedSize(*new_seq, *(tables[ind]));
398  queue.setPriority(pair, newsize);
399  }
400  }
401  }
402  }
403 
404  // here, there remains only one nonzero pointer in tables:
405  // the result of our combination
406  Idx k = 0;
407 
408  while (!tables[k])
409  ++k;
410 
411  delete tables[k];
412 
413  return result;
414  }
415 
417  template < typename GUM_SCALAR >
419  const Set< const MultiDimImplementation< GUM_SCALAR >* >& set,
420  const Schedule< GUM_SCALAR >& schedule) {
422  }
423 
425  template < typename GUM_SCALAR >
426  template < template < typename > class TABLE >
428  const Set< const TABLE< GUM_SCALAR >* >& set,
429  const Schedule< GUM_SCALAR >& schedule) {
431  }
432 
434  template < typename GUM_SCALAR >
436  const Set< const ScheduleMultiDim< GUM_SCALAR >* >& set,
437  const Schedule< GUM_SCALAR >& schedule) {
438  // check if the set passed in argument is empty.
439  if (set.size() < 2) return std::pair< long, long >(0, 0);
440 
441  long max_memory = 0;
442  long current_memory = 0;
443 
444  // create a vector with all the tables to combine
445  std::vector< const Sequence< const DiscreteVariable* >* > tables(set.size());
446  std::vector< Size > table_size(set.size());
447 
448  {
449  Idx i = 0;
450 
451  for (const auto tab : set) {
452  tables[i] = &(tab->variablesSequence());
453  Size size = 0;
454 
455  for (const auto var : tab->variablesSequence())
456  size *= var->domainSize();
457 
458  table_size[i] = size;
459  i += 1;
460  }
461  }
462 
463  // create a vector indicating wether the elements in tables are freshly
464  // created Sequence<const DiscreteVariable *>* due to the combination of
465  // some
466  // ScheduleMultiDims or if they were added by the user into the combination
467  // 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< Idx, Idx > pair;
474 
475  PriorityQueue< std::pair< Idx, Idx >, Size > queue;
476 
477  for (Idx i = 0; i < tables.size(); ++i) {
478  pair.first = i;
479 
480  for (Idx 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 (Idx k = 1; k < tables.size(); ++k) {
492  // get the combination to perform and do it
493  pair = queue.pop();
494  Idx ti = pair.first;
495  Idx 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  long new_size = 1;
504 
505  for (const auto var : seq1) {
506  if (std::numeric_limits< long >::max() / (long)var->domainSize()
507  < new_size)
508  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
509 
510  new_size *= long(var->domainSize());
511  new_seq->insert(var);
512  }
513 
514  for (const auto var : seq2) {
515  if (!seq1.exists(var)) {
516  if (std::numeric_limits< long >::max() / (long)var->domainSize()
517  < new_size)
518  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
519 
520  new_size *= long(var->domainSize());
521  new_seq->insert(var);
522  }
523  }
524 
525  if (std::numeric_limits< long >::max() - current_memory < new_size) {
526  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
527  }
528 
529  current_memory += new_size;
530 
531  if (current_memory > max_memory) { max_memory = current_memory; }
532 
533  // substitute tables[pair.first] by the result
534  if (tables[ti] && is_t_new[ti]) {
535  delete tables[ti];
536  current_memory -= long(table_size[ti]);
537  }
538 
539  if (tables[tj] && is_t_new[tj]) {
540  delete tables[tj];
541  current_memory -= long(table_size[tj]);
542  }
543 
544  tables[ti] = new_seq;
545 
546  table_size[ti] = new_size;
547  is_t_new[ti] = true;
548  tables[tj] = 0;
549 
550  // remove all the pairs involving tj in the priority queue
551 
552  for (Idx ind = 0; ind < tj; ++ind) {
553  if (tables[ind]) {
554  pair.first = ind;
555  queue.erase(pair);
556  }
557  }
558 
559  pair.first = tj;
560 
561  for (Idx ind = tj + 1; ind < tables.size(); ++ind) {
562  if (tables[ind]) {
563  pair.second = ind;
564  queue.erase(pair);
565  }
566  }
567 
568  // update the "combined" size of all the pairs involving "new_seq"
569  {
570  pair.second = ti;
571  Size newsize;
572 
573  for (Idx ind = 0; ind < ti; ++ind) {
574  if (tables[ind]) {
575  pair.first = ind;
576  newsize = _combinedSize(*new_seq, *(tables[ind]));
577  queue.setPriority(pair, newsize);
578  }
579  }
580 
581  pair.first = ti;
582 
583  for (Idx ind = ti + 1; ind < tables.size(); ++ind) {
584  if (tables[ind]) {
585  pair.second = ind;
586  newsize = _combinedSize(*new_seq, *(tables[ind]));
587  queue.setPriority(pair, newsize);
588  }
589  }
590  }
591  }
592 
593  // here, there remains only one nonzero pointer in tables:
594  // the result of our combination
595  Idx k = 0;
596 
597  while (!tables[k])
598  ++k;
599 
600  delete tables[k];
601 
602  return std::pair< long, long >(max_memory, current_memory);
603  }
604 
606  template < typename GUM_SCALAR >
607  INLINE std::pair< long, long >
609  const Set< const MultiDimImplementation< GUM_SCALAR >* >& set,
610  const Schedule< GUM_SCALAR >& schedule) {
612  }
613 
615  template < typename GUM_SCALAR >
616  template < template < typename > class TABLE >
617  INLINE std::pair< long, long >
619  const Set< const TABLE< GUM_SCALAR >* >& set,
620  const Schedule< GUM_SCALAR >& schedule) {
622  }
623 
624 } /* namespace gum */
625 
626 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
virtual float nbOperations(const Set< const ScheduleMultiDim< GUM_SCALAR > * > &set, const Schedule< GUM_SCALAR > &schedule)=0
returns a rough estimate of the number of operations that will be performed to compute the combinatio...
ScheduleCombination()
default constructor
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
virtual ~ScheduleCombinationBasic()
destructor
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
virtual float nbOperations(const Set< const ScheduleMultiDim< GUM_SCALAR > * > &set, const Schedule< GUM_SCALAR > &schedule)
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 ScheduleCombinationBasic< GUM_SCALAR > * newFactory() const
virtual constructor
virtual std::pair< long, long > memoryUsage(const Set< const ScheduleMultiDim< GUM_SCALAR > * > &set, const Schedule< GUM_SCALAR > &schedule)=0
returns the memory consumption used during the combination
virtual ScheduleMultiDim< GUM_SCALAR > combine(const Set< const ScheduleMultiDim< GUM_SCALAR > * > &set, Schedule< GUM_SCALAR > &schedule)=0
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
virtual MultiDimImplementation< GUM_SCALAR > *(*)(const MultiDimImplementation< GUM_SCALAR > &, const MultiDimImplementation< GUM_SCALAR > &) combineFunction()
returns the combination function currently used by the combinator
virtual std::pair< long, long > memoryUsage(const Set< const ScheduleMultiDim< GUM_SCALAR > * > &set, const Schedule< GUM_SCALAR > &schedule)
returns the memory consumption used during the combination
ScheduleCombinationBasic(MultiDimImplementation< GUM_SCALAR > *(*combine)(const MultiDimImplementation< GUM_SCALAR > &, const MultiDimImplementation< GUM_SCALAR > &))
default constructor
MultiDimImplementation< GUM_SCALAR > *(* _combine)(const MultiDimImplementation< GUM_SCALAR > &t1, const MultiDimImplementation< GUM_SCALAR > &t2)
the function used to combine two tables
virtual ScheduleMultiDim< GUM_SCALAR > combine(const Set< const ScheduleMultiDim< GUM_SCALAR > * > &set, Schedule< GUM_SCALAR > &)
virtual void setCombineFunction(MultiDimImplementation< GUM_SCALAR > *(*combine)(const MultiDimImplementation< GUM_SCALAR > &, const MultiDimImplementation< GUM_SCALAR > &))
changes the function used for combining two TABLES
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
Size NodeId
Type for node ids.
Definition: graphElements.h:98
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55