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