aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
instantiation.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 Header files of gum::Instantiation.
25  *
26  * @author Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
27  */
28 #ifndef GUM_INSTANTIATION_H
29 #define GUM_INSTANTIATION_H
30 
31 #include <ostream>
32 #include <sstream>
33 
34 #include <agrum/agrum.h>
35 
36 #include <agrum/tools/core/hashTable.h>
37 #include <agrum/tools/multidim/implementations/multiDimInterface.h>
38 
39 namespace gum {
40 
41  class MultiDimAdressable;
42  // =========================================================================
43  // === GUM_INSTANTIATION ===
44  // =========================================================================
45  /**
46  * @class Instantiation
47  * @headerfile instantiation.h <agrum/tools/multidim/instantiation.h>
48  * @brief Class for assigning/browsing values to tuples of discrete
49  * variables.
50  * @ingroup multidim_group
51  *
52  * Instantiation is designed to assign values to tuples of variables and to
53  * efficiently loop over values of subsets of variables. This class can be
54  * used in two different flavors:
55  * - the tuple of variables in the Instantiation is related to a
56  * multidimensional array and, when we loop over the possible values of the
57  * tuple, we also loop at the same time over the corresponding values in the
58  * array.
59  * - the tuple of variables in the Instantiation is not related to a
60  * multidimensional array and we can loop over the possible values of the
61  * tuple without looping over values fo any array.
62  *
63  * An Instantiation can be associated/deassociated to a given
64  * multidimensional array using the
65  * MultiDimAdressable::registerSlave(Instantiation& i) and
66  * MultiDimAdressable::unregisterSlave functions. Note that, to be
67  * registrable, the Instantiation must have precisely the same variables as
68  * the array. As a consequence, adding or removing a variable from a
69  * Instantiation associated to an array will unregister it. This behavior is
70  * compulsory as, if it were still associated, it would not be possible to
71  * retrieve a correct value of the array given a value of the Instantiation.
72  * For instance, if M[A,B,C] is an array indexed by Boolean variables A,B,C,
73  * Which value of M should be returned if B=0 and C=0? We do not know for
74  * sure as we do not know the value of A. Note also that, at any time, you
75  * can unregister a Instantiation from its master multidimensional array and
76  * you can ask to associate it (provided the tuple of variable match).
77  *
78  * To print information about a Instantiation use the following function:
79  * @see operator<<(std::ostream&, const Instantiation&).
80  */
81 
82  class Instantiation: public MultiDimInterface {
83  public:
84  // =========================================================================
85  /// @name Constructors / Destructors
86  // =========================================================================
87  /// @{
88 
89  /**
90  * @brief Default constructor: creates an empty tuple.
91  */
92  Instantiation();
93 
94  /**
95  * @brief Copy constructor.
96  *
97  * Note that the Instantiation is by default associated to the same
98  * MultiDimAdressable as aI. This means that looping over values of the
99  * tuple will induce looping over the values of the MultiDimAdressable.
100  * Similarly, the value of the tuple is that of aI, and, if the
101  * Instantiation is slaved, its master is notified of the value of the
102  * Instantiation if notifyMaster is true.
103  *
104  * @param aI The Instantiation we copy.
105  * @param notifyMaster Whether or not notify master if exits.
106  */
107  Instantiation(const Instantiation& aI, const bool notifyMaster = true);
108 
109  /**
110  * @brief Copy operator.
111  *
112  * If this is a slave but not with the same as aI's master: if aI and this
113  * does not share the same variables then an OperationNotAllowed will we be
114  * raised. Otherwise calls this->setVals( aI ).
115  *
116  * If this is not a slave, copies aI.
117  *
118  * @param aI The Instantiation to copy.
119  *
120  * @throw OperationNotAllowed Raised if copy is not allowed.
121  */
122  Instantiation& operator=(const Instantiation& aI);
123 
124  /**
125  * @brief Constructor for a Instantiation of all the variables of a
126  * MultiDimAdressable.
127  *
128  * The variables of the Instantiation are those of aMD (actually, they are
129  * shared in memory). All the variables of aMD belong to the tuple of
130  * variables to be instantiated.
131  *
132  * Note that the Instantiation is by default associated to aMD, i.e.,
133  * looping over values of the tuple will induce looping over the values of
134  * aMD. The value given to the tuple is the first possible value, that is,
135  * (0,...,0). If the Instantiation is slaved, its master is notified of
136  * the value of the Instantiation.
137  *
138  * @param aMD The array the variables of which are those of the
139  * Instantiation.
140  */
141  Instantiation(MultiDimAdressable& aMD);
142 
143  /**
144  * @brief Constructor for a Instantiation of all the variables of a
145  * MultiDimAdressable.
146  *
147  * The variables of the Instantiation are those of aMD (actually, they are
148  * shared in memory). All the variables of aMD belong to the tuple of
149  * variables to be instantiated.
150  *
151  * Note that the Instantiation is by default associated to aMD, i.e.,
152  * looping over values of the tuple will induce looping over the values of
153  * aMD. The value given to the tuple is the first possible value, that is,
154  * (0,...,0). If the Instantiation is slaved, its master is notified of
155  * the value of the Instantiation.
156  *
157  * @param aMD The array the variables of which are those of the
158  * Instantiation.
159  */
160  Instantiation(const MultiDimAdressable& aMD);
161 
162  /**
163  * @brief Constructor for a Instantiation of all the variables of a
164  * MultiDimAdressable.
165  *
166  * The variables of the Instantiation are those of aMD (actually, they are
167  * shared in memory). All the variables of aMD belong to the tuple of
168  * variables to be instantiated.
169  *
170  * Note that the Instantiation is by default associated to aMD, i.e.,
171  * looping over values of the tuple will induce looping over the values of
172  * aMD. The value given to the tuple is the first possible value, that is,
173  * (0,...,0). If the Instantiation is slaved, its master is notified of
174  * the value of the Instantiation.
175  *
176  * @param aMD The array the variables of which are those of the
177  * Instantiation.
178  */
179  Instantiation(MultiDimAdressable* aMD);
180 
181  /**
182  * @brief Constructor for a Instantiation of all the variables of a
183  * MultiDimAdressable.
184  *
185  * The variables of the Instantiation are those of aMD (actually, they are
186  * shared in memory). All the variables of aMD belong to the tuple of
187  * variables to be instantiated.
188  *
189  * Note that the Instantiation is by default associated to aMD, i.e.,
190  * looping over values of the tuple will induce looping over the values of
191  * aMD. The value given to the tuple is the first possible value, that is,
192  * (0,...,0). If the Instantiation is slaved, its master is notified of
193  * the value of the Instantiation.
194  *
195  * @param aMD The array the variables of which are those of the
196  * Instantiation.
197  */
198  Instantiation(const MultiDimAdressable* aMD);
199 
200  /**
201  * @brief Destructor.
202  */
203  ~Instantiation();
204 
205  /// @}
206  // =========================================================================
207  /// @name Accessors / Modifiers
208  // =========================================================================
209  /// @{
210 
211  /**
212  * @brief Returns the number of variables in the Instantiation.
213  * @return Returns the number of variables in the Instantiation.
214  */
215  Idx nbrDim() const final;
216 
217  /**
218  * @brief Adds a new variable in the Instantiation.
219  *
220  * If variable v already belongs to the Instantiation tuple of variables,
221  * then DuplicateElement is thrown in this case. The value of the new
222  * variable is set to that of index 0, that is, the first possible value
223  * for the variable. Since an instantiation must share the same set of
224  * variables with his master an OperationNotAllowed is raised if you try to
225  * add a variable of a slaved instantiation.
226  *
227  * @warning Variable v is known to the Instantiation only by a pointer to
228  * it. As a result, this is not a copy of v that is used by the
229  * Instantiation, but rather v itself. As such, v should never be deleted
230  * from memory until the Instantiation is removed.
231  *
232  * @param v The new variable added to this Instantiation.
233  *
234  * @throw DuplicateElement Raised if v is already in this Instantiation.
235  * @throw InvalidArgument Raised if the name of v is already used in this
236  * Instantiation.
237  * @throw OperationNotAllowed Raised if this is a slave Instantiation.
238  */
239  void add(const DiscreteVariable& v) final;
240 
241  /**
242  * @brief Removes a variable from the Instantiation.
243  *
244  * If variable v does not belong to the Instantiation tuple of variables,
245  * then NotFound is thrown. Since an instantiation must share the same set
246  * of variables with his master an OperationNotAllowed is raised if you try
247  * to remove a variable from a slaved instantiation.
248  *
249  * @param v The variable to remove from this Instantiation.
250  *
251  * @throw NotFound Raised if v does not belong to this Instantiation.
252  * @throw OperationNotAllowed Raised if the instantiation is a slave.
253  */
254  void erase(const DiscreteVariable& v) final;
255  void erase(const std::string& name);
256 
257  /**
258  * @brief Erase all variables from an Instantiation
259  * @throw OperationNotAllowed Raised if the instantiation is a slave.
260  */
261  void clear();
262 
263  /**
264  * @brief Returns the product of the variable's domain size in the
265  * Instantiation.
266  * @return Returns the product of the variable's domain size in the
267  * Instantiation.
268  */
269  Size domainSize() const final;
270 
271  /**
272  * @brief Returns the position of the variable v.
273  * @return Returns the position of the variable v.
274  * @param v The variable for which its position is return.
275  *
276  * @throw NotFound Raised if v does not belong to the instantiation.
277  */
278  Idx pos(const DiscreteVariable& v) const final;
279 
280  /**
281  * @brief Returns the current value of the variable at position i.
282  *
283  * @warning For speed issues, the function does not actually check whether
284  * the overflow flag is set before returning the current value of the
285  * variable as, usually, it is not necessary. If need be, use function
286  * inOverflow() to check.
287  *
288  * @param i The index of the variable.
289  * @return Returns the current value of the variable at position i.
290  *
291  * @throw NotFound Raised if the element cannot be found.
292  */
293  Idx val(Idx i) const;
294 
295  /**
296  * @brief Returns the current value of a given variable.
297  *
298  * @warning For speed issues, the function does not actually check whether
299  * the overflow flag is set before returning the current value of the
300  * variable as, usually, it is not necessary. If need be, use function
301  * inOverflow() to check.
302  *
303  * @param var The variable the value of which we wish to know.
304  * @return Returns the current value of a given variable.
305  *
306  * @throw NotFound Raised it var does not belong to the instantiation.
307  */
308  Idx val(const DiscreteVariable& var) const;
309  Idx val(const std::string& name) const;
310 
311  /**
312  * @brief Returns the current value of a given variable.
313  *
314  * @warning For speed issues, the function does not actually check whether
315  * the overflow flag is set before returning the current value of the
316  * variable as, usually, it is not necessary. If need be, use function
317  * inOverflow() to check.
318  *
319  * @param pvar The variable for which the value is returned.
320  * @return Returns the current value of a given variable.
321  *
322  * @throw NotFound Raised if var does not belong to the instantiation.
323  */
324  Idx valFromPtr(const DiscreteVariable* pvar) const;
325 
326  /**
327  * @brief Returns the variable at position i in the tuple.
328  *
329  * @param i The index of the variable
330  * @return Returns the variable at position i in the tuple.
331  * @throw NotFound Raised if the element cannot be found.
332  */
333  const DiscreteVariable& variable(Idx i) const final;
334 
335  /**
336  * @brief Returns the variable with the name
337  *
338  * @param name The index of the variable
339  * @return Returns the variable qith the name in the tuple.
340  * @warging This function is not O(1)
341  * @throw NotFound Raised if the element cannot be found.
342  */
343  const DiscreteVariable& variable(const std::string& name) const final;
344 
345  /**
346  * @brief Assign newval to variable v in the Instantiation.
347  *
348  * Consider the values of v as an array indexed from 0 to n of values
349  * (which might be anything from real numbers to strings, etc). Parameter
350  * newval indicates the index in this array of the new value taken by v.
351  *
352  * In addition to modifying the value of the variable, the Instantiation
353  * informs its master of the modification. This function also unsets the
354  * overflow flag.
355  *
356  * @param v The variable whose value is assigned.
357  * @param newval The index of the value assigned.
358  * @return Returns a reference to *this in order to chain the chgVal.
359  *
360  * @throw NotFound Raised if variable v does not belong to the
361  * instantiation.
362  * @throw OutOfBound Raised if newval is not a possible value for v.
363  */
364  Instantiation& chgVal(const DiscreteVariable& v, Idx newval);
365 
366  /**
367  * @brief Assign newval to variable v in the Instantiation.
368  *
369  * Consider the values of v as an array indexed from 0 to n of values
370  * (which might be anything from real numbers to strings, etc). Parameter
371  * newval indicates the index in this array of the new value taken by v.
372  *
373  * In addition to modifying the value of the variable, the Instantiation
374  * informs its master of the modification. This function also unsets the
375  * overflow flag.
376  *
377  * @param v The variable whose value is assigned.
378  * @param newval The index of the value assigned.
379  * @return Returns a reference to *this in order to chain the chgVal.
380  *
381  * @throw NotFound Raised if variable v does not belong to the
382  * instantiation.
383  * @throw OutOfBound Raised if newval is not a possible value for v.
384  */
385  Instantiation& chgVal(const DiscreteVariable* v, Idx newval);
386 
387  /**
388  * @brief Assign newval to variable at position varPos in the Instantiation.
389  *
390  * Consider the values of v as an array indexed from 0 to n of values
391  * (which might be anything from real numbers to strings, etc). Parameter
392  * newval indicates the index in this array of the new value taken by v.
393  *
394  * In addition to modifying the value of the variable, the Instantiation
395  * informs its master of the modification. This function also unsets the
396  * overflow flag.
397  *
398  * @param varPos The index of the variable whose value is assigned in the
399  * tuple of variables of the Instantiation.
400  * @param newval The index of the value assigned.
401  * @return A reference to *this in order to chain the chgVal.
402  *
403  * @throw NotFound Raised if the variable does not belong to this
404  * @throw OutOfBound Raised if newval is not a possible value for the
405  * variable
406  */
407  Instantiation& chgVal(Idx varPos, Idx newval);
408 
409  /**
410  * @brief Assign newval to variable at position varPos in the Instantiation.
411  *
412  * Consider the values of v as an array indexed from 0 to n of values
413  * (which might be anything from real numbers to strings, etc). Parameter
414  * newval indicates the index in this array of the new value taken by v.
415  *
416  * In addition to modifying the value of the variable, the Instantiation
417  * informs its master of the modification. This function also unsets the
418  * overflow flag.
419  *
420  * @param var the name of the variable whose value is assigned in the
421  * tuple of variables of the Instantiation.
422  * @param newval The index of the value assigned.
423  * @return A reference to *this in order to chain the chgVal.
424  *
425  * @throw NotFound Raised if the variable does not belong to this
426  * @throw NotFound Raised if newval is not a possible value for the
427  * variable
428  */
429  Instantiation& chgVal(const std::string& var, Idx newval);
430 
431  /**
432  * @brief Assign newval to variable at position varPos in the Instantiation.
433  *
434  * Consider the values of v as an array indexed from 0 to n of values
435  * (which might be anything from real numbers to strings, etc). Parameter
436  * newval indicates the index in this array of the new value taken by v.
437  *
438  * In addition to modifying the value of the variable, the Instantiation
439  * informs its master of the modification. This function also unsets the
440  * overflow flag.
441  *
442  * @param var the name of the variable whose value is assigned in the
443  * tuple of variables of the Instantiation.
444  * @param newval The label of the value assigned.
445  * @return A reference to *this in order to chain the chgVal.
446  *
447  * @throw NotFound Raised if the variable does not belong to this
448  * @throw OutOfBound Raised if newval is not a possible value for the
449  * variable
450  */
451  Instantiation& chgVal(const std::string& var, const std::string& newval);
452 
453  /**
454  * @brief Assign the values from i in the Instantiation.
455  *
456  * For any variable in i and in *this, value of the variable in i is
457  * assigned to the variable in *this.
458  *
459  * In addition of modifying the value of the variables in *this, the
460  * Instantiation informs its master of the modification. This function
461  * also unsets the overflow flag.
462  *
463  * If no variables in i matches, then no value is changed.
464  *
465  * @warning Variables has to be "the same". Therefore chgValIn is usefull
466  * in a same domain variables (for instance a BN). However two identical
467  * variables will not be recognized as same (for instance between 2 BNs).
468  *
469  * @see Instantiation::setValsFrom for this kind of utilisation.
470  *
471  * @param i A Instantiation in which the new values are searched.
472  * @return Returns a reference to *this in order to chain the chgVal.
473  */
474  Instantiation& setVals(const Instantiation& i);
475 
476  /**
477  * @brief Assign the values of external in *this, using map as a bijection
478  * between external and this variables.
479  *
480  * @param map Keys are variables in external.
481  * @param external An instantiation used to change the values in j.
482  *
483  * @throw NotFound Raised if a variable in external does not point to a
484  * variable in *this or in external.
485  */
486  void setValsFrom(
487  const HashTable< const DiscreteVariable*, const DiscreteVariable* >& map,
488  const Instantiation& external);
489 
490  /**
491  * Indicates whether a given variable belongs to the Instantiation.
492  *
493  * @param v The variable for which the test is made.
494  * @return Returns true if v is in the Instantiation.
495  */
496  bool contains(const DiscreteVariable& v) const final;
497  bool contains(const std::string& name) const;
498 
499  /**
500  * Indicates whether a given variable belongs to the Instantiation.
501  *
502  * @param v A pointer on the variable for which the test is made.
503  * @return Returns true if *v is in the Instantiation.
504  */
505  bool contains(const DiscreteVariable* v) const;
506 
507  /**
508  * @brief Returns the sequence of DiscreteVariable of this instantiation.
509  * @return Returns the sequence of DiscreteVariable of this instantiation.
510  */
511  const Sequence< const DiscreteVariable* >& variablesSequence() const final;
512 
513  /**
514  * @brief Returns true if the instantiation is empty.
515  * @return Returns true if the instantiation is empty.
516  */
517  virtual bool empty() const final;
518 
519  /// @}
520  // =========================================================================
521  /// @name Overflow management methods.
522  // =========================================================================
523  /// @{
524 
525  /**
526  * @brief Indicates whether the current value of the tuple is correct or
527  * not.
528  *
529  * The function inOverflow() is used to flag overflowed operation (for
530  * instance, ++ on the last value or -- on the first value will produce an
531  * incorrect value of the tuple. Hence inOverflow() is used as an
532  * end()/rend() function for loops on Instantiation.
533  *
534  * @code
535  * for(Instantiation i.setFirst(); !i.inOverflow(); ++i) {
536  * // code...
537  * }
538  * @endcode
539  */
540  bool inOverflow() const;
541 
542  /**
543  * @brief Removes the flag overflow. See full documentation for details.
544  * (Recommended).
545  *
546  * When we use multiple inner loops w.r.t. a given Instantiation, it may
547  * happen that one inner loop reaches the end() of the Instantiation while
548  * the outer loops do not have reached it. This means that the inner loop
549  * has toggled the overflow flag. To enable the other loops to go on, we
550  * must unset this flag using function unsetOverflow(). For instance,
551  * assume that Prob represents probability P(b|a,c), then normalizing this
552  * proba can be performed using the following code:
553  *
554  * @code
555  * // assume the probability has been defined somewhere:
556  * MultiDimArray<double> Prob;
557  *
558  * // create 2 instantiations for the 2 necessary loops
559  * Instantiation i(Prob), j;
560  * j << a << c;
561  * double delta;
562  *
563  * // outer loop: loop over the values of b
564  * for(i.setFirstIn(j); !i.end(); i.incIn(j))
565  * {
566  * delta = 0.0;
567  * // inner loop: loop over the values of a and c
568  * for(i.setFirstOut(j); !i.end(); i.incerr(j))
569  * delta += dd[i];
570  * for(i.setFirstOut(j); !i.end(); i.incerr(j))
571  * dd[i] /= delta;
572  * // indicate that the end() reached after looping over a and c does not
573  * // correspond to an end() for the loop w.r.t. b
574  * i.unsetOverflow();
575  * }
576  * @endcode
577  */
578 
579  void unsetOverflow();
580 
581  /**
582  * @brief Alias for unsetOverflow().
583  * @see unsetOverflow().
584  */
585  void unsetEnd();
586 
587  /**
588  * @brief Returns true if the Instantiation reached the end.
589  *
590  * Function end() should be used as in:
591  * @code
592  * for(Instantiation i.setFirst();! i.end(); ++i) {
593  * // code
594  * }
595  * @endcode
596  *
597  * @return Returns true if the Instantiation reached the end.
598  */
599  bool end() const;
600 
601  /**
602  * @brief Returns true if the Instantiation reached the rend.
603  *
604  * Function end() should be used as in:
605  * @code
606  * for(Instantiation i.setLast();! i.rend(); --i) {
607  * // code
608  * }
609  * @endcode
610  *
611  * @return Returns true if the Instantiation reached the rend.
612  */
613  bool rend() const;
614 
615  /// @}
616  // =========================================================================
617  /// @name Incrementation and decrementation methods
618  // =========================================================================
619  /// @{
620 
621  /**
622  * @brief Operator increment.
623  *
624  * Note that this operator never throws an exception when it reaches the
625  * end of the possible values of the tuple of variables of the
626  * Instantiation. To know if we reached the end, use function end(). If
627  * the Instantiation is related to a MultiDimAdressable, then the
628  * corresponding value in the latter is updated. If we already reached the
629  * end() or the rend() of the possible values, function inc() will perform
630  * nothing (this prevents looping inadvertently several times within the
631  * same loop). To unset the end flag, use functions unsetOverflow(),
632  * unsetEnd() or one of the setFirst() or setLast().
633  *
634  * Usage example:
635  * @code
636  * for(Instantiation i.setFirst();! i.end(); i.inc()) {
637  * // code
638  * }
639  * @endcode
640  */
641  void inc();
642 
643  /**
644  * @brief Operator decrement
645  *
646  * Note that this operator never throws an exception when it reaches the
647  * end of the possible values of the tuple of variables of the
648  * Instantiation. To know if we reached the end, use function end(). If
649  * the Instantiation is related to a MultiDimAdressable, then the
650  * corresponding value in the latter is updated. If we already reached the
651  * end() or the rend() of the possible values, function inc() will perform
652  * nothing (this prevents looping inadvertently several times within the
653  * same loop). To unset the end flag, use functions unsetOverflow(),
654  * unsetEnd() or one of the setFirst() or setLast().
655  *
656  * Usage example:
657  * @code
658  * for(Instantiation i.setLast();! i.rend(); i.dec()) {
659  * // code
660  * }
661  * @endcode
662  */
663  void dec();
664 
665  /**
666  * @brief Operator increment for the variables in i.
667  *
668  * Note that, if the Instantiation is related to a MultiDimAdressable, then
669  * the corresponding value in the latter is updated.
670  *
671  * Note also that this operator never throws an exception when it reaches
672  * the end of the possible values of the tuple of variables of the
673  * Instantiation. To know if we reached the end, use function end().
674  * Finally, let us mention that the value of instantiation i is not taken
675  * into account, that is, only the variables belonging to i are taken into
676  * account. The next value of *this is thus computed w.r.t. to the current
677  * value of *this. If we already reached the end() or the rend() of the
678  * possible values, function incIn() will perform nothing (this prevents
679  * looping inadvertently several times within the same loop). To unset the
680  * end flag, use functions unsetOverflow(), unsetEnd() or one of the
681  * setFirst() or setLast().
682  *
683  * @param i The set of variables to increment in this Instantiation.
684  */
685  void incIn(const Instantiation& i);
686 
687  /**
688  * @brief Operator decrement for the variables in i.
689  *
690  * Note that, if the Instantiation is related to a MultiDimAdressable, then
691  * the corresponding value in the latter is updated.
692  *
693  * Note also that this operator never throws an exception when it reaches
694  * the end of the possible values of the tuple of variables of the
695  * Instantiation. To know if we reached the end, use function end().
696  * Finally, let us mention that the value of instantiation i is not taken
697  * into account, that is, only the variables belonging to i are taken into
698  * account. The next value of *this is thus computed w.r.t. to the current
699  * value of *this. If we already reached the end() or the rend() of the
700  * possible values, function incIn() will perform nothing (this prevents
701  * looping inadvertently several times within the same loop). To unset the
702  * end flag, use functions unsetOverflow(), unsetEnd() or one of the
703  * setFirst() or setLast().
704  *
705  * @param i The set of variables to decrement in this Instantiation.
706  */
707  void decIn(const Instantiation& i);
708 
709  /**
710  * @brief Operator increment for the variables not in i.
711  *
712  * Note that, if the Instantiation is related to a MultiDimAdressable, then
713  * the corresponding value in the latter is updated.
714  *
715  * Note also that this operator never throws an exception when it reaches
716  * the end of the possible values of the tuple of variables of the
717  * Instantiation. To know if we reached the end, use function end().
718  * Finally, let us mention that the value of instantiation i is not taken
719  * into account, that is, only the variables not belonging to i are taken
720  * into account. The next value of *this is thus computed w.r.t. to the
721  * current value of *this. If we already reached the end() or the rend() of
722  * the possible values, function incerr() will perform nothing (this
723  * prevents looping inadvertently several times within the same loop). To
724  * unset the end flag, use functions unsetOverflow(), unsetEnd() or one of
725  * the setFirst() or setLast().
726  *
727  * @param i The set of variable to not increment in this Instantiation.
728  */
729  void incOut(const Instantiation& i);
730 
731  /**
732  * @brief Operator decrement for the variables not in i.
733  *
734  * Note that, if the Instantiation is related to a MultiDimAdressable, then
735  * the corresponding value in the latter is updated. Note also that this
736  * operator never throws an exception when it reaches the end of the
737  * possible values of the tuple of variables of the Instantiation. To know
738  * if we reached the end, use function end(). Finally, let us mention that
739  * the value of instantiation i is not taken into account, that is, only
740  * the variables not belonging to i are taken into account. The next value
741  * of *this is thus computed w.r.t. to the current value of *this. If we
742  * already reached the end() or the rend() of the possible values, function
743  * incerr() will perform nothing (this prevents looping inadvertently
744  * several times within the same loop). To unset the end flag, use
745  * functions unsetOverflow(), unsetEnd() or one of the setFirst() or
746  * setLast().
747  *
748  * @param i The set of variables to not decrement in this Instantiation.
749  */
750  void decOut(const Instantiation& i);
751 
752  /**
753  * @brief Operator increment for vars which are not v.
754  *
755  * Note that, if the Instantiation is related to a MultiDimAdressable, then
756  * the corresponding value in the latter is updated. Note also that this
757  * operator never throws an exception when it reaches the end of the
758  * possible values of the tuple of variables of the Instantiation. To know
759  * if we reached the end, use function end(). If we already reached the
760  * end() or the rend() of the possible values, function incNotVar() will
761  * perform nothing (this prevents looping inadvertently several times
762  * within the same loop). To unset the end flag, use functions
763  * unsetOverflow(), unsetEnd() or one of the setFirst() or setLast().
764  *
765  * @param v The variable not to increment in this Instantiation.
766  */
767  void incNotVar(const DiscreteVariable& v);
768 
769  /**
770  * @brief Operator decrement for vars which are not v.
771  *
772  * Note that, if the Instantiation is related to a MultiDimAdressable,
773  * then the corresponding value in the latter is updated.
774  *
775  * Note also that this operator never throws an exception when it reaches
776  * the end of the possible values of the tuple of variables of the
777  * Instantiation. To know if we reached the end, use function end(). If we
778  * already reached the end() or the rend() of the possible values, function
779  * incNotVar() will perform nothing (this prevents looping inadvertently
780  * several times within the same loop). To unset the end flag, use
781  * functions unsetOverflow(), unsetEnd() or one of the setFirst() or
782  * setLast().
783  *
784  * @param v The varaible not to decrement in this Instantiation.
785  */
786  void decNotVar(const DiscreteVariable& v);
787 
788  /**
789  * @brief Operator increment for variable v only.
790  *
791  * This function increment only variable v. Trying to increment the last
792  * possible value results in an overflow (no exception is thrown in this
793  * case). If we already reached the end() or the rend() of the possible
794  * values, function incVar() will perform nothing (this prevents looping
795  * inadvertently several times within the same loop). To unset the end
796  * flag, use functions unsetOverflow(), unsetEnd() or one of the setFirst()
797  * or setLast().
798  *
799  * @param v The variable to increment in this Instantiation.
800  * @throw NotFound Raised if variable v does not belong to the
801  * Instantiation.
802  */
803 
804  void incVar(const DiscreteVariable& v);
805 
806  /**
807  * @brief Operator decrement for variable v only.
808  *
809  * This function decrement only variable v. Trying to decrement the last
810  * possible value results in an overflow (no exception is thrown in this
811  * case). If we already reached the end() or the rend() of the possible
812  * values, function incVar() will perform nothing (this prevents looping
813  * inadvertently several times within the same loop). To unset the end
814  * flag, use functions unsetOverflow(), unsetEnd() or one of the setFirst()
815  * or setLast().
816  *
817  * @param v The variable to decrement in this Instantiation.
818  * @throw NotFound Raised if variable v does not belong to the
819  * Instantiation.
820  */
821 
822  void decVar(const DiscreteVariable& v);
823 
824  /// @}
825  // =========================================================================
826  /// @name Initialization methods
827  // =========================================================================
828  /// @{
829 
830  /**
831  * @brief Assign the first values to the tuple of the Instantiation.
832  *
833  * Note that, if the Instantiation is related to a MultiDimAdressable, then
834  * the corresponding value in the latter is updated. This function
835  * naturally unsets the overFlow flag.
836  */
837  void setFirst();
838 
839  /**
840  * @brief Assign the last values in the Instantiation.
841  *
842  * Note that, if the Instantiation is related to a MultiDimAdressable, then
843  * the corresponding value in the latter is updated. This function
844  * naturally unsets the overFlow flag.
845  */
846  void setLast();
847 
848  /**
849  * @brief Assign the first values in the Instantiation for the variables in
850  * i.
851  *
852  * Note that, if the Instantiation is related to a MultiDimAdressable, then
853  * the corresponding value in the latter is updated. Note also that the
854  * value of instantiation i is not taken into account, that is, only the
855  * variables not belonging to i are taken into account. This function
856  * naturally unsets the overFlow flag.
857  *
858  * @param i The variables to which their first value is assigned in this
859  * Instantiation.
860  */
861  void setFirstIn(const Instantiation& i);
862 
863  /**
864  * @brief Assign the last values in the Instantiation for the variables in
865  * i.
866  *
867  * Where Di is the domain size of variable i in the Instantiation) for the
868  * i vars.
869  *
870  * Note that, if the Instantiation is related to a MultiDimAdressable, then
871  * the corresponding value in the latter is updated. Note also that the
872  * value of instantiation i is not taken into account, that is, only the
873  * variables belonging to i are taken into account. This function naturally
874  * unsets the overFlow flag.
875  *
876  * @param i The variables to which their last value is assigned in this
877  * Instantiation.
878  */
879  void setLastIn(const Instantiation& i);
880 
881  /**
882  * @brief Assign the first values in the Instantiation for the variables
883  * not in i.
884  *
885  * Note that, if the Instantiation is related to a qum::MultiDimAdressable,
886  * then the corresponding value in the latter is updated. Note also that
887  * the value of instantiation i is not taken into account, that is, only
888  * the variables not belonging to i are taken into account. This function
889  * naturally unsets the overFlow flag.
890  *
891  * @param i The variable that will not be set to their first value in this
892  * Instantiation.
893  */
894 
895  void setFirstOut(const Instantiation& i);
896 
897  /**
898  * @brief Assign the last values in the Instantiation for the variables not
899  * in i.
900  *
901  * Note that, if the Instantiation is related to a MultiDimAdressable, then
902  * the corresponding value in the latter is updated. Note also that the
903  * value of instantiation i is not taken into account, that is, only the
904  * variables not belonging to i are taken into account. This function
905  * naturally unsets the overFlow flag.
906  *
907  * @param i The variables that will not be set to their last value in this
908  * Instantiation.
909  */
910  void setLastOut(const Instantiation& i);
911 
912  /**
913  * @brief Assign the first values to variables different of v.
914  *
915  * Note that, if the Instantiation is related to a MultiDimAdressable, then
916  * the corresponding value in the latter is updated. This function
917  * naturally unsets the overFlow flag.
918  *
919  * @param v Tha variable that will not be set to its first value in this
920  * Instantiation.
921  */
922 
923  void setFirstNotVar(const DiscreteVariable& v);
924 
925  /**
926  * @brief Assign the last values to variables different of v.
927  *
928  * Note that, if the Instantiation is related to a MultiDimAdressable, then
929  * the corresponding value in the latter is updated. This function
930  * naturally unsets the overFlow flag.
931  *
932  * @param v The variable that will not be set to its last value in this
933  * Instantiation.
934  */
935  void setLastNotVar(const DiscreteVariable& v);
936 
937  /**
938  * @brief Assign the first value in the Instantiation for var v.
939  *
940  * Note that, if the Instantiation is related to a MultiDimAdressable, then
941  * the corresponding value in the latter is updated. This function
942  * naturally unsets the overFlow flag.
943  *
944  * @param v The variable that will be set to its first value in this
945  * Instantiation.
946  */
947  void setFirstVar(const DiscreteVariable& v);
948 
949  /**
950  * @brief Assign the last value in the Instantiation for var v.
951  *
952  * Note that, if the Instantiation is related to a MultiDimAdressable, then
953  * the corresponding value in the latter is updated. This function
954  * naturally unsets the overFlow flag.
955  *
956  * @param v The variable that will be set to its last value in this
957  * Instantiation.
958  */
959  void setLastVar(const DiscreteVariable& v);
960 
961  /// @}
962  // =========================================================================
963  /// @name Notification methods
964  // =========================================================================
965  /// @{
966 
967  /**
968  * @brief Tries to register the Instantiation to a MultiDimAdressable.
969  *
970  * The function will actually register the Instantiation if and only if it
971  * has precisely the same variables as the MultiDimAdressable (by
972  * precisely, we mean a physical equality, that is, the variables are at
973  * the same places in memory).
974  *
975  * @param aMD The multidimensional array which will be the master of *this
976  * @returns Returns true if and only if the Instantiation has been
977  * associated successfully to aMD.
978  *
979  * @throw OperationNotAllowed Raised if this instantiation has already a
980  * master.
981  */
982  bool actAsSlave(MultiDimAdressable& aMD);
983 
984  /**
985  * @brief Deassociate the master MultiDimAdressable, if any.
986  * @returns Returns true if and only if the Instantiation has been
987  * unregistered.
988  */
989  bool forgetMaster();
990 
991  /**
992  * @brief Indicates whether the Instantiation has a master.
993  * @return Returns true if the Instantiation has a master.
994  */
995  bool isSlave() const;
996 
997  /**
998  * @brief Indicates whether m is the master of this instantiation.
999  * @return Returns true if m is the master of this instantiation.
1000  */
1001  bool isMaster(const MultiDimAdressable* m) const;
1002 
1003  /**
1004  * @brief Indicates whether m is the master of this instantiation.
1005  * @return Returns true if m is the master of this instantiation.
1006  */
1007  bool isMaster(const MultiDimAdressable& m) const;
1008 
1009  /**
1010  * @brief Force the variables sequence to be the same as the master one.
1011  *
1012  * The master should be a friend to notify dimensions changes
1013  * friend class MultiDimAdressable.
1014  *
1015  * @param m The master of this instantiation.
1016  * @throw OperationNotAllowed Raised if m is not the master of
1017  * instantiation.
1018  */
1019  void synchronizeWithMaster(const MultiDimAdressable* m);
1020 
1021  /**
1022  * @brief Call Instantiation::add__(const DiscreteVariable&) by master.
1023  *
1024  * @param m The master of this instantiation.
1025  * @param v The varaible to add.
1026  * @throw OperationNotAllowed Raised if m is not hte master of this
1027  * instantiation.
1028  */
1029  void addWithMaster(const MultiDimAdressable* m, const DiscreteVariable& v);
1030 
1031  /**
1032  * @brief Call Instantiation::erase__(const DiscreteVariable&) by master.
1033  *
1034  * @param m The master of this instantiation.
1035  * @param v The variable to remove.
1036  * @throw OperationNotAllowed Raised if m is not the master of this
1037  * instantiation.
1038  */
1039  void eraseWithMaster(const MultiDimAdressable* m, const DiscreteVariable& v);
1040 
1041  /// @}
1042  // =========================================================================
1043  /// @name Operators
1044  // =========================================================================
1045  /// @{
1046 
1047  /**
1048  * @brief operator==
1049  */
1050  bool operator==(const Instantiation& other) const;
1051 
1052  /**
1053  * @brief Alias of Instantiation::inc().
1054  * @return Returns this Instantiation.
1055  */
1056  Instantiation& operator++();
1057 
1058  /**
1059  * @brief Alias of Instantiation::dec().
1060  * @return Returns this Instantiation.
1061  */
1062  Instantiation& operator--();
1063 
1064  /**
1065  * @brief Calls depl times Instantiation::inc().
1066  * @return Returns this Instantiation.
1067  */
1068  Instantiation& operator+=(Size depl);
1069 
1070  /**
1071  * @brief Calls depl times Instantiation::dec().
1072  * @return Returns this Instantiation.
1073  */
1074  Instantiation& operator-=(Size depl);
1075 
1076  /// @}
1077  // =========================================================================
1078  /// @name Various methods
1079  // =========================================================================
1080  /// @{
1081 
1082  /**
1083  * @brief Returns the hamming distance of this instantiation.
1084  * @return Returns the hamming distance of this instantiation.
1085  */
1086  Idx hamming() const;
1087 
1088  /**
1089  * @brief Give a string version of instantiation.
1090  * @return Returns a string version of instantiation.
1091  */
1092  std::string toString() const;
1093 
1094  /**
1095  * @brief Reorder vars of this instantiation giving the order in v.
1096  *
1097  * In the new order variables common to v and *this are placed first, then
1098  * variables only in *this.
1099  *
1100  * The variables only in v are ignored.
1101  *
1102  * @param v The new order of variables for this Instantiation.
1103  * @throw OperationNotAllowed if slave instantiation
1104  */
1105  void reorder(const Sequence< const DiscreteVariable* >& v);
1106 
1107  /**
1108  * @brief Calls reorder(const Sequence<const DiscreteVariable*>&) with
1109  * i.variablesSequence()
1110  * @param i The sequence of variables with which to reorder this
1111  * Instantiation.
1112  */
1113  void reorder(const Instantiation& i);
1114 
1115  /// @}
1116 
1117  protected:
1118  /**
1119  * @brief Replace x by y.
1120  * @param x The variable to replace.
1121  * @param y The variable replacing x.
1122  */
1123  virtual void replace_(const DiscreteVariable* x,
1124  const DiscreteVariable* y) final;
1125 
1126  private:
1127  /// The master, if any, contains precisely the set of variables to be
1128  /// instantiated.
1129  MultiDimAdressable* master__;
1130 
1131  /// The tuple of variables to be instantiated.
1132  Sequence< const DiscreteVariable* > vars__;
1133 
1134  /// The current instantiation: the value of the tuple.
1135  std::vector< Idx > vals__;
1136 
1137  /// Indicates whether the current value of the tuple is valid when we loop
1138  /// sufficiently over values of the tuple, we may have browsed all the
1139  /// possible values and we have to know in a way or another that the tuple
1140  /// contains no more value. This is precisely the meaning of Boolean
1141  /// overflow
1142  bool overflow__;
1143 
1144  /**
1145  * @brief Swap two variables in the Instantiation.
1146  * @param i The first variable.
1147  * @param j The second variable.
1148  */
1149  void swap__(Idx i, Idx j);
1150 
1151  /**
1152  * @brief Modifies internally the value of a given variable of the sequence.
1153  *
1154  * In addition to modifying the value of the variable, the Instantiation
1155  * informs its master MultiDimAdressable of the modification.
1156  *
1157  * @param varPos The variable to change.
1158  * @param newVal The variable new value.
1159  */
1160  void chgVal__(Idx varPos, Idx newVal);
1161 
1162  /**
1163  * @brief Adds a new var to the sequence of vars.
1164  *
1165  * If variable v already belongs to the Instantiation tuple of variables,
1166  * then nothing is done. In particular, no exception is thrown in this
1167  * case.
1168  *
1169  * @warning note that this function does not deassociate the Instantiation
1170  * from its master MultiDimAdressable, if any. To do so, use function add
1171  * instead.
1172  *
1173  * @warning this function does not notify the master MultiDimAdressable,
1174  * if any. Use in addition function chgVal or chgVal__ if need be.
1175  *
1176  * @warning variable v is known to the Instantiation only by a pointer to
1177  * it. As a result, this is not a copy of v that is used by Instantiation
1178  * but rather v itself. As such, v should never be deleted from memory
1179  * until the Instantiation is removed.
1180  *
1181  * @param v The new var.
1182  * @throw DuplicateElement Raised if v is already in this Instantiation.
1183  */
1184  void add__(const DiscreteVariable& v);
1185 
1186  /**
1187  * @brief Removes a variable from the sequence of vars.
1188  *
1189  * If variable v does not belong to the Instantiation tuple of variables,
1190  * then nothing is done. In particular, no exception is thrown in this
1191  * case.
1192  *
1193  * @warning this function does not notify the master MultiDimAdressable,
1194  * if any.
1195  *
1196  * @warning note that this function does not deassociate the Instantiation
1197  * from its master MultiDimAdressable, if any. To do so, use function
1198  * removeDim instead.
1199  *
1200  * @param v The variable to be erased from the tuple.
1201  */
1202  void erase__(const DiscreteVariable& v);
1203 
1204  /**
1205  * This function is called by the master (if any) when changes arise in its
1206  * vars list.
1207  *
1208  * @warning No implementation of this method?
1209  *
1210  * @param v the new vars list
1211  */
1212  void notifiedDimChanged__(const Sequence< const DiscreteVariable* >& v);
1213 
1214  /**
1215  * @brief Initialize this Instantiation.
1216  * @param master This Instantiation's master.
1217  */
1218  void init__(MultiDimAdressable* master);
1219 
1220  /**
1221  * @brief Reorder vars of this instantiation giving the order in v.
1222  *
1223  * In the new order variables common to v and *this are placed first, then
1224  * variables only in *this.
1225  *
1226  * The variables only in v are ignored.
1227  *
1228  * @param v The new order of variables in this Instantiation.
1229  */
1230  void reorder__(const Sequence< const DiscreteVariable* >& v);
1231 
1232  void masterChangeNotification__(Idx varPos, Idx newVal, Idx oldVal) const;
1233  void masterFirstNotification__() const;
1234  void masterIncNotification__() const;
1235  void masterLastNotification__() const;
1236  void masterDecNotification__() const;
1237  };
1238 
1239  /**
1240  * @brief Print information of the instantiation in the stream.
1241  */
1242  std::ostream& operator<<(std::ostream&, const Instantiation&);
1243 
1244  /**
1245  * @brief Hash function for gum::Instantiation.
1246  * @ingroup hashfunctions_group
1247  */
1248  template <>
1249  // class HashFunc< Instantiation > : public HashFuncBase< Instantiation > {
1250  class HashFunc< Instantiation >: public HashFuncBase< Instantiation > {
1251  public:
1252  /**
1253  * @brief Returns the value of a key as a Size.
1254  * @param key The value to return as a Size.
1255  * @return Returns the value of a key as a Size.
1256  */
1257  static Size castToSize(const Instantiation& key);
1258 
1259  /**
1260  * @brief Computes the hashed value of a key.
1261  * @param key The key to compute the hashed value.
1262  * @return Returns the hashed value of a key.
1263  */
1264  virtual Size operator()(const Instantiation& key) const override final;
1265  };
1266 } /* namespace gum */
1267 
1268 #ifndef GUM_NO_INLINE
1269 # include <agrum/tools/multidim/instantiation_inl.h>
1270 #endif /* GUM_NO_INLINE */
1271 
1272 #endif /* GUM_INSTANTIATION_H */