aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
instantiation.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 /**
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(const HashTable< const DiscreteVariable*, const DiscreteVariable* >& map,
487  const Instantiation& external);
488 
489  /**
490  * Indicates whether a given variable belongs to the Instantiation.
491  *
492  * @param v The variable for which the test is made.
493  * @return Returns true if v is in the Instantiation.
494  */
495  bool contains(const DiscreteVariable& v) const final;
496  bool contains(const std::string& name) const;
497 
498  /**
499  * Indicates whether a given variable belongs to the Instantiation.
500  *
501  * @param v A pointer on the variable for which the test is made.
502  * @return Returns true if *v is in the Instantiation.
503  */
504  bool contains(const DiscreteVariable* v) const;
505 
506  /**
507  * @brief Returns the sequence of DiscreteVariable of this instantiation.
508  * @return Returns the sequence of DiscreteVariable of this instantiation.
509  */
510  const Sequence< const DiscreteVariable* >& variablesSequence() const final;
511 
512  /**
513  * @brief Returns true if the instantiation is empty.
514  * @return Returns true if the instantiation is empty.
515  */
516  virtual bool empty() const final;
517 
518  /// @}
519  // =========================================================================
520  /// @name Overflow management methods.
521  // =========================================================================
522  /// @{
523 
524  /**
525  * @brief Indicates whether the current value of the tuple is correct or
526  * not.
527  *
528  * The function inOverflow() is used to flag overflowed operation (for
529  * instance, ++ on the last value or -- on the first value will produce an
530  * incorrect value of the tuple. Hence inOverflow() is used as an
531  * end()/rend() function for loops on Instantiation.
532  *
533  * @code
534  * for(Instantiation i.setFirst(); !i.inOverflow(); ++i) {
535  * // code...
536  * }
537  * @endcode
538  */
539  bool inOverflow() const;
540 
541  /**
542  * @brief Removes the flag overflow. See full documentation for details.
543  * (Recommended).
544  *
545  * When we use multiple inner loops w.r.t. a given Instantiation, it may
546  * happen that one inner loop reaches the end() of the Instantiation while
547  * the outer loops do not have reached it. This means that the inner loop
548  * has toggled the overflow flag. To enable the other loops to go on, we
549  * must unset this flag using function unsetOverflow(). For instance,
550  * assume that Prob represents probability P(b|a,c), then normalizing this
551  * proba can be performed using the following code:
552  *
553  * @code
554  * // assume the probability has been defined somewhere:
555  * MultiDimArray<double> Prob;
556  *
557  * // create 2 instantiations for the 2 necessary loops
558  * Instantiation i(Prob), j;
559  * j << a << c;
560  * double delta;
561  *
562  * // outer loop: loop over the values of b
563  * for(i.setFirstIn(j); !i.end(); i.incIn(j))
564  * {
565  * delta = 0.0;
566  * // inner loop: loop over the values of a and c
567  * for(i.setFirstOut(j); !i.end(); i.incerr(j))
568  * delta += dd[i];
569  * for(i.setFirstOut(j); !i.end(); i.incerr(j))
570  * dd[i] /= delta;
571  * // indicate that the end() reached after looping over a and c does not
572  * // correspond to an end() for the loop w.r.t. b
573  * i.unsetOverflow();
574  * }
575  * @endcode
576  */
577 
578  void unsetOverflow();
579 
580  /**
581  * @brief Alias for unsetOverflow().
582  * @see unsetOverflow().
583  */
584  void unsetEnd();
585 
586  /**
587  * @brief Returns true if the Instantiation reached the end.
588  *
589  * Function end() should be used as in:
590  * @code
591  * for(Instantiation i.setFirst();! i.end(); ++i) {
592  * // code
593  * }
594  * @endcode
595  *
596  * @return Returns true if the Instantiation reached the end.
597  */
598  bool end() const;
599 
600  /**
601  * @brief Returns true if the Instantiation reached the rend.
602  *
603  * Function end() should be used as in:
604  * @code
605  * for(Instantiation i.setLast();! i.rend(); --i) {
606  * // code
607  * }
608  * @endcode
609  *
610  * @return Returns true if the Instantiation reached the rend.
611  */
612  bool rend() const;
613 
614  /// @}
615  // =========================================================================
616  /// @name Incrementation and decrementation methods
617  // =========================================================================
618  /// @{
619 
620  /**
621  * @brief Operator increment.
622  *
623  * Note that this operator never throws an exception when it reaches the
624  * end of the possible values of the tuple of variables of the
625  * Instantiation. To know if we reached the end, use function end(). If
626  * the Instantiation is related to a MultiDimAdressable, then the
627  * corresponding value in the latter is updated. If we already reached the
628  * end() or the rend() of the possible values, function inc() will perform
629  * nothing (this prevents looping inadvertently several times within the
630  * same loop). To unset the end flag, use functions unsetOverflow(),
631  * unsetEnd() or one of the setFirst() or setLast().
632  *
633  * Usage example:
634  * @code
635  * for(Instantiation i.setFirst();! i.end(); i.inc()) {
636  * // code
637  * }
638  * @endcode
639  */
640  void inc();
641 
642  /**
643  * @brief Operator decrement
644  *
645  * Note that this operator never throws an exception when it reaches the
646  * end of the possible values of the tuple of variables of the
647  * Instantiation. To know if we reached the end, use function end(). If
648  * the Instantiation is related to a MultiDimAdressable, then the
649  * corresponding value in the latter is updated. If we already reached the
650  * end() or the rend() of the possible values, function inc() will perform
651  * nothing (this prevents looping inadvertently several times within the
652  * same loop). To unset the end flag, use functions unsetOverflow(),
653  * unsetEnd() or one of the setFirst() or setLast().
654  *
655  * Usage example:
656  * @code
657  * for(Instantiation i.setLast();! i.rend(); i.dec()) {
658  * // code
659  * }
660  * @endcode
661  */
662  void dec();
663 
664  /**
665  * @brief Operator increment for the variables in i.
666  *
667  * Note that, if the Instantiation is related to a MultiDimAdressable, then
668  * the corresponding value in the latter is updated.
669  *
670  * Note also that this operator never throws an exception when it reaches
671  * the end of the possible values of the tuple of variables of the
672  * Instantiation. To know if we reached the end, use function end().
673  * Finally, let us mention that the value of instantiation i is not taken
674  * into account, that is, only the variables belonging to i are taken into
675  * account. The next value of *this is thus computed w.r.t. to the current
676  * value of *this. If we already reached the end() or the rend() of the
677  * possible values, function incIn() will perform nothing (this prevents
678  * looping inadvertently several times within the same loop). To unset the
679  * end flag, use functions unsetOverflow(), unsetEnd() or one of the
680  * setFirst() or setLast().
681  *
682  * @param i The set of variables to increment in this Instantiation.
683  */
684  void incIn(const Instantiation& i);
685 
686  /**
687  * @brief Operator decrement for the variables in i.
688  *
689  * Note that, if the Instantiation is related to a MultiDimAdressable, then
690  * the corresponding value in the latter is updated.
691  *
692  * Note also that this operator never throws an exception when it reaches
693  * the end of the possible values of the tuple of variables of the
694  * Instantiation. To know if we reached the end, use function end().
695  * Finally, let us mention that the value of instantiation i is not taken
696  * into account, that is, only the variables belonging to i are taken into
697  * account. The next value of *this is thus computed w.r.t. to the current
698  * value of *this. If we already reached the end() or the rend() of the
699  * possible values, function incIn() will perform nothing (this prevents
700  * looping inadvertently several times within the same loop). To unset the
701  * end flag, use functions unsetOverflow(), unsetEnd() or one of the
702  * setFirst() or setLast().
703  *
704  * @param i The set of variables to decrement in this Instantiation.
705  */
706  void decIn(const Instantiation& i);
707 
708  /**
709  * @brief Operator increment for the variables not in i.
710  *
711  * Note that, if the Instantiation is related to a MultiDimAdressable, then
712  * the corresponding value in the latter is updated.
713  *
714  * Note also that this operator never throws an exception when it reaches
715  * the end of the possible values of the tuple of variables of the
716  * Instantiation. To know if we reached the end, use function end().
717  * Finally, let us mention that the value of instantiation i is not taken
718  * into account, that is, only the variables not belonging to i are taken
719  * into account. The next value of *this is thus computed w.r.t. to the
720  * current value of *this. If we already reached the end() or the rend() of
721  * the possible values, function incerr() will perform nothing (this
722  * prevents looping inadvertently several times within the same loop). To
723  * unset the end flag, use functions unsetOverflow(), unsetEnd() or one of
724  * the setFirst() or setLast().
725  *
726  * @param i The set of variable to not increment in this Instantiation.
727  */
728  void incOut(const Instantiation& i);
729 
730  /**
731  * @brief Operator decrement for the variables not in i.
732  *
733  * Note that, if the Instantiation is related to a MultiDimAdressable, then
734  * the corresponding value in the latter is updated. Note also that this
735  * operator never throws an exception when it reaches the end of the
736  * possible values of the tuple of variables of the Instantiation. To know
737  * if we reached the end, use function end(). Finally, let us mention that
738  * the value of instantiation i is not taken into account, that is, only
739  * the variables not belonging to i are taken into account. The next value
740  * of *this is thus computed w.r.t. to the current value of *this. If we
741  * already reached the end() or the rend() of the possible values, function
742  * incerr() will perform nothing (this prevents looping inadvertently
743  * several times within the same loop). To unset the end flag, use
744  * functions unsetOverflow(), unsetEnd() or one of the setFirst() or
745  * setLast().
746  *
747  * @param i The set of variables to not decrement in this Instantiation.
748  */
749  void decOut(const Instantiation& i);
750 
751  /**
752  * @brief Operator increment for vars which are not v.
753  *
754  * Note that, if the Instantiation is related to a MultiDimAdressable, then
755  * the corresponding value in the latter is updated. Note also that this
756  * operator never throws an exception when it reaches the end of the
757  * possible values of the tuple of variables of the Instantiation. To know
758  * if we reached the end, use function end(). If we already reached the
759  * end() or the rend() of the possible values, function incNotVar() will
760  * perform nothing (this prevents looping inadvertently several times
761  * within the same loop). To unset the end flag, use functions
762  * unsetOverflow(), unsetEnd() or one of the setFirst() or setLast().
763  *
764  * @param v The variable not to increment in this Instantiation.
765  */
766  void incNotVar(const DiscreteVariable& v);
767 
768  /**
769  * @brief Operator decrement for vars which are not v.
770  *
771  * Note that, if the Instantiation is related to a MultiDimAdressable,
772  * then the corresponding value in the latter is updated.
773  *
774  * Note also that this operator never throws an exception when it reaches
775  * the end of the possible values of the tuple of variables of the
776  * Instantiation. To know if we reached the end, use function end(). If we
777  * already reached the end() or the rend() of the possible values, function
778  * incNotVar() will perform nothing (this prevents looping inadvertently
779  * several times within the same loop). To unset the end flag, use
780  * functions unsetOverflow(), unsetEnd() or one of the setFirst() or
781  * setLast().
782  *
783  * @param v The varaible not to decrement in this Instantiation.
784  */
785  void decNotVar(const DiscreteVariable& v);
786 
787  /**
788  * @brief Operator increment for variable v only.
789  *
790  * This function increment only variable v. Trying to increment the last
791  * possible value results in an overflow (no exception is thrown in this
792  * case). If we already reached the end() or the rend() of the possible
793  * values, function incVar() will perform nothing (this prevents looping
794  * inadvertently several times within the same loop). To unset the end
795  * flag, use functions unsetOverflow(), unsetEnd() or one of the setFirst()
796  * or setLast().
797  *
798  * @param v The variable to increment in this Instantiation.
799  * @throw NotFound Raised if variable v does not belong to the
800  * Instantiation.
801  */
802 
803  void incVar(const DiscreteVariable& v);
804 
805  /**
806  * @brief Operator decrement for variable v only.
807  *
808  * This function decrement only variable v. Trying to decrement the last
809  * possible value results in an overflow (no exception is thrown in this
810  * case). If we already reached the end() or the rend() of the possible
811  * values, function incVar() will perform nothing (this prevents looping
812  * inadvertently several times within the same loop). To unset the end
813  * flag, use functions unsetOverflow(), unsetEnd() or one of the setFirst()
814  * or setLast().
815  *
816  * @param v The variable to decrement in this Instantiation.
817  * @throw NotFound Raised if variable v does not belong to the
818  * Instantiation.
819  */
820 
821  void decVar(const DiscreteVariable& v);
822 
823  /// @}
824  // =========================================================================
825  /// @name Initialization methods
826  // =========================================================================
827  /// @{
828 
829  /**
830  * @brief Assign the first values to the tuple of the Instantiation.
831  *
832  * Note that, if the Instantiation is related to a MultiDimAdressable, then
833  * the corresponding value in the latter is updated. This function
834  * naturally unsets the overFlow flag.
835  */
836  void setFirst();
837 
838  /**
839  * @brief Assign the last values in the Instantiation.
840  *
841  * Note that, if the Instantiation is related to a MultiDimAdressable, then
842  * the corresponding value in the latter is updated. This function
843  * naturally unsets the overFlow flag.
844  */
845  void setLast();
846 
847  /**
848  * @brief Assign the first values in the Instantiation for the variables in
849  * i.
850  *
851  * Note that, if the Instantiation is related to a MultiDimAdressable, then
852  * the corresponding value in the latter is updated. Note also that the
853  * value of instantiation i is not taken into account, that is, only the
854  * variables not belonging to i are taken into account. This function
855  * naturally unsets the overFlow flag.
856  *
857  * @param i The variables to which their first value is assigned in this
858  * Instantiation.
859  */
860  void setFirstIn(const Instantiation& i);
861 
862  /**
863  * @brief Assign the last values in the Instantiation for the variables in
864  * i.
865  *
866  * Where Di is the domain size of variable i in the Instantiation) for the
867  * i vars.
868  *
869  * Note that, if the Instantiation is related to a MultiDimAdressable, then
870  * the corresponding value in the latter is updated. Note also that the
871  * value of instantiation i is not taken into account, that is, only the
872  * variables belonging to i are taken into account. This function naturally
873  * unsets the overFlow flag.
874  *
875  * @param i The variables to which their last value is assigned in this
876  * Instantiation.
877  */
878  void setLastIn(const Instantiation& i);
879 
880  /**
881  * @brief Assign the first values in the Instantiation for the variables
882  * not in i.
883  *
884  * Note that, if the Instantiation is related to a qum::MultiDimAdressable,
885  * then the corresponding value in the latter is updated. Note also that
886  * the value of instantiation i is not taken into account, that is, only
887  * the variables not belonging to i are taken into account. This function
888  * naturally unsets the overFlow flag.
889  *
890  * @param i The variable that will not be set to their first value in this
891  * Instantiation.
892  */
893 
894  void setFirstOut(const Instantiation& i);
895 
896  /**
897  * @brief Assign the last values in the Instantiation for the variables not
898  * in i.
899  *
900  * Note that, if the Instantiation is related to a MultiDimAdressable, then
901  * the corresponding value in the latter is updated. Note also that the
902  * value of instantiation i is not taken into account, that is, only the
903  * variables not belonging to i are taken into account. This function
904  * naturally unsets the overFlow flag.
905  *
906  * @param i The variables that will not be set to their last value in this
907  * Instantiation.
908  */
909  void setLastOut(const Instantiation& i);
910 
911  /**
912  * @brief Assign the first values to variables different of v.
913  *
914  * Note that, if the Instantiation is related to a MultiDimAdressable, then
915  * the corresponding value in the latter is updated. This function
916  * naturally unsets the overFlow flag.
917  *
918  * @param v Tha variable that will not be set to its first value in this
919  * Instantiation.
920  */
921 
922  void setFirstNotVar(const DiscreteVariable& v);
923 
924  /**
925  * @brief Assign the last values to variables different of v.
926  *
927  * Note that, if the Instantiation is related to a MultiDimAdressable, then
928  * the corresponding value in the latter is updated. This function
929  * naturally unsets the overFlow flag.
930  *
931  * @param v The variable that will not be set to its last value in this
932  * Instantiation.
933  */
934  void setLastNotVar(const DiscreteVariable& v);
935 
936  /**
937  * @brief Assign the first value in the Instantiation for var v.
938  *
939  * Note that, if the Instantiation is related to a MultiDimAdressable, then
940  * the corresponding value in the latter is updated. This function
941  * naturally unsets the overFlow flag.
942  *
943  * @param v The variable that will be set to its first value in this
944  * Instantiation.
945  */
946  void setFirstVar(const DiscreteVariable& v);
947 
948  /**
949  * @brief Assign the last value in the Instantiation for var v.
950  *
951  * Note that, if the Instantiation is related to a MultiDimAdressable, then
952  * the corresponding value in the latter is updated. This function
953  * naturally unsets the overFlow flag.
954  *
955  * @param v The variable that will be set to its last value in this
956  * Instantiation.
957  */
958  void setLastVar(const DiscreteVariable& v);
959 
960  /// @}
961  // =========================================================================
962  /// @name Notification methods
963  // =========================================================================
964  /// @{
965 
966  /**
967  * @brief Tries to register the Instantiation to a MultiDimAdressable.
968  *
969  * The function will actually register the Instantiation if and only if it
970  * has precisely the same variables as the MultiDimAdressable (by
971  * precisely, we mean a physical equality, that is, the variables are at
972  * the same places in memory).
973  *
974  * @param aMD The multidimensional array which will be the master of *this
975  * @returns Returns true if and only if the Instantiation has been
976  * associated successfully to aMD.
977  *
978  * @throw OperationNotAllowed Raised if this instantiation has already a
979  * master.
980  */
981  bool actAsSlave(MultiDimAdressable& aMD);
982 
983  /**
984  * @brief Deassociate the master MultiDimAdressable, if any.
985  * @returns Returns true if and only if the Instantiation has been
986  * unregistered.
987  */
988  bool forgetMaster();
989 
990  /**
991  * @brief Indicates whether the Instantiation has a master.
992  * @return Returns true if the Instantiation has a master.
993  */
994  bool isSlave() const;
995 
996  /**
997  * @brief Indicates whether m is the master of this instantiation.
998  * @return Returns true if m is the master of this instantiation.
999  */
1000  bool isMaster(const MultiDimAdressable* m) const;
1001 
1002  /**
1003  * @brief Indicates whether m is the master of this instantiation.
1004  * @return Returns true if m is the master of this instantiation.
1005  */
1006  bool isMaster(const MultiDimAdressable& m) const;
1007 
1008  /**
1009  * @brief Force the variables sequence to be the same as the master one.
1010  *
1011  * The master should be a friend to notify dimensions changes
1012  * friend class MultiDimAdressable.
1013  *
1014  * @param m The master of this instantiation.
1015  * @throw OperationNotAllowed Raised if m is not the master of
1016  * instantiation.
1017  */
1018  void synchronizeWithMaster(const MultiDimAdressable* m);
1019 
1020  /**
1021  * @brief Call Instantiation:: _add_(const DiscreteVariable&) by master.
1022  *
1023  * @param m The master of this instantiation.
1024  * @param v The varaible to add.
1025  * @throw OperationNotAllowed Raised if m is not hte master of this
1026  * instantiation.
1027  */
1028  void addWithMaster(const MultiDimAdressable* m, const DiscreteVariable& v);
1029 
1030  /**
1031  * @brief Call Instantiation:: _erase_(const DiscreteVariable&) by master.
1032  *
1033  * @param m The master of this instantiation.
1034  * @param v The variable to remove.
1035  * @throw OperationNotAllowed Raised if m is not the master of this
1036  * instantiation.
1037  */
1038  void eraseWithMaster(const MultiDimAdressable* m, const DiscreteVariable& v);
1039 
1040  /// @}
1041  // =========================================================================
1042  /// @name Operators
1043  // =========================================================================
1044  /// @{
1045 
1046  /**
1047  * @brief operator==
1048  */
1049  bool operator==(const Instantiation& other) const;
1050 
1051  /**
1052  * @brief Alias of Instantiation::inc().
1053  * @return Returns this Instantiation.
1054  */
1055  Instantiation& operator++();
1056 
1057  /**
1058  * @brief Alias of Instantiation::dec().
1059  * @return Returns this Instantiation.
1060  */
1061  Instantiation& operator--();
1062 
1063  /**
1064  * @brief Calls depl times Instantiation::inc().
1065  * @return Returns this Instantiation.
1066  */
1067  Instantiation& operator+=(Size depl);
1068 
1069  /**
1070  * @brief Calls depl times Instantiation::dec().
1071  * @return Returns this Instantiation.
1072  */
1073  Instantiation& operator-=(Size depl);
1074 
1075  /// @}
1076  // =========================================================================
1077  /// @name Various methods
1078  // =========================================================================
1079  /// @{
1080 
1081  /**
1082  * @brief Returns the hamming distance of this instantiation.
1083  * @return Returns the hamming distance of this instantiation.
1084  */
1085  Idx hamming() const;
1086 
1087  /**
1088  * @brief Give a string version of instantiation.
1089  * @return Returns a string version of instantiation.
1090  */
1091  std::string toString() const;
1092 
1093  /**
1094  * @brief Reorder vars of this instantiation giving the order in v.
1095  *
1096  * In the new order variables common to v and *this are placed first, then
1097  * variables only in *this.
1098  *
1099  * The variables only in v are ignored.
1100  *
1101  * @param v The new order of variables for this Instantiation.
1102  * @throw OperationNotAllowed if slave instantiation
1103  */
1104  void reorder(const Sequence< const DiscreteVariable* >& v);
1105 
1106  /**
1107  * @brief Calls reorder(const Sequence<const DiscreteVariable*>&) with
1108  * i.variablesSequence()
1109  * @param i The sequence of variables with which to reorder this
1110  * Instantiation.
1111  */
1112  void reorder(const Instantiation& i);
1113 
1114  /// @}
1115 
1116  protected:
1117  /**
1118  * @brief Replace x by y.
1119  * @param x The variable to replace.
1120  * @param y The variable replacing x.
1121  */
1122  virtual void replace_(const DiscreteVariable* x, const DiscreteVariable* y) final;
1123 
1124  private:
1125  /// The master, if any, contains precisely the set of variables to be
1126  /// instantiated.
1127  MultiDimAdressable* _master_;
1128 
1129  /// The tuple of variables to be instantiated.
1130  Sequence< const DiscreteVariable* > _vars_;
1131 
1132  /// The current instantiation: the value of the tuple.
1133  std::vector< Idx > _vals_;
1134 
1135  /// Indicates whether the current value of the tuple is valid when we loop
1136  /// sufficiently over values of the tuple, we may have browsed all the
1137  /// possible values and we have to know in a way or another that the tuple
1138  /// contains no more value. This is precisely the meaning of Boolean
1139  /// overflow
1140  bool _overflow_;
1141 
1142  /**
1143  * @brief Swap two variables in the Instantiation.
1144  * @param i The first variable.
1145  * @param j The second variable.
1146  */
1147  void _swap_(Idx i, Idx j);
1148 
1149  /**
1150  * @brief Modifies internally the value of a given variable of the sequence.
1151  *
1152  * In addition to modifying the value of the variable, the Instantiation
1153  * informs its master MultiDimAdressable of the modification.
1154  *
1155  * @param varPos The variable to change.
1156  * @param newVal The variable new value.
1157  */
1158  void _chgVal_(Idx varPos, Idx newVal);
1159 
1160  /**
1161  * @brief Adds a new var to the sequence of vars.
1162  *
1163  * If variable v already belongs to the Instantiation tuple of variables,
1164  * then nothing is done. In particular, no exception is thrown in this
1165  * case.
1166  *
1167  * @warning note that this function does not deassociate the Instantiation
1168  * from its master MultiDimAdressable, if any. To do so, use function add
1169  * instead.
1170  *
1171  * @warning this function does not notify the master MultiDimAdressable,
1172  * if any. Use in addition function chgVal or _chgVal_ if need be.
1173  *
1174  * @warning variable v is known to the Instantiation only by a pointer to
1175  * it. As a result, this is not a copy of v that is used by Instantiation
1176  * but rather v itself. As such, v should never be deleted from memory
1177  * until the Instantiation is removed.
1178  *
1179  * @param v The new var.
1180  * @throw DuplicateElement Raised if v is already in this Instantiation.
1181  */
1182  void _add_(const DiscreteVariable& v);
1183 
1184  /**
1185  * @brief Removes a variable from the sequence of vars.
1186  *
1187  * If variable v does not belong to the Instantiation tuple of variables,
1188  * then nothing is done. In particular, no exception is thrown in this
1189  * case.
1190  *
1191  * @warning this function does not notify the master MultiDimAdressable,
1192  * if any.
1193  *
1194  * @warning note that this function does not deassociate the Instantiation
1195  * from its master MultiDimAdressable, if any. To do so, use function
1196  * removeDim instead.
1197  *
1198  * @param v The variable to be erased from the tuple.
1199  */
1200  void _erase_(const DiscreteVariable& v);
1201 
1202  /**
1203  * This function is called by the master (if any) when changes arise in its
1204  * vars list.
1205  *
1206  * @warning No implementation of this method?
1207  *
1208  * @param v the new vars list
1209  */
1210  void _notifiedDimChanged_(const Sequence< const DiscreteVariable* >& v);
1211 
1212  /**
1213  * @brief Initialize this Instantiation.
1214  * @param master This Instantiation's master.
1215  */
1216  void _init_(MultiDimAdressable* master);
1217 
1218  /**
1219  * @brief Reorder vars of this instantiation giving the order in v.
1220  *
1221  * In the new order variables common to v and *this are placed first, then
1222  * variables only in *this.
1223  *
1224  * The variables only in v are ignored.
1225  *
1226  * @param v The new order of variables in this Instantiation.
1227  */
1228  void _reorder_(const Sequence< const DiscreteVariable* >& v);
1229 
1230  void _masterChangeNotification_(Idx varPos, Idx newVal, Idx oldVal) const;
1231  void _masterFirstNotification_() const;
1232  void _masterIncNotification_() const;
1233  void _masterLastNotification_() const;
1234  void _masterDecNotification_() const;
1235  };
1236 
1237  /**
1238  * @brief Print information of the instantiation in the stream.
1239  */
1240  std::ostream& operator<<(std::ostream&, const Instantiation&);
1241 
1242  /**
1243  * @brief Hash function for gum::Instantiation.
1244  * @ingroup hashfunctions_group
1245  */
1246  template <>
1247  // class HashFunc< Instantiation > : public HashFuncBase< Instantiation > {
1248  class HashFunc< Instantiation >: public HashFuncBase< Instantiation > {
1249  public:
1250  /**
1251  * @brief Returns the value of a key as a Size.
1252  * @param key The value to return as a Size.
1253  * @return Returns the value of a key as a Size.
1254  */
1255  static Size castToSize(const Instantiation& key);
1256 
1257  /**
1258  * @brief Computes the hashed value of a key.
1259  * @param key The key to compute the hashed value.
1260  * @return Returns the hashed value of a key.
1261  */
1262  virtual Size operator()(const Instantiation& key) const override final;
1263  };
1264 } /* namespace gum */
1265 
1266 #ifndef GUM_NO_INLINE
1267 # include <agrum/tools/multidim/instantiation_inl.h>
1268 #endif /* GUM_NO_INLINE */
1269 
1270 #endif /* GUM_INSTANTIATION_H */