aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
fmdp_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /**
23  * @file
24  * @brief Template implementation of FMDP/FMDP.h classes.
25  *
26  * @author Pierre-Henri WUILLEMIN(@LIP6) and Jean-Christophe MAGNAN and Christophe
27  * GONZALES(@AMU)
28  */
29 
30 //======================================================================
31 #include <cstdio>
32 #include <iostream>
33 //======================================================================
34 #include <agrum/FMDP/fmdp.h>
35 //======================================================================
36 #define RECAST(x) reinterpret_cast< const MultiDimFunctionGraph< GUM_SCALAR >* >(x)
37 
38 namespace gum {
39 
40 
41  /* **************************************************************************************************
42  * **/
43  /* ** **/
44  /* ** Constructors / Destructors **/
45  /* ** **/
46  /* **************************************************************************************************
47  * **/
48 
49  // ===========================================================================
50  // Default constructor.
51  // ===========================================================================
52  template < typename GUM_SCALAR >
53  INLINE FMDP< GUM_SCALAR >::FMDP(bool onDestructionDeleteVar) {
54  GUM_CONSTRUCTOR(FMDP);
55  onDestructionDeleteVars__ = onDestructionDeleteVar;
56 
57  // Default Action initialisation
58  actionMap__.insert(0, new std::string("DEFAULT"));
59  actionTransitionTable__.insert(0, new VarTransitionTable< GUM_SCALAR >());
60  actionCostTable__.insert(0, nullptr);
61  actionRewardTable__.insert(0, nullptr);
62  }
63 
64  // ===========================================================================
65  // Destructor.
66  // ===========================================================================
67  template < typename GUM_SCALAR >
68  FMDP< GUM_SCALAR >::~FMDP() {
69  // Action Transition Graph deletion
70  for (auto iterA = actionTransitionTable__.beginSafe();
71  iterA != actionTransitionTable__.endSafe();
72  ++iterA) {
73  if (iterA.val()) {
74  for (auto iterH = (iterA.val())->beginSafe();
75  iterH != (iterA.val())->endSafe();
76  ++iterH)
77  if (iterH.val()) delete iterH.val();
78  delete iterA.val();
79  }
80  }
81 
82  // Action cost graph deletion
83  for (auto iterA = actionCostTable__.beginSafe();
84  iterA != actionCostTable__.endSafe();
85  ++iterA)
86  if (iterA.val()) delete iterA.val();
87 
88  // Action reward graph deletion
89  for (auto iterA = actionRewardTable__.beginSafe();
90  iterA != actionRewardTable__.endSafe();
91  ++iterA)
92  if (iterA.val()) delete iterA.val();
93 
94  // Action Name deletion
95  for (auto iterId = actionMap__.beginSafe(); iterId != actionMap__.endSafe();
96  ++iterId)
97  delete iterId.second();
98 
99  // Primed Variables deletion
100  for (auto varIter = main2primed__.beginSafe();
101  varIter != main2primed__.endSafe();
102  ++varIter) {
103  delete varIter.second();
104  if (onDestructionDeleteVars__) delete varIter.first();
105  }
106 
107  GUM_DESTRUCTOR(FMDP);
108  }
109 
110 
111  /* **************************************************************************************************
112  * **/
113  /* ** **/
114  /* ** Variable Handling Methods. **/
115  /* ** **/
116  /* **************************************************************************************************
117  * **/
118 
119  // ===========================================================================
120  // Adds a variable to FMDP description
121  // @throw DuplicateElement if a similar variable already exists
122  // ===========================================================================
123  template < typename GUM_SCALAR >
124  INLINE void FMDP< GUM_SCALAR >::addVariable(const DiscreteVariable* var) {
125  if (varSeq__.exists(var))
126  GUM_ERROR(DuplicateElement,
127  " Variable " << var->name()
128  << " has already been inserted in FMDP.");
129 
130 
131  varSeq__.insert(var);
132 
133  // Prime version creation
134  DiscreteVariable* primeVar = var->clone();
135  primeVar->setName(var->name() + "'");
136  main2primed__.insert(var, primeVar);
137  }
138 
139 
140  /* **************************************************************************************************
141  * **/
142  /* ** **/
143  /* ** Variable Handling Methods. **/
144  /* ** **/
145  /* **************************************************************************************************
146  * **/
147 
148  // ===========================================================================
149  // Adds an action to FMDP description
150  // @throw DuplicateElement if an action with same name already exists
151  // ===========================================================================
152  template < typename GUM_SCALAR >
153  INLINE void FMDP< GUM_SCALAR >::addAction(Idx actionId,
154  const std::string& action) {
155  if (actionId == 0) GUM_ERROR(DuplicateElement, " Action Id 0 is reserved.");
156 
157  for (BijectionIteratorSafe< Idx, const std::string* > actIter
158  = actionMap__.beginSafe();
159  actIter != actionMap__.endSafe();
160  ++actIter)
161  if (*(actIter.second()) == action)
162  GUM_ERROR(DuplicateElement,
163  " Action "
164  << action
165  << " has already been inserted in FMDP with this name.");
166 
167  if (actionMap__.existsFirst(actionId))
168  GUM_ERROR(DuplicateElement,
169  " An action with same id (" << actionId
170  << ") has already been inserted.");
171 
172  actionMap__.insert(actionId, new std::string(action));
173 
174  actionTransitionTable__.insert(actionId,
175  new VarTransitionTable< GUM_SCALAR >());
176  actionCostTable__.insert(actionId, nullptr);
177  actionRewardTable__.insert(actionId, nullptr);
178 
179  actionSeq__.insert(actionId);
180  }
181 
182 
183  /* **************************************************************************************************
184  * **/
185  /* ** **/
186  /* ** Transition methods. **/
187  /* ** **/
188  /* **************************************************************************************************
189  * **/
190 
191  // ===========================================================================
192  // Adds a variable transition table to specified action
193  // @throw NotFound if action or var does not exists
194  // @throw DuplicateElement if variable already has a transition for this
195  // action
196  // ===========================================================================
197  template < typename GUM_SCALAR >
198  INLINE void FMDP< GUM_SCALAR >::addTransitionForAction(
199  Idx actionId,
200  const DiscreteVariable* var,
201  const MultiDimImplementation< GUM_SCALAR >* transition) {
202  if (!varSeq__.exists(var))
203  GUM_ERROR(NotFound,
204  " Variable " << var->name() << " has not been declared before.");
205 
206  if (!actionTransitionTable__.exists(actionId))
207  GUM_ERROR(NotFound,
208  " Action " << actionName(actionId)
209  << " has not been declared before.");
210 
211  if (actionTransitionTable__[actionId]->exists(var))
212  GUM_ERROR(DuplicateElement,
213  " Variable " << var->name()
214  << " already has a transition table in " << actionId
215  << " table.");
216 
217  actionTransitionTable__[actionId]->insert(var, transition);
218  }
219 
220 
221  // ===========================================================================
222  // Returns transition associated to given in parameter variable and given
223  // action
224  // ===========================================================================
225  template < typename GUM_SCALAR >
226  INLINE const MultiDimImplementation< GUM_SCALAR >*
227  FMDP< GUM_SCALAR >::transition(Idx actionId,
228  const DiscreteVariable* v) const {
229  if (!actionTransitionTable__.exists(actionId))
230  GUM_ERROR(NotFound,
231  " Action " << actionName(actionId)
232  << " has not been declared before.");
233 
234  if (actionTransitionTable__[actionId]->exists(v))
235  return (*actionTransitionTable__[actionId])[v];
236  else
237  return (*actionTransitionTable__[0]).exists(v)
238  ? (*actionTransitionTable__[0])[v]
239  : nullptr;
240  }
241 
242 
243  /* **************************************************************************************************
244  * **/
245  /* ** **/
246  /* ** Cost methods. **/
247  /* ** **/
248  /* **************************************************************************************************
249  * **/
250 
251  // ===========================================================================
252  // Adds a cost table to specified action
253  // @throw NotFound if action does not exists
254  // @throw DuplicateElement if action already has a cost
255  // ===========================================================================
256  template < typename GUM_SCALAR >
257  INLINE void FMDP< GUM_SCALAR >::addCostForAction(
258  Idx actionId,
259  const MultiDimImplementation< GUM_SCALAR >* cost) {
260  if (!actionCostTable__.exists(actionId))
261  GUM_ERROR(NotFound,
262  " Action " << actionName(actionId)
263  << " has not been declared before.");
264 
265  if (actionCostTable__[actionId] != nullptr)
266  GUM_ERROR(DuplicateElement,
267  " Action " << actionName(actionId) << " already has a cost table");
268 
269  actionCostTable__[actionId] = cost;
270  }
271 
272 
273  // ===========================================================================
274  // Returns transition associated to given in parameter variable and given
275  // action
276  // ===========================================================================
277  template < typename GUM_SCALAR >
278  INLINE const MultiDimImplementation< GUM_SCALAR >*
279  FMDP< GUM_SCALAR >::cost(Idx actionId) const {
280  if (!actionCostTable__.exists(actionId))
281  GUM_ERROR(NotFound,
282  " Action " << actionName(actionId)
283  << " has not been declared before.");
284 
285  if (actionCostTable__[actionId]) return actionCostTable__[actionId];
286  return actionCostTable__[0];
287  }
288 
289 
290  /* **************************************************************************************************
291  * **/
292  /* ** **/
293  /* ** Cost methods. **/
294  /* ** **/
295  /* **************************************************************************************************
296  * **/
297 
298  // ===========================================================================
299  // Adds a default variable reward
300  // @throw DuplicateElement if a default reward exists already
301  // ===========================================================================
302  template < typename GUM_SCALAR >
303  INLINE void FMDP< GUM_SCALAR >::addRewardForAction(
304  Idx actionId,
305  const MultiDimImplementation< GUM_SCALAR >* reward) {
306  if (!actionRewardTable__.exists(actionId))
307  GUM_ERROR(NotFound,
308  " Action " << actionName(actionId)
309  << " has not been declared before.");
310 
311  if (actionRewardTable__[actionId] != nullptr)
312  GUM_ERROR(DuplicateElement,
313  " Action " << actionName(actionId)
314  << " already has a reward table");
315 
316  actionRewardTable__[actionId] = reward;
317  }
318 
319 
320  // ===========================================================================
321  // Returns transition associated to given in parameter variable and given
322  // action
323  // ===========================================================================
324  template < typename GUM_SCALAR >
325  INLINE const MultiDimImplementation< GUM_SCALAR >*
326  FMDP< GUM_SCALAR >::reward(Idx actionId) const {
327  if (!actionRewardTable__.exists(actionId))
328  GUM_ERROR(NotFound,
329  " Action " << actionName(actionId)
330  << " has not been declared before.");
331 
332  if (actionRewardTable__[actionId]) return actionRewardTable__[actionId];
333  return actionRewardTable__[0];
334  }
335 
336 
337  /* **************************************************************************************************
338  * **/
339  /* ** **/
340  /* ** Miscelleanous methods. **/
341  /* ** **/
342  /* **************************************************************************************************
343  * **/
344 
345  // ===========================================================================
346  // Returns name of action given in parameter
347  // ===========================================================================
348  template < typename GUM_SCALAR >
349  INLINE const std::string& FMDP< GUM_SCALAR >::actionName(Idx actionId) const {
350  if (!actionMap__.existsFirst(actionId))
351  GUM_ERROR(NotFound, "No action with " << actionId << " as identifiant.");
352 
353  return *(actionMap__.second(actionId));
354  }
355 
356  // ===========================================================================
357  // Returns action id
358  // ===========================================================================
359  template < typename GUM_SCALAR >
360  INLINE Idx FMDP< GUM_SCALAR >::actionId(const std::string& action) const {
361  for (BijectionIterator< Idx, const std::string* > actIter
362  = actionMap__.begin();
363  actIter != actionMap__.end();
364  ++actIter)
365  if (*(actIter.second()) == action) { return actIter.first(); }
366 
367  GUM_ERROR(NotFound, " Action " << action << " has not been declared before.");
368  }
369 
370 
371  template < typename GUM_SCALAR >
372  INLINE std::string FMDP< GUM_SCALAR >::toString() const {
373  std::stringstream fmdpCore;
374 
375  for (auto actionIter = beginActions(); actionIter != endActions();
376  ++actionIter) {
377  for (auto varIter = beginVariables(); varIter != endVariables(); ++varIter)
378  if (this->transition(*actionIter, *varIter))
379  fmdpCore << RECAST(this->transition(*actionIter, *varIter))->toDot()
380  << std::endl;
381  if (this->reward(*actionIter))
382  fmdpCore << RECAST(this->reward(*actionIter))->toDot() << std::endl;
383  }
384 
385  for (auto varIter = beginVariables(); varIter != endVariables(); ++varIter)
386  if (this->transition(0, *varIter))
387  fmdpCore << RECAST(this->transition(0, *varIter))->toDot() << std::endl;
388  if (this->reward()) fmdpCore << RECAST(this->reward())->toDot() << std::endl;
389  return fmdpCore.str();
390  }
391 
392 
393  template < typename GUM_SCALAR >
394  INLINE Size FMDP< GUM_SCALAR >::size() const {
395  Size s = 0;
396  for (auto actionIter = beginActions(); actionIter != endActions();
397  ++actionIter) {
398  for (auto varIter = beginVariables(); varIter != endVariables(); ++varIter)
399  if (this->transition(*actionIter, *varIter))
400  s += this->transition(*actionIter, *varIter)->realSize();
401  if (this->reward(*actionIter)) s += this->reward(*actionIter)->realSize();
402  }
403 
404  for (auto varIter = beginVariables(); varIter != endVariables(); ++varIter)
405  if (this->transition(0, *varIter))
406  s += this->transition(0, *varIter)->realSize();
407  if (this->reward()) s += this->reward()->realSize();
408  return s;
409  }
410 } // namespace gum
#define RECAST(x)
Definition: fmdp_tpl.h:36