aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
scheduleCombinationBasic_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /** @file
23  * @brief A class to combine efficiently several ScheduleMultiDims
24  *
25  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26  */
27 
28 #ifndef DOXYGEN_SHOULD_SKIP_THIS
29 
30 # include <agrum/agrum.h>
31 # include <limits>
32 
33 # include <agrum/tools/graphicalModels/inference/scheduler/scheduleCombinationBasic.h>
34 
35 namespace gum {
36 
37  /// constructor
38  template < typename GUM_SCALAR >
39  ScheduleCombinationBasic< GUM_SCALAR >::ScheduleCombinationBasic(
44  combine_(combine) {
45  /// for debugging purposes
47  }
48 
49  /// copy constructor
50  template < typename GUM_SCALAR >
55  /// for debugging purposes
57  }
58 
59  /// destructor
60  template < typename GUM_SCALAR >
62  /// for debugging purposes
64  }
65 
66  /// virtual constructor
67  template < typename GUM_SCALAR >
70  return new ScheduleCombinationBasic< GUM_SCALAR >(*this);
71  }
72 
73  /// changes the function used for combining two MultiDimImplementations
74  template < typename GUM_SCALAR >
79  combine_ = combine;
80  }
81 
82  /// returns the combination function currently used by the combinator
83  template < typename GUM_SCALAR >
88  return combine_;
89  }
90 
91  /// returns the domain size of the Cartesian product of the union of all the
92  /// variables in seq1 and seq2
93  template < typename GUM_SCALAR >
95  const Sequence< const DiscreteVariable* >& seq1,
96  const Sequence< const DiscreteVariable* >& seq2) const {
97  if (seq1.empty() && seq2.empty()) return 0;
98 
99  Size size = 1;
100 
101  for (const auto var: seq1)
102  size *= var->domainSize();
103 
104  for (const auto var: seq2)
105  if (!seq1.exists(var)) size *= var->domainSize();
106 
107  return size;
108  }
109 
110  // adds operations to an already created schedule
111  template < typename GUM_SCALAR >
113  const Set< const ScheduleMultiDim< GUM_SCALAR >* >& set,
115  // check if the set passed in argument is empty. If so, raise an exception
116  if (set.size() < 2) {
118  "the set passed to a ScheduleCombinationBasic"
119  " should at least contain two elements");
120  }
121 
122  // create a vector with all the tables to combine
124 
125  {
126  Idx i = 0;
127 
128  for (const auto sched: set) {
129  tables[i] = sched;
130  i += 1;
131  }
132  }
133 
134  // create a vector indicating wether the elements in tables are freshly
135  // created ScheduleMultiDim<GUM_SCALAR>* due to the combination of some
136  // ScheduleMultiDims or if they were added by the user into the
137  // combination container
138  std::vector< bool > is_t_new(tables.size(), false);
139 
140  // for each pair of tables (i,j), compute the size of the table that would
141  // result from the addition of tables i and j and store the result into a
142  // priorityQueue
143  std::pair< Idx, Idx > pair;
144 
146 
147  for (Idx i = 0; i < tables.size(); ++i) {
148  pair.first = i;
149  const Sequence< const DiscreteVariable* >& seq1
150  = tables[i]->variablesSequence();
151 
152  for (Idx j = i + 1; j < tables.size(); ++j) {
153  pair.second = j;
155  }
156  }
157 
158  // now parse the priority queue: the top element (i,j) gives the combination
159  // to perform. When the result R has been computed, substitute i by R,
160  // remove
161  // table j and recompute all the priorities of all the pairs (R,k) still
162  // available.
163  // Timer timer;
164  for (Idx k = 1; k < tables.size(); ++k) {
165  // get the combination to perform and do it
166  pair = queue.pop();
167  Idx ti = pair.first;
168  Idx tj = pair.second;
169 
170  // create the combination that will be performed later on and put it into
171  // the schedule
174 
175  // substitute tables[pair.first] by the result and delete the temporary
176  // multidim tables
177 
178  if (tables[ti] && is_t_new[ti]) {
183  }
184 
185  if (tables[tj] && is_t_new[tj]) {
190  }
191 
192  tables[ti] = &(static_cast< const ScheduleCombine< GUM_SCALAR >& >
193 
195  .result());
196  is_t_new[ti] = true;
197  tables[tj] = 0;
198 
199  // remove all the pairs involving tj in the priority queue
200 
201  for (Idx 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 (Idx 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
221  pair.second = ti;
222  Size newsize;
223 
224  for (Idx ind = 0; ind < ti; ++ind) {
225  if (tables[ind]) {
226  pair.first = ind;
229  }
230  }
231 
232  pair.first = ti;
233 
234  for (Idx ind = ti + 1; ind < tables.size(); ++ind) {
235  if (tables[ind]) {
236  pair.second = ind;
239  }
240  }
241  }
242  }
243 
244  // here, there remains only one nonzero pointer in tables:
245  // the result of our combination
246  Idx k = 0;
247 
248  while (!tables[k])
249  ++k;
250 
251  return *(tables[k]);
252  }
253 
254  // adds operations to an already created schedule
255  template < typename GUM_SCALAR >
258  const Set< const MultiDimImplementation< GUM_SCALAR >* >& set,
261  }
262 
263  // adds operations to an already created schedule
264  template < typename GUM_SCALAR >
265  template < template < typename > class TABLE >
268  const Set< const TABLE< GUM_SCALAR >* >& set,
271  }
272 
273  /// returns the result of the combination
274  template < typename GUM_SCALAR >
276  const Set< const ScheduleMultiDim< GUM_SCALAR >* >& set,
277  const Schedule< GUM_SCALAR >& schedule) {
278  // check if the set passed in argument is empty.
279  if (set.size() < 2) return 0.0f;
280 
281  float result = 0.0f;
282 
283  // create a vector with all the tables to combine
284  std::vector< const Sequence< const DiscreteVariable* >* > tables(set.size());
285 
286  {
287  Idx i = 0;
288 
289  for (const auto sched: set) {
290  tables[i] = &(sched->variablesSequence());
291  i += 1;
292  }
293  }
294 
295  // create a vector indicating wether the elements in tables are freshly
296  // created Sequence<const DiscreteVariable *>* due to the combination of
297  // some
298  // ScheduleMultiDims or if they were added by the user into the combination
299  // container
300  std::vector< bool > is_t_new(tables.size(), false);
301 
302  // for each pair of tables (i,j), compute the size of the table that would
303  // result from the addition of tables i and j and store the result into a
304  // priorityQueue
305  std::pair< Idx, Idx > pair;
307 
308  for (Idx i = 0; i < tables.size(); ++i) {
309  pair.first = i;
310 
311  for (Idx j = i + 1; j < tables.size(); ++j) {
312  pair.second = j;
314  }
315  }
316 
317  // now parse the priority queue: the top element (i,j) gives the combination
318  // to perform. When the result R has been computed, substitute i by R,
319  // remove
320  // table j and recompute all the priorities of all the pairs (R,k) still
321  // available.
322  for (Idx k = 1; k < tables.size(); ++k) {
323  // get the combination to perform and do it
324  pair = queue.pop();
325  Idx ti = pair.first;
326  Idx tj = pair.second;
327 
328  // compute the result
330  = new Sequence< const DiscreteVariable* >;
331  const Sequence< const DiscreteVariable* >& seq1 = *(tables[ti]);
332  const Sequence< const DiscreteVariable* >& seq2 = *(tables[tj]);
333 
334  Size new_size = 1;
335 
336  for (const auto var: seq1) {
337  new_size *= var->domainSize();
338  new_seq->insert(var);
339  }
340 
341  for (const auto var: seq2)
342  if (!seq1.exists(var)) {
343  new_size *= var->domainSize();
344  new_seq->insert(var);
345  }
346 
347  result += new_size;
348 
349  // substitute tables[pair.first] by the result
350 
351  if (tables[ti] && is_t_new[ti]) delete tables[ti];
352 
353  if (tables[tj] && is_t_new[tj]) delete tables[tj];
354 
355  tables[ti] = new_seq;
356 
357  is_t_new[ti] = true;
358 
359  tables[tj] = 0;
360 
361  // remove all the pairs involving tj in the priority queue
362  for (Idx ind = 0; ind < tj; ++ind) {
363  if (tables[ind]) {
364  pair.first = ind;
365  queue.erase(pair);
366  }
367  }
368 
369  pair.first = tj;
370 
371  for (Idx ind = tj + 1; ind < tables.size(); ++ind) {
372  if (tables[ind]) {
373  pair.second = ind;
374  queue.erase(pair);
375  }
376  }
377 
378  // update the "combined" size of all the pairs involving "new_seq"
379  {
380  pair.second = ti;
381  Size newsize;
382 
383  for (Idx ind = 0; ind < ti; ++ind) {
384  if (tables[ind]) {
385  pair.first = ind;
388  }
389  }
390 
391  pair.first = ti;
392 
393  for (Idx ind = ti + 1; ind < tables.size(); ++ind) {
394  if (tables[ind]) {
395  pair.second = ind;
398  }
399  }
400  }
401  }
402 
403  // here, there remains only one nonzero pointer in tables:
404  // the result of our combination
405  Idx k = 0;
406 
407  while (!tables[k])
408  ++k;
409 
410  delete tables[k];
411 
412  return result;
413  }
414 
415  /// returns the result of the combination
416  template < typename GUM_SCALAR >
418  const Set< const MultiDimImplementation< GUM_SCALAR >* >& set,
419  const Schedule< GUM_SCALAR >& schedule) {
421  }
422 
423  /// returns the result of the combination
424  template < typename GUM_SCALAR >
425  template < template < typename > class TABLE >
427  const Set< const TABLE< GUM_SCALAR >* >& set,
428  const Schedule< GUM_SCALAR >& schedule) {
430  }
431 
432  /// returns the result of the combination
433  template < typename GUM_SCALAR >
435  const Set< const ScheduleMultiDim< GUM_SCALAR >* >& set,
436  const Schedule< GUM_SCALAR >& schedule) {
437  // check if the set passed in argument is empty.
438  if (set.size() < 2) return std::pair< long, long >(0, 0);
439 
440  long max_memory = 0;
441  long current_memory = 0;
442 
443  // create a vector with all the tables to combine
444  std::vector< const Sequence< const DiscreteVariable* >* > tables(set.size());
445  std::vector< Size > table_size(set.size());
446 
447  {
448  Idx i = 0;
449 
450  for (const auto tab: set) {
451  tables[i] = &(tab->variablesSequence());
452  Size size = 0;
453 
454  for (const auto var: tab->variablesSequence())
455  size *= var->domainSize();
456 
457  table_size[i] = size;
458  i += 1;
459  }
460  }
461 
462  // create a vector indicating wether the elements in tables are freshly
463  // created Sequence<const DiscreteVariable *>* due to the combination of
464  // some
465  // ScheduleMultiDims or if they were added by the user into the combination
466  // container
467  std::vector< bool > is_t_new(tables.size(), false);
468 
469  // for each pair of tables (i,j), compute the size of the table that would
470  // result from the addition of tables i and j and store the result into a
471  // priorityQueue
472  std::pair< Idx, Idx > pair;
473 
475 
476  for (Idx i = 0; i < tables.size(); ++i) {
477  pair.first = i;
478 
479  for (Idx j = i + 1; j < tables.size(); ++j) {
480  pair.second = j;
482  }
483  }
484 
485  // now parse the priority queue: the top element (i,j) gives the combination
486  // to perform. When the result R has been computed, substitute i by R,
487  // remove
488  // table j and recompute all the priorities of all the pairs (R,k) still
489  // available.
490  for (Idx k = 1; k < tables.size(); ++k) {
491  // get the combination to perform and do it
492  pair = queue.pop();
493  Idx ti = pair.first;
494  Idx tj = pair.second;
495 
496  // compute the result
498  = new Sequence< const DiscreteVariable* >;
499  const Sequence< const DiscreteVariable* >& seq1 = *(tables[ti]);
500  const Sequence< const DiscreteVariable* >& seq2 = *(tables[tj]);
501 
502  long new_size = 1;
503 
504  for (const auto var: seq1) {
505  if (std::numeric_limits< long >::max() / (long)var->domainSize()
506  < new_size)
507  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
508 
509  new_size *= long(var->domainSize());
510  new_seq->insert(var);
511  }
512 
513  for (const auto var: seq2) {
514  if (!seq1.exists(var)) {
515  if (std::numeric_limits< long >::max() / (long)var->domainSize()
516  < new_size)
517  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
518 
519  new_size *= long(var->domainSize());
520  new_seq->insert(var);
521  }
522  }
523 
524  if (std::numeric_limits< long >::max() - current_memory < new_size) {
525  GUM_ERROR(OutOfBounds, "memory usage out of long int range");
526  }
527 
529 
531 
532  // substitute tables[pair.first] by the result
533  if (tables[ti] && is_t_new[ti]) {
534  delete tables[ti];
535  current_memory -= long(table_size[ti]);
536  }
537 
538  if (tables[tj] && is_t_new[tj]) {
539  delete tables[tj];
540  current_memory -= long(table_size[tj]);
541  }
542 
543  tables[ti] = new_seq;
544 
546  is_t_new[ti] = true;
547  tables[tj] = 0;
548 
549  // remove all the pairs involving tj in the priority queue
550 
551  for (Idx ind = 0; ind < tj; ++ind) {
552  if (tables[ind]) {
553  pair.first = ind;
554  queue.erase(pair);
555  }
556  }
557 
558  pair.first = tj;
559 
560  for (Idx ind = tj + 1; ind < tables.size(); ++ind) {
561  if (tables[ind]) {
562  pair.second = ind;
563  queue.erase(pair);
564  }
565  }
566 
567  // update the "combined" size of all the pairs involving "new_seq"
568  {
569  pair.second = ti;
570  Size newsize;
571 
572  for (Idx ind = 0; ind < ti; ++ind) {
573  if (tables[ind]) {
574  pair.first = ind;
577  }
578  }
579 
580  pair.first = ti;
581 
582  for (Idx ind = ti + 1; ind < tables.size(); ++ind) {
583  if (tables[ind]) {
584  pair.second = ind;
587  }
588  }
589  }
590  }
591 
592  // here, there remains only one nonzero pointer in tables:
593  // the result of our combination
594  Idx k = 0;
595 
596  while (!tables[k])
597  ++k;
598 
599  delete tables[k];
600 
601  return std::pair< long, long >(max_memory, current_memory);
602  }
603 
604  /// returns the memory consumption used during the combination
605  template < typename GUM_SCALAR >
606  INLINE std::pair< long, long >
608  const Set< const MultiDimImplementation< GUM_SCALAR >* >& set,
609  const Schedule< GUM_SCALAR >& schedule) {
611  }
612 
613  /// returns the memory consumption used during the combination
614  template < typename GUM_SCALAR >
615  template < template < typename > class TABLE >
616  INLINE std::pair< long, long >
618  const Set< const TABLE< GUM_SCALAR >* >& set,
619  const Schedule< GUM_SCALAR >& schedule) {
621  }
622 
623 } /* namespace gum */
624 
625 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669