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