aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
scheduleMultiDim_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 MultiDimImplementation Wrapper used for scheduling inferences
24  *
25  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26  */
27 
28 #ifndef DOXYGEN_SHOULD_SKIP_THIS
29 
30 # include <sstream>
31 # include <string>
32 
33 # include <agrum/agrum.h>
34 
35 # include <agrum/tools/graphicalModels/inference/scheduler/scheduleMultiDim.h>
36 
37 namespace gum {
38 
39  /// returns a new distinct ID for each abtract scheduleMultiDim
40  template < typename GUM_SCALAR >
41  Idx ScheduleMultiDim< GUM_SCALAR >::_newId_() {
42  static Idx _abstract_id_ = 0;
43  return ++_abstract_id_;
44  }
45 
46  /// returns a mapping from id to multidimImplementations
47  template < typename GUM_SCALAR >
48  HashTable< Idx, const MultiDimImplementation< GUM_SCALAR >* >&
49  ScheduleMultiDim< GUM_SCALAR >::_id2multidim_() {
50  static HashTable< Idx, const MultiDimImplementation< GUM_SCALAR >* > _multidims_;
51 # ifdef GUM_DEBUG_MODE
52  // for debugging purposes, we should inform the aGrUM's debugger that
53  // the static hashtable used here will be removed at the end of the
54  // program's execution.
55  static bool first_time = true;
56 
57  if (first_time) {
58  first_time = false;
59  __debug__::_inc_deletion_("HashTable",
60  __FILE__,
61  __LINE__,
62  "destructor of",
63  (void*)&_multidims_);
64  }
65 
66 # endif /* GUM_DEBUG_MODE */
67  return _multidims_;
68  }
69 
70  /// returns the id corresponding to a given multidim
71  template < typename GUM_SCALAR >
72  HashTable< const MultiDimImplementation< GUM_SCALAR >*, Idx >&
73  ScheduleMultiDim< GUM_SCALAR >::_multidim2id_() {
74  static HashTable< const MultiDimImplementation< GUM_SCALAR >*, Idx > _multidim_ids_;
75 # ifdef GUM_DEBUG_MODE
76  // for debugging purposes, we should inform the aGrUM's debugger that
77  // the static hashtable used here will be removed at the end of the
78  // program's execution.
79  static bool first_time = true;
80 
81  if (first_time) {
82  first_time = false;
83  __debug__::_inc_deletion_("HashTable",
84  __FILE__,
85  __LINE__,
86  "destructor of",
87  (void*)&_multidim_ids_);
88  }
89 
90 # endif /* GUM_DEBUG_MODE */
91  return _multidim_ids_;
92  }
93 
94  /// returns a table indicating how many ScheduleMultiDim have the same id
95  template < typename GUM_SCALAR >
96  HashTable< Idx, Idx >& ScheduleMultiDim< GUM_SCALAR >::_id2refs_() {
97  static HashTable< Idx, Idx > _ids_;
98 # ifdef GUM_DEBUG_MODE
99  // for debugging purposes, we should inform the aGrUM's debugger that
100  // the static hashtable used here will be removed at the end of the
101  // program's execution.
102  static bool first_time = true;
103 
104  if (first_time) {
105  first_time = false;
106  __debug__::_inc_deletion_("HashTable", __FILE__, __LINE__, "destructor of", (void*)&_ids_);
107  }
108 
109 # endif /* GUM_DEBUG_MODE */
110  return _ids_;
111  }
112 
113  /// returns a table with the variables of the table corresponding to id
114  template < typename GUM_SCALAR >
115  HashTable< Idx, const Sequence< const DiscreteVariable* >* >&
116  ScheduleMultiDim< GUM_SCALAR >::_id2vars_() {
117  static HashTable< Idx, const Sequence< const DiscreteVariable* >* > _vars_;
118 # ifdef GUM_DEBUG_MODE
119  // for debugging purposes, we should inform the aGrUM's debugger that
120  // the static hashtable used here will be removed at the end of the
121  // program's execution.
122  static bool first_time = true;
123 
124  if (first_time) {
125  first_time = false;
126  __debug__::_inc_deletion_("HashTable", __FILE__, __LINE__, "destructor of", (void*)&_vars_);
127  }
128 
129 # endif /* GUM_DEBUG_MODE */
130  return _vars_;
131  }
132 
133  /// returns a table with the domain size of the table corresponding to id
134  template < typename GUM_SCALAR >
135  HashTable< Idx, Size >& ScheduleMultiDim< GUM_SCALAR >::_id2size_() {
136  static HashTable< Idx, Size > _size_;
137 # ifdef GUM_DEBUG_MODE
138  // for debugging purposes, we should inform the aGrUM's debugger that
139  // the static hashtable used here will be removed at the end of the
140  // program's execution.
141  static bool first_time = true;
142 
143  if (first_time) {
144  first_time = false;
145  __debug__::_inc_deletion_("HashTable", __FILE__, __LINE__, "destructor of", (void*)&_size_);
146  }
147 
148 # endif /* GUM_DEBUG_MODE */
149  return _size_;
150  }
151 
152  /// constructs a ScheduleMultiDim containing an already built decorator
153  template < typename GUM_SCALAR >
154  ScheduleMultiDim< GUM_SCALAR >::ScheduleMultiDim(
155  const MultiDimImplementation< GUM_SCALAR >& multidim) {
156  // for debugging purposes
157  GUM_CONSTRUCTOR(ScheduleMultiDim);
158 
159  // check whether the multidimImplementation has already been stored
160 
161  if (_multidim2id_().exists(&multidim)) {
162  // get the id already allocated to the implementation
163  _id_ = _multidim2id_().operator[](&multidim);
164 
165  // update the number of references of _id_
166  HashTable< Idx, Idx >& refs = _id2refs_();
167  ++refs[_id_];
168  } else {
169  // assign a new id to the implementation
170  _id_ = _newId_();
171 
172  // store the multidim into the set of all mappings id<->multidim
173  _id2multidim_().insert(_id_, &multidim);
174  _multidim2id_().insert(&multidim, _id_);
175 
176  // indicate that the id is currently used once
177  _id2refs_().insert(_id_, 1);
178 
179  // store the variables of the multidim
180  const Sequence< const DiscreteVariable* >* vars
181  = new Sequence< const DiscreteVariable* >(multidim.variablesSequence());
182  _id2vars_().insert(_id_, vars);
183 
184  // store the domain size of the multidim
185  _id2size_().insert(_id_, multidim.domainSize());
186  }
187  }
188 
189  /// constructs a ScheduleMultiDim containing an already built decorator
190  template < typename GUM_SCALAR >
191  ScheduleMultiDim< GUM_SCALAR >::ScheduleMultiDim(
192  const MultiDimDecorator< GUM_SCALAR >& multidim) {
193  // for debugging purposes
194  GUM_CONSTRUCTOR(ScheduleMultiDim);
195 
196  const MultiDimImplementation< GUM_SCALAR >* impl = multidim.content();
197 
198  // check whether the multidimImplementation has already been stored
199 
200  if (_multidim2id_().exists(impl)) {
201  // get the id already allocated to the implementation
202  _id_ = _multidim2id_().operator[](impl);
203 
204  // update the number of references of _id_
205  HashTable< Idx, Idx >& refs = _id2refs_();
206  ++refs[_id_];
207  } else {
208  // assign a new id to the implementation
209  _id_ = _newId_();
210 
211  // store the multidim into the set of all mappings id<->multidim
212  _id2multidim_().insert(_id_, impl);
213  _multidim2id_().insert(impl, _id_);
214 
215  // indicate that the id is currently used once
216  _id2refs_().insert(_id_, 1);
217 
218  // store the variables of the multidim
219  const Sequence< const DiscreteVariable* >* vars
220  = new Sequence< const DiscreteVariable* >(multidim.variablesSequence());
221  _id2vars_().insert(_id_, vars);
222 
223  // store the domain size of the multidim
224  _id2size_().insert(_id_, multidim.domainSize());
225  }
226  }
227 
228  /// construct an (abstract) ScheduleMultiDim for a decorator yet to be built
229  template < typename GUM_SCALAR >
230  ScheduleMultiDim< GUM_SCALAR >::ScheduleMultiDim(
231  const Sequence< const DiscreteVariable* >& vars) :
232  _id_(_newId_()) {
233  // for debugging purposes
234  GUM_CONSTRUCTOR(ScheduleMultiDim);
235 
236  // indicate that the id is currently used once
237  _id2refs_().insert(_id_, 1);
238 
239  // store the variables of the multidim
240  const Sequence< const DiscreteVariable* >* new_vars
241  = new Sequence< const DiscreteVariable* >(vars);
242  _id2vars_().insert(_id_, new_vars);
243 
244  // compute and store the domain size
245  Size size = 1;
246 
247  for (const auto var: *new_vars)
248  size *= var->domainSize();
249 
250  _id2size_().insert(_id_, size);
251  }
252 
253  /// copy constructor
254  template < typename GUM_SCALAR >
255  ScheduleMultiDim< GUM_SCALAR >::ScheduleMultiDim(const ScheduleMultiDim< GUM_SCALAR >& from) :
256  _id_(from._id_) {
257  // for debugging purposes
258  GUM_CONS_CPY(ScheduleMultiDim);
259 
260  // update the number of references of _id_
261  HashTable< Idx, Idx >& refs = _id2refs_();
262  ++refs[_id_];
263  }
264 
265  /// destructor
266  template < typename GUM_SCALAR >
267  ScheduleMultiDim< GUM_SCALAR >::~ScheduleMultiDim() {
268  // for debugging purposes
269  GUM_DESTRUCTOR(ScheduleMultiDim);
270 
271  // get the number of scheduleMultiDims that reference the same id
272  HashTable< Idx, Idx >& refs = _id2refs_();
273  Idx& nb_refs = refs[_id_];
274 
275  if (nb_refs == 1) {
276  // remove the id and the multidimdecorator from the mappings
277  if (_id2multidim_().exists(_id_)) {
278  _multidim2id_().erase(_id2multidim_().operator[](_id_));
279  _id2multidim_().erase(_id_);
280  }
281 
282  refs.erase(_id_);
283 
284  delete _id2vars_().operator[](_id_);
285  _id2vars_().erase(_id_);
286  _id2size_().erase(_id_);
287  } else
288  --nb_refs;
289  }
290 
291  /// copy operator
292  template < typename GUM_SCALAR >
293  ScheduleMultiDim< GUM_SCALAR >&
294  ScheduleMultiDim< GUM_SCALAR >::operator=(const ScheduleMultiDim< GUM_SCALAR >& from) {
295  // avoid self assignment
296  if (_id_ != from._id_) {
297  // remove the old id
298  HashTable< Idx, Idx >& refs = _id2refs_();
299  Idx& nb_refs = refs[_id_];
300 
301  if (nb_refs == 1) {
302  // remove the id and the multidimdecorator from the mappings
303  if (_id2multidim_().exists(_id_)) {
304  _multidim2id_().erase(_id2multidim_().operator[](_id_));
305  _id2multidim_().erase(_id_);
306  }
307 
308  refs.erase(_id_);
309 
310  delete _id2vars_().operator[](_id_);
311  _id2vars_().erase(_id_);
312  _id2size_().erase(_id_);
313  } else
314  --nb_refs;
315 
316  _id_ = from._id_;
317 
318  ++refs[_id_];
319  }
320 
321  return *this;
322  }
323 
324  /// checks whether two ScheduleMultiDim are related to the same table
325  template < typename GUM_SCALAR >
326  INLINE bool
327  ScheduleMultiDim< GUM_SCALAR >::operator==(const ScheduleMultiDim< GUM_SCALAR >& m) const {
328  return (_id_ == m._id_);
329  }
330 
331  /// checks whether two ScheduleMultiDim are related to different tables
332  template < typename GUM_SCALAR >
333  INLINE bool
334  ScheduleMultiDim< GUM_SCALAR >::operator!=(const ScheduleMultiDim< GUM_SCALAR >& m) const {
335  return (_id_ != m._id_);
336  }
337 
338  /// returns the multiDimImplementation actually contained in the
339  /// ScheduleMultiDim
340  template < typename GUM_SCALAR >
341  INLINE const MultiDimImplementation< GUM_SCALAR >&
342  ScheduleMultiDim< GUM_SCALAR >::multiDim() const {
343  return *(_id2multidim_().operator[](_id_));
344  }
345 
346  /// returns whether the ScheduleMultiDim contains a real
347  /// multiDimImplementation
348  template < typename GUM_SCALAR >
349  INLINE bool ScheduleMultiDim< GUM_SCALAR >::isAbstract() const {
350  return !_id2multidim_().exists(_id_);
351  }
352 
353  /// returns the id of the ScheduleMultiDim
354  template < typename GUM_SCALAR >
355  INLINE Idx ScheduleMultiDim< GUM_SCALAR >::id() const {
356  return _id_;
357  }
358 
359  /// returns the set of variables involved in the multidim
360  template < typename GUM_SCALAR >
361  INLINE const Sequence< const DiscreteVariable* >&
362  ScheduleMultiDim< GUM_SCALAR >::variablesSequence() const {
363  return *(_id2vars_().operator[](_id_));
364  }
365 
366  /// returns the domain size of the multidim
367  template < typename GUM_SCALAR >
368  INLINE Size ScheduleMultiDim< GUM_SCALAR >::domainSize() const {
369  return _id2size_().operator[](_id_);
370  }
371 
372  /// sets a new multiDimImplementation inside the wrapper
373  template < typename GUM_SCALAR >
374  void ScheduleMultiDim< GUM_SCALAR >::setMultiDim(const MultiDimImplementation< GUM_SCALAR >& m) {
375  // check whether the same Multidimimplementation has not already been
376  // wrapped with another ID. In this case, we shall throw a DuplicateElement
377  // exception
378  if (_multidim2id_().exists(&m)) {
379  if (_multidim2id_().operator[](&m) != _id_) {
380  GUM_ERROR(DuplicateElement,
381  "the multidim table has already been "
382  "wrapped into a ScheduleMultidim with another id");
383  }
384  } else {
385  // here, the multidim has never been stored into a ScheduleMultiDim
386 
387  // if the current ScheduleMultiDim already contained a
388  // multidimImplementation
389  // we should remove it first and, then, add the new one
390  if (_id2multidim_().exists(_id_)) {
391  const MultiDimImplementation< GUM_SCALAR >* impl = _id2multidim_().operator[](_id_);
392 
393  if (impl == &m) return;
394 
395  _multidim2id_().erase(impl);
396 
397  _id2multidim_().operator[](_id_) = &m;
398  } else {
399  // store the new multidim
400  _id2multidim_().insert(_id_, &m);
401  }
402 
403  _multidim2id_().insert(&m, _id_);
404 
405  // update the variables of the scheduleMultiDim
406  const Sequence< const DiscreteVariable* >& m_vars = m.variablesSequence();
407  Sequence< const DiscreteVariable* >* vars
408  = const_cast< Sequence< const DiscreteVariable* >* >(_id2vars_().operator[](_id_));
409  *vars = m_vars;
410 
411  // update the size of the wrapper
412  _id2size_().operator[](_id_) = m.domainSize();
413  }
414  }
415 
416  /// sets a new multiDimImplementation inside the wrapper
417  template < typename GUM_SCALAR >
418  INLINE void
419  ScheduleMultiDim< GUM_SCALAR >::setMultiDim(const MultiDimDecorator< GUM_SCALAR >& m) {
420  setMultiDim(*(m.content()));
421  }
422 
423  /// displays the content of the multidim
424  template < typename GUM_SCALAR >
425  std::string ScheduleMultiDim< GUM_SCALAR >::toString() const {
426  std::stringstream str;
427  str << "<";
428 
429  // get the pointer of the multidim if it exists
430 
431  try {
432  str << _id2multidim_().operator[](_id_);
433  } catch (NotFound&) { str << _id_; }
434 
435  str << ">";
436 
437  return str.str();
438  }
439 
440 } /* namespace gum */
441 
442 #endif /* DOXYGEN_SHOULD_SKIP_THIS */