aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
scheduleCombinationBasic_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by 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 = tables[i]->variablesSequence();
150 
151  for (Idx j = i + 1; j < tables.size(); ++j) {
152  pair.second = j;
154  }
155  }
156 
157  // now parse the priority queue: the top element (i,j) gives the combination
158  // to perform. When the result R has been computed, substitute i by R,
159  // remove
160  // table j and recompute all the priorities of all the pairs (R,k) still
161  // available.
162  // Timer timer;
163  for (Idx k = 1; k < tables.size(); ++k) {
164  // get the combination to perform and do it
165  pair = queue.pop();
166  Idx ti = pair.first;
167  Idx tj = pair.second;
168 
169  // create the combination that will be performed later on and put it into
170  // the schedule
173 
174  // substitute tables[pair.first] by the result and delete the temporary
175  // multidim tables
176 
177  if (tables[ti] && is_t_new[ti]) {
182  }
183 
184  if (tables[tj] && is_t_new[tj]) {
189  }
190 
191  tables[ti] = &(static_cast< const ScheduleCombine< GUM_SCALAR >& >
192 
194  .result());
195  is_t_new[ti] = true;
196  tables[tj] = 0;
197 
198  // remove all the pairs involving tj in the priority queue
199 
200  for (Idx ind = 0; ind < tj; ++ind) {
201  if (tables[ind]) {
202  pair.first = ind;
203  queue.erase(pair);
204  }
205  }
206 
207  pair.first = tj;
208 
209  for (Idx ind = tj + 1; ind < tables.size(); ++ind) {
210  if (tables[ind]) {
211  pair.second = ind;
212  queue.erase(pair);
213  }
214  }
215 
216  // update the "combinated" size of all the pairs involving "result"
217  {
218  const Sequence< const DiscreteVariable* >& seq1 = 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;
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;
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 >
255  const Set< const MultiDimImplementation< GUM_SCALAR >* >& set,
258  }
259 
260  // adds operations to an already created schedule
261  template < typename GUM_SCALAR >
262  template < template < typename > class TABLE >
267  }
268 
269  /// returns the result of the combination
270  template < typename GUM_SCALAR >
272  const Set< const ScheduleMultiDim< GUM_SCALAR >* >& set,
273  const Schedule< GUM_SCALAR >& schedule) {
274  // check if the set passed in argument is empty.
275  if (set.size() < 2) return 0.0f;
276 
277  float result = 0.0f;
278 
279  // create a vector with all the tables to combine
280  std::vector< const Sequence< const DiscreteVariable* >* > tables(set.size());
281 
282  {
283  Idx i = 0;
284 
285  for (const auto sched: set) {
286  tables[i] = &(sched->variablesSequence());
287  i += 1;
288  }
289  }
290 
291  // create a vector indicating wether the elements in tables are freshly
292  // created Sequence<const DiscreteVariable *>* due to the combination of
293  // some
294  // ScheduleMultiDims or if they were added by the user into the combination
295  // container
296  std::vector< bool > is_t_new(tables.size(), false);
297 
298  // for each pair of tables (i,j), compute the size of the table that would
299  // result from the addition of tables i and j and store the result into a
300  // priorityQueue
301  std::pair< Idx, Idx > pair;
303 
304  for (Idx i = 0; i < tables.size(); ++i) {
305  pair.first = i;
306 
307  for (Idx j = i + 1; j < tables.size(); ++j) {
308  pair.second = j;
310  }
311  }
312 
313  // now parse the priority queue: the top element (i,j) gives the combination
314  // to perform. When the result R has been computed, substitute i by R,
315  // remove
316  // table j and recompute all the priorities of all the pairs (R,k) still
317  // available.
318  for (Idx k = 1; k < tables.size(); ++k) {
319  // get the combination to perform and do it
320  pair = queue.pop();
321  Idx ti = pair.first;
322  Idx tj = pair.second;
323 
324  // compute the result
325  Sequence< const DiscreteVariable* >* new_seq = new Sequence< const DiscreteVariable* >;
326  const Sequence< const DiscreteVariable* >& seq1 = *(tables[ti]);
327  const Sequence< const DiscreteVariable* >& seq2 = *(tables[tj]);
328 
329  Size new_size = 1;
330 
331  for (const auto var: seq1) {
332  new_size *= var->domainSize();
333  new_seq->insert(var);
334  }
335 
336  for (const auto var: seq2)
337  if (!seq1.exists(var)) {
338  new_size *= var->domainSize();
339  new_seq->insert(var);
340  }
341 
342  result += new_size;
343 
344  // substitute tables[pair.first] by the result
345 
346  if (tables[ti] && is_t_new[ti]) delete tables[ti];
347 
348  if (tables[tj] && is_t_new[tj]) delete tables[tj];
349 
350  tables[ti] = new_seq;
351 
352  is_t_new[ti] = true;
353 
354  tables[tj] = 0;
355 
356  // remove all the pairs involving tj in the priority queue
357  for (Idx ind = 0; ind < tj; ++ind) {
358  if (tables[ind]) {
359  pair.first = ind;
360  queue.erase(pair);
361  }
362  }
363 
364  pair.first = tj;
365 
366  for (Idx ind = tj + 1; ind < tables.size(); ++ind) {
367  if (tables[ind]) {
368  pair.second = ind;
369  queue.erase(pair);
370  }
371  }
372 
373  // update the "combined" size of all the pairs involving "new_seq"
374  {
375  pair.second = ti;
376  Size newsize;
377 
378  for (Idx ind = 0; ind < ti; ++ind) {
379  if (tables[ind]) {
380  pair.first = ind;
383  }
384  }
385 
386  pair.first = ti;
387 
388  for (Idx ind = ti + 1; ind < tables.size(); ++ind) {
389  if (tables[ind]) {
390  pair.second = ind;
393  }
394  }
395  }
396  }
397 
398  // here, there remains only one nonzero pointer in tables:
399  // the result of our combination
400  Idx k = 0;
401 
402  while (!tables[k])
403  ++k;
404 
405  delete tables[k];
406 
407  return result;
408  }
409 
410  /// returns the result of the combination
411  template < typename GUM_SCALAR >
413  const Set< const MultiDimImplementation< GUM_SCALAR >* >& set,
414  const Schedule< GUM_SCALAR >& schedule) {
416  }
417 
418  /// returns the result of the combination
419  template < typename GUM_SCALAR >
420  template < template < typename > class TABLE >
422  const Set< const TABLE< GUM_SCALAR >* >& set,
423  const Schedule< GUM_SCALAR >& schedule) {
425  }
426 
427  /// returns the result of the combination
428  template < typename GUM_SCALAR >
430  const Set< const ScheduleMultiDim< GUM_SCALAR >* >& set,
431  const Schedule< GUM_SCALAR >& schedule) {
432  // check if the set passed in argument is empty.
433  if (set.size() < 2) return std::pair< long, long >(0, 0);
434 
435  long max_memory = 0;
436  long current_memory = 0;
437 
438  // create a vector with all the tables to combine
439  std::vector< const Sequence< const DiscreteVariable* >* > tables(set.size());
440  std::vector< Size > table_size(set.size());
441 
442  {
443  Idx i = 0;
444 
445  for (const auto tab: set) {
446  tables[i] = &(tab->variablesSequence());
447  Size size = 0;
448 
449  for (const auto var: tab->variablesSequence())
450  size *= var->domainSize();
451 
452  table_size[i] = size;
453  i += 1;
454  }
455  }
456 
457  // create a vector indicating wether the elements in tables are freshly
458  // created Sequence<const DiscreteVariable *>* due to the combination of
459  // some
460  // ScheduleMultiDims or if they were added by the user into the combination
461  // container
462  std::vector< bool > is_t_new(tables.size(), false);
463 
464  // for each pair of tables (i,j), compute the size of the table that would
465  // result from the addition of tables i and j and store the result into a
466  // priorityQueue
467  std::pair< Idx, Idx > pair;
468 
470 
471  for (Idx i = 0; i < tables.size(); ++i) {
472  pair.first = i;
473 
474  for (Idx j = i + 1; j < tables.size(); ++j) {
475  pair.second = j;
477  }
478  }
479 
480  // now parse the priority queue: the top element (i,j) gives the combination
481  // to perform. When the result R has been computed, substitute i by R,
482  // remove
483  // table j and recompute all the priorities of all the pairs (R,k) still
484  // available.
485  for (Idx k = 1; k < tables.size(); ++k) {
486  // get the combination to perform and do it
487  pair = queue.pop();
488  Idx ti = pair.first;
489  Idx tj = pair.second;
490 
491  // compute the result
492  Sequence< const DiscreteVariable* >* new_seq = new Sequence< const DiscreteVariable* >;
493  const Sequence< const DiscreteVariable* >& seq1 = *(tables[ti]);
494  const Sequence< const DiscreteVariable* >& seq2 = *(tables[tj]);
495 
496  long new_size = 1;
497 
498  for (const auto var: seq1) {
499  if (std::numeric_limits< long >::max() / (long)var->domainSize() < new_size)
500  GUM_ERROR(OutOfBounds, "memory usage out of long int range")
501 
502  new_size *= long(var->domainSize());
503  new_seq->insert(var);
504  }
505 
506  for (const auto var: seq2) {
507  if (!seq1.exists(var)) {
508  if (std::numeric_limits< long >::max() / (long)var->domainSize() < new_size)
509  GUM_ERROR(OutOfBounds, "memory usage out of long int range")
510 
511  new_size *= long(var->domainSize());
512  new_seq->insert(var);
513  }
514  }
515 
516  if (std::numeric_limits< long >::max() - current_memory < new_size) {
517  GUM_ERROR(OutOfBounds, "memory usage out of long int range")
518  }
519 
521 
523 
524  // substitute tables[pair.first] by the result
525  if (tables[ti] && is_t_new[ti]) {
526  delete tables[ti];
527  current_memory -= long(table_size[ti]);
528  }
529 
530  if (tables[tj] && is_t_new[tj]) {
531  delete tables[tj];
532  current_memory -= long(table_size[tj]);
533  }
534 
535  tables[ti] = new_seq;
536 
538  is_t_new[ti] = true;
539  tables[tj] = 0;
540 
541  // remove all the pairs involving tj in the priority queue
542 
543  for (Idx ind = 0; ind < tj; ++ind) {
544  if (tables[ind]) {
545  pair.first = ind;
546  queue.erase(pair);
547  }
548  }
549 
550  pair.first = tj;
551 
552  for (Idx ind = tj + 1; ind < tables.size(); ++ind) {
553  if (tables[ind]) {
554  pair.second = ind;
555  queue.erase(pair);
556  }
557  }
558 
559  // update the "combined" size of all the pairs involving "new_seq"
560  {
561  pair.second = ti;
562  Size newsize;
563 
564  for (Idx ind = 0; ind < ti; ++ind) {
565  if (tables[ind]) {
566  pair.first = ind;
569  }
570  }
571 
572  pair.first = ti;
573 
574  for (Idx ind = ti + 1; ind < tables.size(); ++ind) {
575  if (tables[ind]) {
576  pair.second = ind;
579  }
580  }
581  }
582  }
583 
584  // here, there remains only one nonzero pointer in tables:
585  // the result of our combination
586  Idx k = 0;
587 
588  while (!tables[k])
589  ++k;
590 
591  delete tables[k];
592 
593  return std::pair< long, long >(max_memory, current_memory);
594  }
595 
596  /// returns the memory consumption used during the combination
597  template < typename GUM_SCALAR >
599  const Set< const MultiDimImplementation< GUM_SCALAR >* >& set,
600  const Schedule< GUM_SCALAR >& schedule) {
602  }
603 
604  /// returns the memory consumption used during the combination
605  template < typename GUM_SCALAR >
606  template < template < typename > class TABLE >
608  const Set< const TABLE< GUM_SCALAR >* >& set,
609  const Schedule< GUM_SCALAR >& schedule) {
611  }
612 
613 } /* namespace gum */
614 
615 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643