aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
imddi_tpl.h
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#pragma once
42
43
51// =======================================================
54
56// =======================================================
59// =======================================================
61
62// =======================================================
63
64
65namespace gum {
66
67 // ############################################################################
68 // Constructor & destructor.
69 // ############################################################################
70
71 // ============================================================================
72 // Variable Learner constructor
73 // ============================================================================
74 template < TESTNAME AttributeSelection, bool isScalar >
76 double attributeSelectionThreshold,
77 double pairSelectionThreshold,
78 gum::VariableSet attributeListe,
79 const DiscreteVariable* learnedValue) :
80 IncrementalGraphLearner< AttributeSelection, isScalar >(target, attributeListe, learnedValue),
81 _lg_(&(this->model_), pairSelectionThreshold), _nbTotalObservation_(0),
82 _attributeSelectionThreshold_(attributeSelectionThreshold) {
83 GUM_CONSTRUCTOR(IMDDI);
84 _addLeaf_(this->root_);
85 }
86
87 // ============================================================================
88 // Reward Learner constructor
89 // ============================================================================
90 template < TESTNAME AttributeSelection, bool isScalar >
92 double attributeSelectionThreshold,
93 double pairSelectionThreshold,
94 gum::VariableSet attributeListe) :
95 IncrementalGraphLearner< AttributeSelection, isScalar >(
96 target,
97 attributeListe,
98 new LabelizedVariable("Reward", "", 2)),
99 _lg_(&(this->model_), pairSelectionThreshold), _nbTotalObservation_(0),
100 _attributeSelectionThreshold_(attributeSelectionThreshold) {
101 GUM_CONSTRUCTOR(IMDDI);
102 _addLeaf_(this->root_);
103 }
104
105 // ============================================================================
106 // Reward Learner constructor
107 // ============================================================================
108 template < TESTNAME AttributeSelection, bool isScalar >
110 GUM_DESTRUCTOR(IMDDI);
112 leafIter != _leafMap_.endSafe();
113 ++leafIter)
114 delete leafIter.val();
115 }
116
117 // ############################################################################
118 // Incrementals methods
119 // ############################################################################
120
121 template < TESTNAME AttributeSelection, bool isScalar >
126
127 template < TESTNAME AttributeSelection, bool isScalar >
129 NodeId currentNodeId) {
131 newObs,
132 currentNodeId);
133 if (this->nodeVarMap_[currentNodeId] == this->value_) _lg_.updateLeaf(_leafMap_[currentNodeId]);
134 }
135
136 // ============================================================================
137 // Updates the tree after a new observation has been added
138 // ============================================================================
139 template < TESTNAME AttributeSelection, bool isScalar >
141 _varOrder_.clear();
142
143 // First xe initialize the node set which will give us the scores
144 Set< NodeId > currentNodeSet;
145 currentNodeSet.insert(this->root_);
146
147 // Then we initialize the pool of variables to consider
149 for (vs.begin(); vs.hasNext(); vs.next()) {
150 _updateScore_(vs.current(), this->root_, vs);
151 }
152
153 // Then, until there's no node remaining
154 while (!vs.isEmpty()) {
155 // We select the best var
156 const DiscreteVariable* selectedVar = vs.select();
157 _varOrder_.insert(selectedVar);
158
159 // Then we decide if we update each node according to this var
160 _updateNodeSet_(currentNodeSet, selectedVar, vs);
161 }
162
163 // If there are remaining node that are not leaves after we establish the
164 // var order
165 // these nodes are turned into leaf.
166 for (SetIteratorSafe< NodeId > nodeIter = currentNodeSet.beginSafe();
167 nodeIter != currentNodeSet.endSafe();
168 ++nodeIter)
169 this->convertNode2Leaf_(*nodeIter);
170
171
172 if (_lg_.needsUpdate()) _lg_.update();
173 }
174
175 // ############################################################################
176 // Updating methods
177 // ############################################################################
178
179
180 // ###################################################################
181 // Select the most relevant variable
182 //
183 // First parameter is the set of variables among which the most
184 // relevant one is choosed
185 // Second parameter is the set of node the will attribute a score
186 // to each variable so that we choose the best.
187 // ###################################################################
188 template < TESTNAME AttributeSelection, bool isScalar >
190 NodeId nody,
191 VariableSelector& vs) {
192 if (!this->nodeId2Database_[nody]->isTestRelevant(var)) return;
193 double weight = (double)this->nodeId2Database_[nody]->nbObservation()
195 vs.updateScore(var,
196 weight * this->nodeId2Database_[nody]->testValue(var),
197 weight * this->nodeId2Database_[nody]->testOtherCriterion(var));
198 }
199
200 template < TESTNAME AttributeSelection, bool isScalar >
202 NodeId nody,
203 VariableSelector& vs) {
204 if (!this->nodeId2Database_[nody]->isTestRelevant(var)) return;
205 double weight = (double)this->nodeId2Database_[nody]->nbObservation()
207 vs.downdateScore(var,
208 weight * this->nodeId2Database_[nody]->testValue(var),
209 weight * this->nodeId2Database_[nody]->testOtherCriterion(var));
210 }
211
212 // ============================================================================
213 // For each node in the given set, this methods checks whether or not
214 // we should installed the given variable as a test.
215 // If so, the node is updated
216 // ============================================================================
217 template < TESTNAME AttributeSelection, bool isScalar >
219 const DiscreteVariable* selectedVar,
220 VariableSelector& vs) {
221 Set< NodeId > oldNodeSet(nodeSet);
222 nodeSet.clear();
223 for (SetIteratorSafe< NodeId > nodeIter = oldNodeSet.beginSafe();
224 nodeIter != oldNodeSet.endSafe();
225 ++nodeIter) {
226 if (this->nodeId2Database_[*nodeIter]->isTestRelevant(selectedVar)
227 && this->nodeId2Database_[*nodeIter]->testValue(selectedVar)
229 this->transpose_(*nodeIter, selectedVar);
230
231 // Then we subtract the from the score given to each variables the
232 // quantity given by this node
233 for (vs.begin(); vs.hasNext(); vs.next()) {
234 _downdateScore_(vs.current(), *nodeIter, vs);
235 }
236
237 // And finally we add all its child to the new set of nodes
238 // and updates the remaining var's score
239 for (Idx modality = 0; modality < this->nodeVarMap_[*nodeIter]->domainSize(); ++modality) {
240 NodeId sonId = this->nodeSonsMap_[*nodeIter][modality];
241 nodeSet << sonId;
242
243 for (vs.begin(); vs.hasNext(); vs.next()) {
244 _updateScore_(vs.current(), sonId, vs);
245 }
246 }
247 } else {
248 nodeSet << *nodeIter;
249 }
250 }
251 }
252
253 // ============================================================================
254 // Insert a new node with given associated database, var and maybe sons
255 // ============================================================================
256 template < TESTNAME AttributeSelection, bool isScalar >
259 const DiscreteVariable* boundVar,
261 NodeId currentNodeId
263 boundVar,
264 obsSet);
265
266 _addLeaf_(currentNodeId);
267
268 return currentNodeId;
269 }
270
271 // ============================================================================
272 // Changes var associated to a node
273 // ============================================================================
274 template < TESTNAME AttributeSelection, bool isScalar >
276 const DiscreteVariable* desiredVar) {
277 if (this->nodeVarMap_[currentNodeId] == this->value_) _removeLeaf_(currentNodeId);
278
280 desiredVar);
281
282 if (desiredVar == this->value_) _addLeaf_(currentNodeId);
283 }
284
285 // ============================================================================
286 // Remove node from graph
287 // ============================================================================
288 template < TESTNAME AttributeSelection, bool isScalar >
290 if (this->nodeVarMap_[currentNodeId] == this->value_) _removeLeaf_(currentNodeId);
292 }
293
294 // ============================================================================
295 // Add leaf to aggregator
296 // ============================================================================
297 template < TESTNAME AttributeSelection, bool isScalar >
299 _leafMap_.insert(
300 currentNodeId,
302 this->nodeId2Database_[currentNodeId],
303 &(this->valueAssumed_)));
304 _lg_.addLeaf(_leafMap_[currentNodeId]);
305 }
306
307 // ============================================================================
308 // Remove leaf from aggregator
309 // ============================================================================
310 template < TESTNAME AttributeSelection, bool isScalar >
312 _lg_.removeLeaf(_leafMap_[currentNodeId]);
313 delete _leafMap_[currentNodeId];
314 _leafMap_.erase(currentNodeId);
315 }
316
317 // ============================================================================
318 // Computes the Reduced and Ordered Function Graph associated to this ordered
319 // tree
320 // ============================================================================
321 template < TESTNAME AttributeSelection, bool isScalar >
323 // if( _lg_.needsUpdate() || this->needUpdate_ ){
325 this->needUpdate_ = false;
326 // }
327 }
328
329 // ============================================================================
330 // Performs the leaves merging
331 // ============================================================================
332 template < TESTNAME AttributeSelection, bool isScalar >
334 // *******************************************************************************************************
335 // Mise à jour de l'aggregateur de feuille
336 _lg_.update();
337
338 // *******************************************************************************************************
339 // Reinitialisation du Graphe de Décision
340 this->target_->clear();
341 for (auto varIter = _varOrder_.beginSafe(); varIter != _varOrder_.endSafe(); ++varIter)
342 this->target_->add(**varIter);
343 this->target_->add(*this->value_);
344
346
347 // *******************************************************************************************************
348 // Insertion des feuilles
349 HashTable< NodeId, AbstractLeaf* > treeNode2leaf = _lg_.leavesMap();
352 = treeNode2leaf.cbeginSafe();
353 treeNodeIter != treeNode2leaf.cendSafe();
354 ++treeNodeIter) {
355 if (!leaf2DGNode.exists(treeNodeIter.val()))
356 leaf2DGNode.insert(treeNodeIter.val(),
358
359 toTarget.insert(treeNodeIter.key(), leaf2DGNode[treeNodeIter.val()]);
360 }
361
362 // *******************************************************************************************************
363 // Insertion des noeuds internes (avec vérification des possibilités de
364 // fusion)
366 varIter != _varOrder_.rendSafe();
367 --varIter) {
368 for (Link< NodeId >* curNodeIter = this->var2Node_[*varIter]->list(); curNodeIter;
369 curNodeIter = curNodeIter->nextLink()) {
370 NodeId* sonsMap
371 = static_cast< NodeId* >(SOA_ALLOCATE(sizeof(NodeId) * (*varIter)->domainSize()));
372 for (Idx modality = 0; modality < (*varIter)->domainSize(); ++modality)
373 sonsMap[modality] = toTarget[this->nodeSonsMap_[curNodeIter->element()][modality]];
374 toTarget.insert(curNodeIter->element(),
375 this->target_->manager()->addInternalNode(*varIter, sonsMap));
376 }
377 }
378
379 // *******************************************************************************************************
380 // Polish
381 this->target_->manager()->setRootNode(toTarget[this->root_]);
382 this->target_->manager()->clean();
383 }
384
385 // ============================================================================
386 // Performs the leaves merging
387 // ============================================================================
388 template < TESTNAME AttributeSelection, bool isScalar >
391 double value = 0.0;
392 for (Idx moda = 0; moda < leaf->nbModa(); moda++) {
393 value += (double)leaf->effectif(moda) * this->valueAssumed_.atPos(moda);
394 }
395 if (leaf->total()) value /= (double)leaf->total();
396 return this->target_->manager()->addTerminalNode(value);
397 }
398
399 // ============================================================================
400 // Performs the leaves merging
401 // ============================================================================
402 template < TESTNAME AttributeSelection, bool isScalar >
405 NodeId* sonsMap
406 = static_cast< NodeId* >(SOA_ALLOCATE(sizeof(NodeId) * this->value_->domainSize()));
407 for (Idx modality = 0; modality < this->value_->domainSize(); ++modality) {
408 double newVal = 0.0;
409 if (leaf->total()) newVal = (double)leaf->effectif(modality) / (double)leaf->total();
410 sonsMap[modality] = this->target_->manager()->addTerminalNode(newVal);
411 }
412 return this->target_->manager()->addInternalNode(this->value_, sonsMap);
413 }
414
415 template < TESTNAME AttributeSelection, bool isScalar >
419 varIter != _varOrder_.endSafe();
420 ++varIter)
421 ret->add(**varIter);
422 }
423
424} // namespace gum
Headers of the ChiSquare class.
Safe Iterators for hashtables.
<agrum/FMDP/learning/datastructure/leaves/abstractLeaf.h>
virtual Idx nbModa() const =0
virtual double total() const =0
virtual double effectif(Idx) const =0
Gaves the leaf effectif for given modality.
<agrum/FMDP/learning/datastructure/leaves/concreteLeaf.h>
Base class for discrete random variable.
Safe Const Iterators for hashtables.
Definition hashTable.h:1662
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
const_iterator_safe cbeginSafe() const
Returns the safe const_iterator pointing to the beginning of the hashtable.
const const_iterator_safe & cendSafe() const noexcept
Returns the safe const_iterator pointing to the end of the hashtable.
bool exists(const Key &key) const
Checks whether there exists an element with a given key in the hashtable.
void _addLeaf_(NodeId)
Adds a new observation to the structure.
Definition imddi_tpl.h:298
NodeId _insertLeafInFunctionGraph_(AbstractLeaf *, Int2Type< true >)
Computes the score of the given variables for the given node.
Definition imddi_tpl.h:389
void _updateNodeSet_(Set< NodeId > &, const DiscreteVariable *, VariableSelector &)
For each node in the given set, this methods checks whether or not we should installed the given vari...
Definition imddi_tpl.h:218
Idx _nbTotalObservation_
The total number of observation added to this tree.
Definition imddi.h:184
IMDDI(MultiDimFunctionGraph< double > *target, double attributeSelectionThreshold, double pairSelectionThreshold, gum::VariableSet attributeListe, const DiscreteVariable *learnedValue)
Variable Learner constructor.
Definition imddi_tpl.h:75
void _removeLeaf_(NodeId)
Adds a new observation to the structure.
Definition imddi_tpl.h:311
void addObservation(const Observation *) override
Adds a new observation to the structure.
Definition imddi_tpl.h:122
void _updateScore_(const DiscreteVariable *, NodeId, VariableSelector &vs)
Computes the score of the given variables for the given node.
Definition imddi_tpl.h:189
LeafAggregator _lg_
Definition imddi.h:179
Sequence< const DiscreteVariable * > _varOrder_
Definition imddi.h:177
void _downdateScore_(const DiscreteVariable *, NodeId, VariableSelector &vs)
Computes the score of the given variables for the given node.
Definition imddi_tpl.h:201
double _attributeSelectionThreshold_
The threshold above which we consider variables to be dependant.
Definition imddi.h:187
void chgNodeBoundVar_(NodeId chgedNodeId, const DiscreteVariable *desiredVar) override
Adds a new observation to the structure.
Definition imddi_tpl.h:275
NodeId insertLeafNode_(NodeDatabase< AttributeSelection, isScalar > *nDB, const DiscreteVariable *boundVar, Set< const Observation * > *sonsMap) override
Adds a new observation to the structure.
Definition imddi_tpl.h:257
void removeNode_(NodeId removedNodeId) override
Adds a new observation to the structure.
Definition imddi_tpl.h:289
HashTable< NodeId, AbstractLeaf * > _leafMap_
Definition imddi.h:181
void insertSetOfVars(MultiDimFunctionGraph< double > *ret) const override
Definition imddi_tpl.h:416
~IMDDI() override
Default destructor.
Definition imddi_tpl.h:109
void _rebuildFunctionGraph_()
Computes the score of the given variables for the given node.
Definition imddi_tpl.h:333
void updateNodeWithObservation_(const Observation *newObs, NodeId currentNodeId) override
Adds a new observation to the structure.
Definition imddi_tpl.h:128
void updateGraph() override
Updates the tree after a new observation has been added.
Definition imddi_tpl.h:140
void updateFunctionGraph() override
Computes the score of the given variables for the given node.
Definition imddi_tpl.h:322
virtual void updateNodeWithObservation_(const Observation *newObs, NodeId currentNodeId)
Will update internal graph's NodeDatabase of given node with the new observation.
virtual void transpose_(NodeId, const DiscreteVariable *)
virtual NodeId insertLeafNode_(NodeDatabase< AttributeSelection, isScalar > *nDB, const DiscreteVariable *boundVar, Set< const Observation * > *obsSet)
inserts a new leaf node in internal graohs
HashTable< const DiscreteVariable *, LinkedList< NodeId > * > var2Node_
HashTable< NodeId, NodeDatabase< AttributeSelection, isScalar > * > nodeId2Database_
virtual void addObservation(const Observation *obs)
Inserts a new observation.
HashTable< NodeId, const DiscreteVariable * > nodeVarMap_
IncrementalGraphLearner(MultiDimFunctionGraph< double > *target, gum::VariableSet attributesSet, const DiscreteVariable *learnVariable)
virtual void removeNode_(NodeId removedNodeId)
Removes a node from the internal graph.
virtual void chgNodeBoundVar_(NodeId chgedNodeId, const DiscreteVariable *desiredVar)
Changes the associated variable of a node.
class LabelizedVariable
void add(const DiscreteVariable &v) override
Adds a new var to the variables of the multidimensional matrix.
<agrum/FMDP/learning/datastructure/nodeDatabase.h>
Safe iterators for Sequence.
Definition sequence.h:1148
Safe iterators for the Set class.
Definition set.h:592
void clear()
Removes all the elements, if any, from the set.
Definition set_tpl.h:315
void insert(const Key &k)
Inserts a new element into the set.
Definition set_tpl.h:510
iterator_safe beginSafe() const
The usual safe begin iterator to parse the set.
Definition set_tpl.h:385
static const iterator_safe & endSafe() noexcept
The usual safe end iterator to parse the set.
Definition set_tpl.h:397
<agrum/FMDP/planning/FunctionGraph/variableselector.h>
void updateScore(const DiscreteVariable *var, double score, double secondaryscore)
The set of remaining vars to select among.
void downdateScore(const DiscreteVariable *var, double score, double secondaryscore)
The set of remaining vars to select among.
bool hasNext() const
The set of remaining vars to select among.
void begin()
The set of remaining vars to select among.
const DiscreteVariable * select()
Select the most relevant variable.
void next()
The set of remaining vars to select among.
bool isEmpty() const
The set of remaining vars to select among.
const DiscreteVariable * current() const
The set of remaining vars to select among.
Size Idx
Type for indexes.
Definition types.h:79
Size NodeId
Type for node ids.
Headers of the IMDDI class.
Base class for labelized discrete random variables.
Useful macros for maths.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
Set< const DiscreteVariable * > VariableSet
priority queues (in which an element cannot appear more than once)
#define SOA_ALLOCATE(x)
Provides basic types used in aGrUM.