aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
instantiation_inl.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 /**
23  * @file
24  * @brief Inline implemenation of gum::Instantiation.
25  *
26  * @author Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
27  */
28 
29 #include <agrum/tools/multidim/implementations/multiDimAdressable.h>
30 
31 namespace gum {
32 
33  // indicates whether a given variable belongs to the Instantiation
35  return vars__.exists(&v);
36  }
37 
38  INLINE bool Instantiation::contains(const std::string& name) const {
39  return contains(variable(name));
40  }
41 
42  // indicates whether a given variable belongs to the Instantiation
44  return vars__.exists(v);
45  }
46 
47  // modifies internally the value of a given variable of the sequence
50  vals__[varPos] = newVal;
51 
53  }
54 
55  // modifies the value of a given variable of the sequence (external function)
56  INLINE Instantiation& Instantiation::chgVal(const DiscreteVariable& v,
57  Idx newVal) {
58  try {
59  // check that the variable does belong to the instantiation and that the
60  // new
61  // value is possible.
62  Idx varPos = vars__.pos(&v); // throws NotFound if v doesn't belong to this
63 
64  if (newVal >= v.domainSize()) { GUM_ERROR(OutOfBounds, ""); }
65 
66  // if we were in overflow, indicate that we are not anymore
67  overflow__ = false;
68 
70 
71  return *this;
72  } catch (NotFound&) {
73  std::string name = "instantiation does not contain this DiscreteVariable: ";
75  }
76  }
77 
79  Idx newVal) {
80  try {
81  // check that the variable does belong to the instantiation and that the
82  // new
83  // value is possible.
84  Idx varPos = vars__.pos(v); // throws NotFound if v doesn't belong to this
85 
86  if (newVal >= v->domainSize()) { GUM_ERROR(OutOfBounds, ""); }
87 
88  // if we were in overflow, indicate that we are not anymore
89  overflow__ = false;
90 
92 
93  return *this;
94  } catch (NotFound&) {
95  std::string name = "instantiation does not contain this DiscreteVariable: ";
96  GUM_ERROR(NotFound, name + v->name());
97  }
98  }
99 
100  // modifies the value of a given variable of the sequence (external function)
102  // check that the variable does belong to the instantiation and that the new
103  // value is possible.
104  if (vals__.size() <= varPos) { GUM_ERROR(NotFound, ""); }
105 
106  if (newVal >= vars__[varPos]->domainSize()) { GUM_ERROR(OutOfBounds, ""); }
107 
108  // if we were in overflow, indicate that we are not anymore
109  overflow__ = false;
110 
112 
113  return *this;
114  }
115 
117  return chgVal(variable(var), newVal);
118  }
119 
121  const std::string& newVal) {
122  const auto& vv = variable(var);
123  Idx pos = vv.index(newVal);
124  return chgVal(vv, pos);
125  }
126 
127  // adds a new var to the sequence of vars
129  // if master__ : not allowed
130  if (master__) { GUM_ERROR(OperationNotAllowed, "in slave Instantiation"); }
131 
132  // check if the variable already belongs to the tuple of variables
133  // of the Instantiation
134  if (vars__.exists(&v)) {
136  "Var <" << v.name() << "> already exists in this instantiation");
137  }
138 
139  for (const auto& vv: vars__) {
140  if (vv->name() == v.name()) {
142  "Var with name <" << v.name()
143  << "> already exists in this instantiation");
144  }
145  }
146 
147  // actually add the new dimension
148  add__(v);
149  }
150 
151  // removes a variable from the sequence of vars
153  // if master__ : not allowed
154  if (master__) { GUM_ERROR(OperationNotAllowed, "in slave Instantiation"); }
155 
156  // check that the variable does actually belong to the Instantiation
157  if (!vars__.exists(&v)) {
158  GUM_ERROR(NotFound, "Var does not exist in this instantiation");
159  }
160 
161  // actually delete the dimension
162  erase__(v);
163  }
164 
166  erase(variable(name));
167  }
168 
169  // removes everything
171  if (master__) { GUM_ERROR(OperationNotAllowed, "in slave Instantiation"); }
172 
173  vars__.clear();
174  vals__.clear();
175  }
176 
177  // @brief returns the product of the size of the domains of the variables
178  // belonging to the matrix
180  Size s = 1;
181 
182  for (const auto var: vars__)
183  s *= var->domainSize();
184 
185  return s;
186  }
187 
188  // returns the index of a var
190  return vars__.pos(&k);
191  }
192 
193  // returns the number of vars in the sequence
194  INLINE Idx Instantiation::nbrDim() const { return vars__.size(); }
195 
196  // returns the current value of a given variable
198  if (i >= vals__.size()) {
199  GUM_ERROR(NotFound, i << " is out of bound index for the instantiation.");
200  }
201 
202  return vals__[i];
203  }
204 
205  // returns the current value of a given variable
207  return vals__[vars__.pos(&var)];
208  }
209  // returns the current value of a given variable
211  return val(variable(name));
212  }
213 
214 
215  // returns the current value of a given variable
217  return vals__[vars__.pos(pvar)];
218  }
219 
220  // returns the variable at position i in the tuple
222  return *(vars__.atPos(i));
223  }
224  // returns the variable with name in the tuple
225  INLINE const DiscreteVariable&
227  for (const auto& v: vars__) {
228  if (v->name() == name) return *v;
229  }
230 
231  GUM_ERROR(NotFound, "'" << name << "' can not be found in the instantiation.")
232  }
233 
234  // indicates whether the current value of the tuple is correct or not
235  INLINE bool Instantiation::inOverflow() const { return overflow__; }
236 
237  // end() just is a synonym for inOverflow()
238  INLINE bool Instantiation::end() const { return inOverflow(); }
239 
240  // rend() just is a synonym for inOverflow()
241  INLINE bool Instantiation::rend() const { return inOverflow(); }
242 
243  // indicates that the current value is correct even if it should be in
244  // overflow
246 
247  // alias for unsetOverflow
249 
250  // operator ++
252  Size p = nbrDim();
253  if (p == 0) { overflow__ = true; }
254 
255  if (overflow__) return;
256  p -= 1;
257  Idx cpt = 0;
258  // if we are in overflow, do nothing
259 
260  // perform the increment
261  while (true) {
262  Idx v = vals__[cpt];
263 
264  if (v + 1 == vars__[cpt]->domainSize()) {
265  vals__[cpt] = 0;
266 
267  if (cpt == p) {
268  overflow__ = true;
270  return;
271  } else
272  ++cpt;
273  } else {
274  ++vals__[cpt];
275  break;
276  }
277  }
278 
280  }
281 
282  // operator --
284  Size p = nbrDim();
285  if (p == 0) { overflow__ = true; }
286 
287  if (overflow__) return;
288  p -= 1;
289  Idx cpt = 0;
290  // if we are in overflow, do nothing
291 
292  // perform the increment
293  while (true) {
294  Idx v = vals__[cpt];
295 
296  if (v == 0) {
297  vals__[cpt] = vars__[cpt]->domainSize() - 1;
298 
299  if (cpt == p) {
300  overflow__ = true;
301 
303 
304  return;
305  } else
306  ++cpt;
307  } else {
308  --vals__[cpt];
309  break;
310  }
311  }
312 
314  }
315 
316  // operator ++
318  inc();
319  return *this;
320  }
321 
322  // operator --
324  dec();
325  return *this;
326  }
327 
328  // operator +=
330  for (Idx i = 0; i < depl; i++)
331  inc();
332 
333  return *this;
334  }
335 
336  // operator -=
338  for (Idx i = 0; i < depl; i++)
339  dec();
340 
341  return *this;
342  }
343 
344  // assign the (0,0,...) first value to the tuple of the Instantiation.
346  overflow__ = false;
347  Size s = nbrDim();
348 
349  for (Idx p = 0; p < s; ++p)
350  vals__[p] = 0;
351 
353  }
354 
355  // put the (D1-1,D2-1,...) last value in the Instantiation
357  overflow__ = false;
358  Size s = nbrDim();
359 
360  for (Idx p = 0; p < s; ++p)
361  vals__[p] = vars__[p]->domainSize() - 1;
362 
364  }
365 
366  // operator ++ limited only to the variables in i
368  // if i is empty, overflow and do nothing
369  if (i.nbrDim() == 0) {
370  overflow__ = true;
371  return;
372  }
373 
374  // if we are in overflow, do nothing
375  if (overflow__) return;
376 
377  Size p = i.nbrDim() - 1;
378 
379  Idx i_cpt = 0;
380 
381  while (true) {
382  // verify that vars__[cpt] belongs to i before incrementing its value
383  const DiscreteVariable& v = i.variable(i_cpt);
384 
385  if (!contains(v)) {
386  if (i_cpt == p) {
387  overflow__ = true;
388  return;
389  } else
390  ++i_cpt;
391  } else {
392  Idx cpt = pos(v);
393  Idx iv = vals__[cpt];
394 
395  if (iv + 1 == vars__[cpt]->domainSize()) {
396  chgVal__(cpt, 0);
397 
398  if (i_cpt == p) {
399  overflow__ = true;
400  return;
401  } else
402  ++i_cpt;
403  } else {
404  chgVal__(cpt, iv + 1);
405  return;
406  }
407  }
408  }
409  }
410 
411  // operator -- limited only to the variables in i
413  Size p = i.nbrDim() - 1;
414  Idx i_cpt = 0;
415  // if we are in overflow, do nothing
416 
417  if (overflow__) return;
418 
419  while (true) {
420  // verify that vars__[cpt] belongs to i before incrementing its value
421  const DiscreteVariable& v = i.variable(i_cpt);
422 
423  if (!contains(v)) {
424  if (i_cpt == p) {
425  overflow__ = true;
426  return;
427  } else
428  ++i_cpt;
429  } else {
430  Idx cpt = pos(v);
431  Idx iv = vals__[cpt];
432 
433  if (iv == 0) {
434  chgVal__(cpt, vars__[cpt]->domainSize() - 1);
435 
436  if (i_cpt == p) {
437  overflow__ = true;
438  return;
439  } else
440  ++i_cpt;
441  } else {
442  chgVal__(cpt, iv - 1);
443  return;
444  }
445  }
446  }
447  }
448 
449  // reorder vars in *this
452  }
453 
454  // put the (0,0,...) first value in the Instantiation for the variables in i
456  overflow__ = false;
457  Idx s = nbrDim();
458 
459  for (Size p = 0; p < s; ++p)
460  if (i.contains(vars__[p])) chgVal__(p, 0);
461  }
462 
463  // change values with those in i
465  overflow__ = false;
466  Idx s = i.nbrDim();
467 
468  for (Size p = 0; p < s; ++p)
469  if (contains(i.variable(p))) chgVal__(pos(i.variable(p)), i.val(p));
470 
471  return *this;
472  }
473 
474  // put the (D1-1,D2-1,...) lastvalue in the Instantiation for variables in i
476  overflow__ = false;
477  Idx s = nbrDim();
478 
479  for (Size p = 0; p < s; ++p)
480  if (i.contains(vars__[p])) chgVal__(p, vars__[p]->domainSize() - 1);
481  }
482 
483  // operator ++ for the variables not in i
485  Size p = nbrDim() - 1;
486  Idx cpt = 0;
487  // if we are in overflow, do nothing
488 
489  if (overflow__) return;
490 
491  while (true) {
492  if (i.contains(vars__[cpt])) {
493  if (cpt == p) {
494  overflow__ = true;
495  return;
496  } else
497  ++cpt;
498  } else {
499  Idx v = vals__[cpt];
500 
501  if (v + 1 == vars__[cpt]->domainSize()) {
502  chgVal__(cpt, 0);
503 
504  if (cpt == p) {
505  overflow__ = true;
506  return;
507  } else
508  ++cpt;
509  } else {
510  chgVal__(cpt, v + 1);
511  return;
512  }
513  }
514  }
515  }
516 
517  // operator -- for the variables not in i
519  Size p = nbrDim() - 1;
520  Idx cpt = 0;
521  // if we are in overflow, do nothing
522 
523  if (overflow__) return;
524 
525  while (true) {
526  if (i.contains(vars__[cpt])) {
527  if (cpt == p) {
528  overflow__ = true;
529  return;
530  } else
531  ++cpt;
532  } else {
533  Idx v = vals__[cpt];
534 
535  if (v == 0) {
536  chgVal__(cpt, vars__[cpt]->domainSize() - 1);
537 
538  if (cpt == p) {
539  overflow__ = true;
540  return;
541  } else
542  ++cpt;
543  } else {
544  chgVal__(cpt, v - 1);
545  return;
546  }
547  }
548  }
549  }
550 
551  // put the (0,0,...) first val in the Instantiation for the variables not in
552  // i
554  overflow__ = false;
555  Idx s = nbrDim();
556 
557  for (Size p = 0; p < s; ++p)
558  if (!i.contains(vars__[p])) chgVal__(p, 0);
559  }
560 
561  // put the (D1-1,D2-1,...) lastvalue in the Instantiation for vars not in i
563  overflow__ = false;
564  Idx s = nbrDim();
565 
566  for (Size p = 0; p < s; ++p)
567  if (!i.contains(vars__[p])) chgVal__(p, vars__[p]->domainSize() - 1);
568  }
569 
570  // operator ++ for vars which are not v.
572  Size p = nbrDim() - 1;
573  Idx cpt = 0;
574  // if we are in overflow, do nothing
575 
576  if (overflow__) return;
577 
578  while (true) {
579  if (vars__[cpt] == &v) {
580  if (cpt == p) {
581  overflow__ = true;
582  return;
583  } else
584  ++cpt;
585  } else {
586  Idx iv = vals__[cpt];
587 
588  if (iv + 1 == vars__[cpt]->domainSize()) {
589  chgVal__(cpt, 0);
590 
591  if (cpt == p) {
592  overflow__ = true;
593  return;
594  } else
595  ++cpt;
596  } else {
597  chgVal__(cpt, iv + 1);
598  return;
599  }
600  }
601  }
602  }
603 
604  // operator -- for vars which are not v.
606  Size p = nbrDim() - 1;
607  Idx cpt = 0;
608  // if we are in overflow, do nothing
609 
610  if (overflow__) return;
611 
612  while (true) {
613  if (vars__[cpt] == &v) {
614  if (cpt == p) {
615  overflow__ = true;
616  return;
617  } else
618  ++cpt;
619  } else {
620  Idx iv = vals__[cpt];
621 
622  if (iv == 0) {
623  chgVal__(cpt, vars__[cpt]->domainSize() - 1);
624 
625  if (cpt == p) {
626  overflow__ = true;
627  return;
628  } else
629  ++cpt;
630  } else {
631  chgVal__(cpt, iv - 1);
632  return;
633  }
634  }
635  }
636  }
637 
638  // assign the (0,0,...) first value to variables which are not v.
640  overflow__ = false;
641  Idx s = nbrDim();
642 
643  for (Size p = 0; p < s; ++p) {
644  if (vars__[p] == &v) {
645  Idx oldval = vals__[p];
646  setFirst();
647  chgVal__(p, oldval);
648  return;
649  }
650  }
651 
652  setFirst();
653  }
654 
655  // put the (D1-1,D2-1,...) lastvalue in the Instantiation for vars != v
657  overflow__ = false;
658  Idx s = nbrDim();
659 
660  for (Size p = 0; p < s; ++p) {
661  if (vars__[p] == &v) {
662  Idx oldval = vals__[p];
663  setLast();
664  chgVal__(p, oldval);
665  return;
666  }
667  }
668 
669  setLast();
670  }
671 
672  // operator ++ for variable v only
674  // get the position of the variable
675  Idx cpt = vars__.pos(&v);
676  // if we are in overflow, do nothing
677 
678  if (overflow__) return;
679 
680  Idx p = vals__[cpt];
681 
682  if (p + 1 == v.domainSize()) {
683  chgVal__(cpt, 0);
684  overflow__ = true;
685  } else {
686  chgVal__(cpt, p + 1);
687  }
688  }
689 
690  // operator -- for variable v only
692  // get the position of the variable
693  Idx cpt = vars__.pos(&v);
694  // if we are in overflow, do nothing
695 
696  if (overflow__) return;
697 
698  Idx p = vals__[cpt];
699 
700  if (p == 0) {
701  chgVal__(cpt, v.domainSize() - 1);
702  overflow__ = true;
703  } else {
704  chgVal__(cpt, p - 1);
705  }
706  }
707 
708  // assign the first value in the Instantiation for var v.
710  overflow__ = false;
711  chgVal__(vars__.pos(&v), 0);
712  }
713 
714  // assign the last value to var v.
716  overflow__ = false;
717  chgVal__(vars__.pos(&v), v.domainSize() - 1);
718  }
719 
720  // indicates whether the Instantiation has a master MultiDimAdressable
721  INLINE bool Instantiation::isSlave() const { return (master__ != nullptr); }
722 
723  // indicates wether the MultiDimAdressable* m is the master
725  return (master__ == m);
726  }
727 
728  // indicates wether the MultiDimAdressable* m is the master
730  return isMaster(&m);
731  }
732 
733  // returns the sequence of DiscreteVariable
734  INLINE const Sequence< const DiscreteVariable* >&
736  return vars__;
737  }
738 
739 
740  // replace 2 vars in the Instantiation
742  if (i == j) return;
743 
744  vars__.swap(i, j);
745 
746  Idx v;
747  v = vals__[i];
748  vals__[i] = vals__[j];
749  vals__[j] = v;
750  }
751 
752  // reordering
753  INLINE
754  void
756  if (master__ != nullptr) {
758  "Reordering impossible in slave instantiation");
759  }
760 
762  }
763 
764  INLINE
766  const Sequence< const DiscreteVariable* >& original) {
767  Idx max = original.size();
768  Idx position = 0;
769  for (Idx i = 0; i < max; ++i) {
770  const DiscreteVariable* pv = original.atPos(i);
771 
772  if (contains(pv)) {
773  auto p = pos(*pv);
774  GUM_ASSERT(p >= position); // this var should not be
775  // already placed.
776  swap__(position, p);
777  position++;
778  }
779  }
780  }
781 
782 
783  // add new dim by master
785  const DiscreteVariable& v) {
786  if (m != master__) {
787  GUM_ERROR(OperationNotAllowed, "only master can do this");
788  }
789 
790  add__(v);
791  }
792 
793 
794  // adds a new var to the sequence of vars
796  vars__.insert(&v);
797  vals__.push_back(0);
798  overflow__ = false;
799  }
800 
801  // removes a variable from the sequence of vars
803  // get the position of the variable
804  Idx pos = vars__.pos(&v);
805  vars__.erase(&v);
806  vals__.erase(vals__.begin() + pos);
807  }
808 
809  // is this empty ?
810  INLINE bool Instantiation::empty() const { return vals__.empty(); }
811 
812  // Replace x by y.
814  const DiscreteVariable* y) {
816  }
817 
818  /// returns a hashed key for hash tables the keys of which are represented
819  /// by vectors of Idx
821  Size h = Size(0);
822  for (const DiscreteVariable* k:
823  key.variablesSequence()) // k are unique only by address (not by name)
824  h += HashFunc< const DiscreteVariable* >::castToSize(k) * Size(key.val(*k));
825 
826  return h;
827  }
828 
829  /// returns a hashed key for hash tables the keys of which are represented
830  /// by vectors of Idx
831  INLINE Size
833  return castToSize(key) & this->hash_mask_;
834  }
835 
837  if (inOverflow() && other.inOverflow()) return true;
838  if (other.nbrDim() != nbrDim()) return false;
839  for (const auto& k: variablesSequence()) {
840  if (!other.contains(k)) return false;
841  if (val(*k) != other.val(*k)) return false;
842  }
843  return true;
844  }
845 } /* namespace gum */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669