aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
adaptiveRMaxPlaner.cpp
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2026 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41
49
50// =========================================================================
51#include <queue>
52#include <vector>
53// #include <algorithm>
54// #include <utility>
55// =========================================================================
58
60// =========================================================================
64// =========================================================================
66
67#ifdef GUM_NO_INLINE
69#endif // GUM_NO_INLINE
70// =========================================================================
71
73#define RECASTED(x) reinterpret_cast< const MultiDimFunctionGraph< double >* >(x)
74
75namespace gum {
76
77 /* **************************************************************************************************
78 * **/
79 /* ** **/
80 /* ** Constructors / Destructors **/
81 /* ** **/
82 /* **************************************************************************************************
83 * **/
84
85 // ===========================================================================
86 // Default constructor
87 // ===========================================================================
89 double discountFactor,
90 double epsilon,
91 const ILearningStrategy* learner,
92 bool verbose) :
93 StructuredPlaner(opi, discountFactor, epsilon, verbose), IDecisionStrategy(),
94 _fmdpLearner_(learner), _initialized_(false) {
95 GUM_CONSTRUCTOR(AdaptiveRMaxPlaner);
96 }
97
98 // ===========================================================================
99 // Default destructor
100 // ===========================================================================
102 GUM_DESTRUCTOR(AdaptiveRMaxPlaner);
103
105 scIter != _counterTable_.endSafe();
106 ++scIter)
107 delete scIter.val();
108 }
109
110 /* **************************************************************************************************
111 * **/
112 /* ** **/
113 /* ** Planning Methods **/
114 /* ** **/
115 /* **************************************************************************************************
116 * **/
117
118 // ==========================================================================
119 // Initializes data structure needed for making the planning
120 // ==========================================================================
122 if (!_initialized_) {
125 for (auto actionIter = fmdp->beginActions(); actionIter != fmdp->endActions(); ++actionIter) {
126 _counterTable_.insert(*actionIter, new StatesCounter());
127 _initializedTable_.insert(*actionIter, false);
128 }
129 _initialized_ = true;
130 }
131 }
132
133 // ===========================================================================
134 // Performs a value iteration
135 // ===========================================================================
143
144 /* **************************************************************************************************
145 * **/
146 /* ** **/
147 /* ** Value Iteration Methods **/
148 /* ** **/
149 /* **************************************************************************************************
150 * **/
151
152 // ===========================================================================
153 // Performs a single step of value iteration
154 // ===========================================================================
156 vFunction_->manager()->setRootNode(vFunction_->manager()->addTerminalNode(0.0));
157 for (auto actionIter = fmdp_->beginActions(); actionIter != fmdp_->endActions(); ++actionIter)
158 vFunction_ = this->operator_->add(vFunction_, RECASTED(this->fmdp_->reward(*actionIter)), 1);
159 }
160
161 // ===========================================================================
162 // Performs a single step of value iteration
163 // ===========================================================================
165 // *****************************************************************************************
166 // Loop reset
167 MultiDimFunctionGraph< double >* newVFunction = operator_->getFunctionInstance();
168 newVFunction->copyAndReassign(*vFunction_, fmdp_->mapMainPrime());
169
170 // *****************************************************************************************
171 // For each action
172 std::vector< MultiDimFunctionGraph< double >* > qActionsSet;
173 for (auto actionIter = fmdp_->beginActions(); actionIter != fmdp_->endActions(); ++actionIter) {
174 MultiDimFunctionGraph< double >* qAction = evalQaction_(newVFunction, *actionIter);
175
176 // *******************************************************************************************
177 // Next, we add the reward
178 qAction = addReward_(qAction, *actionIter);
179
180 qAction = this->operator_->maximize(
181 _actionsRMaxTable_[*actionIter],
182 this->operator_->multiply(qAction, _actionsBoolTable_[*actionIter], 1),
183 2);
184
185 qActionsSet.push_back(qAction);
186 }
187 delete newVFunction;
188
189 // *****************************************************************************************
190 // Next to evaluate main value function, we take maximise over all action
191 // value, ...
192 newVFunction = maximiseQactions_(qActionsSet);
193
194 return newVFunction;
195 }
196
197 /* **************************************************************************************************
198 * **/
199 /* ** **/
200 /* ** Optimal Policy Evaluation Methods **/
201 /* ** **/
202 /* **************************************************************************************************
203 * **/
204
205 // ===========================================================================
206 // Evals the policy corresponding to the given value function
207 // ===========================================================================
209 // *****************************************************************************************
210 // Loop reset
211 MultiDimFunctionGraph< double >* newVFunction = operator_->getFunctionInstance();
212 newVFunction->copyAndReassign(*vFunction_, fmdp_->mapMainPrime());
213
214 std::vector< MultiDimFunctionGraph< ArgMaxSet< double, Idx >, SetTerminalNodePolicy >* >
215 argMaxQActionsSet;
216 // *****************************************************************************************
217 // For each action
218 for (auto actionIter = fmdp_->beginActions(); actionIter != fmdp_->endActions(); ++actionIter) {
219 MultiDimFunctionGraph< double >* qAction = this->evalQaction_(newVFunction, *actionIter);
220
221 qAction = this->addReward_(qAction, *actionIter);
222
223 qAction = this->operator_->maximize(
224 _actionsRMaxTable_[*actionIter],
225 this->operator_->multiply(qAction, _actionsBoolTable_[*actionIter], 1),
226 2);
227
228 argMaxQActionsSet.push_back(makeArgMax_(qAction, *actionIter));
229 }
230 delete newVFunction;
231
232 // *****************************************************************************************
233 // Next to evaluate main value function, we take maximise over all action
234 // value, ...
236 = argmaximiseQactions_(argMaxQActionsSet);
237
238 // *****************************************************************************************
239 // Next to evaluate main value function, we take maximise over all action
240 // value, ...
241 extractOptimalPolicy_(argMaxVFunction);
242 }
243
244 // ===========================================================================
245 //
246 // ===========================================================================
248 _rThreshold_ = _fmdpLearner_->modaMax() * 5 > 30 ? _fmdpLearner_->modaMax() * 5 : 30;
249 _rmax_ = _fmdpLearner_->rMax() / (1.0 - this->discountFactor_);
250
251 for (auto actionIter = this->fmdp()->beginActions(); actionIter != this->fmdp()->endActions();
252 ++actionIter) {
253 std::vector< MultiDimFunctionGraph< double >* > rmaxs;
254 std::vector< MultiDimFunctionGraph< double >* > boolQs;
255
256 for (auto varIter = this->fmdp()->beginVariables(); varIter != this->fmdp()->endVariables();
257 ++varIter) {
258 const IVisitableGraphLearner* visited = _counterTable_[*actionIter];
259
260 MultiDimFunctionGraph< double >* varRMax = this->operator_->getFunctionInstance();
261 MultiDimFunctionGraph< double >* varBoolQ = this->operator_->getFunctionInstance();
262
263 visited->insertSetOfVars(varRMax);
264 visited->insertSetOfVars(varBoolQ);
265
266 std::pair< NodeId, NodeId > rooty
267 = _visitLearner_(visited, visited->root(), varRMax, varBoolQ);
268 varRMax->manager()->setRootNode(rooty.first);
269 varRMax->manager()->reduce();
270 varRMax->manager()->clean();
271 varBoolQ->manager()->setRootNode(rooty.second);
272 varBoolQ->manager()->reduce();
273 varBoolQ->manager()->clean();
274
275 rmaxs.push_back(varRMax);
276 boolQs.push_back(varBoolQ);
277
278 // std::cout << RECASTED(this->fmdp_->transition(*actionIter,
279 // *varIter))->toDot() << std::endl;
280 // for( auto varIter2 =
281 // RECASTED(this->fmdp_->transition(*actionIter,
282 // *varIter))->variablesSequence().beginSafe(); varIter2 !=
283 // RECASTED(this->fmdp_->transition(*actionIter,
284 // *varIter))->variablesSequence().endSafe(); ++varIter2 )
285 // std::cout << (*varIter2)->name() << " | ";
286 // std::cout << std::endl;
287
288 // std::cout << varRMax->toDot() << std::endl;
289 // for( auto varIter =
290 // varRMax->variablesSequence().beginSafe(); varIter !=
291 // varRMax->variablesSequence().endSafe(); ++varIter )
292 // std::cout << (*varIter)->name() << " | ";
293 // std::cout << std::endl;
294
295 // std::cout << varBoolQ->toDot() << std::endl;
296 // for( auto varIter =
297 // varBoolQ->variablesSequence().beginSafe(); varIter !=
298 // varBoolQ->variablesSequence().endSafe(); ++varIter )
299 // std::cout << (*varIter)->name() << " | ";
300 // std::cout << std::endl;
301 }
302
303 // std::cout << "Maximising" << std::endl;
304 _actionsRMaxTable_.insert(*actionIter, this->maximiseQactions_(rmaxs));
305 _actionsBoolTable_.insert(*actionIter, this->minimiseFunctions_(boolQs));
306 }
307 }
308
309 // ===========================================================================
310 //
311 // ===========================================================================
312 std::pair< NodeId, NodeId >
314 NodeId currentNodeId,
317 std::pair< NodeId, NodeId > rep;
318 if (visited->isTerminal(currentNodeId)) {
319 rep.first = rmax->manager()->addTerminalNode(
320 visited->nodeNbObservation(currentNodeId) < _rThreshold_ ? _rmax_ : 0.0);
321 rep.second = boolQ->manager()->addTerminalNode(
322 visited->nodeNbObservation(currentNodeId) < _rThreshold_ ? 0.0 : 1.0);
323 return rep;
324 }
325
326 auto rmaxsons = static_cast< NodeId* >(
327 SOA_ALLOCATE(sizeof(NodeId) * visited->nodeVar(currentNodeId)->domainSize()));
328 auto bqsons = static_cast< NodeId* >(
329 SOA_ALLOCATE(sizeof(NodeId) * visited->nodeVar(currentNodeId)->domainSize()));
330
331 for (Idx moda = 0; moda < visited->nodeVar(currentNodeId)->domainSize(); ++moda) {
332 std::pair< NodeId, NodeId > sonp
333 = _visitLearner_(visited, visited->nodeSon(currentNodeId, moda), rmax, boolQ);
334 rmaxsons[moda] = sonp.first;
335 bqsons[moda] = sonp.second;
336 }
337
338 rep.first = rmax->manager()->addInternalNode(visited->nodeVar(currentNodeId), rmaxsons);
339 rep.second = boolQ->manager()->addInternalNode(visited->nodeVar(currentNodeId), bqsons);
340 return rep;
341 }
342
343 // ===========================================================================
344 //
345 // ===========================================================================
347 for (auto actionIter = this->fmdp()->beginActions(); actionIter != this->fmdp()->endActions();
348 ++actionIter) {
349 delete _actionsBoolTable_[*actionIter];
350 delete _actionsRMaxTable_[*actionIter];
351 }
352 _actionsRMaxTable_.clear();
353 _actionsBoolTable_.clear();
354 }
355
356} // end of namespace gum
#define RECASTED(x)
For shorter line and hence more comprehensive code purposes only.
Headers of the RMax planer class.
Safe Iterators for hashtables.
HashTable< Idx, bool > _initializedTable_
const ILearningStrategy * _fmdpLearner_
HashTable< Idx, MultiDimFunctionGraph< double > * > _actionsBoolTable_
HashTable< Idx, StatesCounter * > _counterTable_
void evalPolicy_() override
Perform the required tasks to extract an optimal policy.
void makePlanning(Idx nbStep=1000000) override
Performs a value iteration.
void initVFunction_() override
Performs a single step of value iteration.
void initialize(const FMDP< double > *fmdp) override
Initializes data structure needed for making the planning.
AdaptiveRMaxPlaner(IOperatorStrategy< double > *opi, double discountFactor, double epsilon, const ILearningStrategy *learner, bool verbose)
Default constructor.
MultiDimFunctionGraph< double > * valueIteration_() override
Performs a single step of value iteration.
~AdaptiveRMaxPlaner() override
Default destructor.
HashTable< Idx, MultiDimFunctionGraph< double > * > _actionsRMaxTable_
std::pair< NodeId, NodeId > _visitLearner_(const IVisitableGraphLearner *, NodeId currentNodeId, MultiDimFunctionGraph< double > *, MultiDimFunctionGraph< double > *)
virtual Size domainSize() const =0
SequenceIteratorSafe< Idx > endActions() const
Returns an iterator reference to the end of the list of actions.
Definition fmdp_tpl.h:419
SequenceIteratorSafe< const DiscreteVariable * > endVariables() const
Returns an iterator reference to the end of the list of variables.
Definition fmdp_tpl.h:398
<agrum/FMDP/SDyna/IDecisionStrategy.h>
virtual void initialize(const FMDP< double > *fmdp)
Initializes the learner.
<agrum/FMDP/SDyna/ILearningStrategy.h>
<agrum/FMDP/SDyna/IVisitableGraphLearner.h>
virtual const DiscreteVariable * nodeVar(NodeId ni) const =0
virtual NodeId root() const =0
virtual bool isTerminal(NodeId ni) const =0
virtual void insertSetOfVars(MultiDimFunctionGraph< double > *) const =0
virtual NodeId nodeSon(NodeId ni, Idx modality) const =0
virtual Idx nodeNbObservation(NodeId ni) const =0
NodeId addInternalNode(const DiscreteVariable *var)
Inserts a new non terminal node in graph.
void clean()
Removes var without nodes in the diagram.
virtual void reduce()=0
Ensures that every isomorphic subgraphs are merged together.
void setRootNode(const NodeId &root)
Sets root node of decision diagram.
NodeId addTerminalNode(const GUM_ELEMENT &value)
Adds a value to the MultiDimFunctionGraph.
void copyAndReassign(const MultiDimFunctionGraph< GUM_ELEMENT, TerminalNodePolicy > &src, const Bijection< const DiscreteVariable *, const DiscreteVariable * > &reassign)
Copies src diagrams structure into this diagrams.
MultiDimFunctionGraphManager< GUM_ELEMENT, TerminalNodePolicy > * manager()
Returns a const reference to the manager of this diagram.
Implementation of a Terminal Node Policy that maps nodeid to a set of value.
<agrum/FMDP/simulation/statesCounter.h>
virtual MultiDimFunctionGraph< ArgMaxSet< double, Idx >, SetTerminalNodePolicy > * argmaximiseQactions_(std::vector< MultiDimFunctionGraph< ArgMaxSet< double, Idx >, SetTerminalNodePolicy > * > &)
void initialize(const FMDP< GUM_ELEMENT > *fmdp) override
Initializes data structure needed for making the planning.
IOperatorStrategy< double > * operator_
void extractOptimalPolicy_(const MultiDimFunctionGraph< ArgMaxSet< double, Idx >, SetTerminalNodePolicy > *optimalValueFunction)
void makePlanning(Idx nbStep=1000000) override
Performs a value iteration.
virtual MultiDimFunctionGraph< double > * addReward_(MultiDimFunctionGraph< double > *function, Idx actionId=0)
MultiDimFunctionGraph< ArgMaxSet< double, Idx >, SetTerminalNodePolicy > * makeArgMax_(const MultiDimFunctionGraph< double > *Qaction, Idx actionId)
virtual MultiDimFunctionGraph< double > * minimiseFunctions_(std::vector< MultiDimFunctionGraph< double > * > &)
StructuredPlaner(IOperatorStrategy< double > *opi, double discountFactor, double epsilon, bool verbose)
MultiDimFunctionGraph< double > * vFunction_
virtual MultiDimFunctionGraph< double > * evalQaction_(const MultiDimFunctionGraph< double > *, Idx)
virtual MultiDimFunctionGraph< double > * maximiseQactions_(std::vector< MultiDimFunctionGraph< double > * > &)
This files contains several function objects that are not (yet) defined in the STL.
Size Idx
Type for indexes.
Definition types.h:79
Size NodeId
Type for node ids.
Header files of gum::Instantiation.
Useful macros for maths.
Headers of MultiDimFunctionGraph.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
Headers of gum::SmallObjectAllocator.
#define SOA_ALLOCATE(x)
Header of the Tensor class.