aGrUM  0.14.2
incrementalGraphLearner_tpl.h
Go to the documentation of this file.
1 /*********************************************************************************
2  * Copyright (C) 2005 by Pierre-Henri WUILLEMIN et Christophe GONZALES *
3  * {prenom.nom}_at_lip6.fr *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  *********************************************************************************/
26 // =======================================================
27 #include <queue>
28 // =======================================================
29 #include <agrum/core/math/math.h>
31 #include <agrum/core/types.h>
32 // =======================================================
35 // =======================================================
37 // =======================================================
38 
39 namespace gum {
40 
41  // ============================================================================
43  // ============================================================================
44 
45  // ############################################################################
56  // ############################################################################
57  template < TESTNAME AttributeSelection, bool isScalar >
61  const DiscreteVariable* value) :
62  _target(target),
63  _setOfVars(varList), _value(value) {
64  GUM_CONSTRUCTOR(IncrementalGraphLearner);
65 
66  for (auto varIter = _setOfVars.cbeginSafe(); varIter != _setOfVars.cendSafe();
67  ++varIter)
68  _var2Node.insert(*varIter, new LinkedList< NodeId >());
69  _var2Node.insert(_value, new LinkedList< NodeId >());
70 
71  _model.addNode();
72  this->_root = _insertLeafNode(
74  _value,
76  }
77 
78 
79  // ############################################################################
81  // ############################################################################
82  template < TESTNAME AttributeSelection, bool isScalar >
83  IncrementalGraphLearner< AttributeSelection,
85  for (auto nodeIter = _nodeId2Database.beginSafe();
86  nodeIter != _nodeId2Database.endSafe();
87  ++nodeIter)
88  delete nodeIter.val();
89 
90  for (auto nodeIter = _nodeSonsMap.beginSafe();
91  nodeIter != _nodeSonsMap.endSafe();
92  ++nodeIter)
93  SOA_DEALLOCATE(nodeIter.val(),
94  sizeof(NodeId) * _nodeVarMap[nodeIter.key()]->domainSize());
95 
96  for (auto varIter = _var2Node.beginSafe(); varIter != _var2Node.endSafe();
97  ++varIter)
98  delete varIter.val();
99 
100  for (auto nodeIter = _leafDatabase.beginSafe();
101  nodeIter != _leafDatabase.endSafe();
102  ++nodeIter)
103  delete nodeIter.val();
104 
105  __clearValue();
106 
107  GUM_DESTRUCTOR(IncrementalGraphLearner);
108  }
109 
110 
111  // ============================================================================
113  // ============================================================================
114 
115  // ############################################################################
120  // ############################################################################
121  template < TESTNAME AttributeSelection, bool isScalar >
123  const Observation* newObs) {
124  __assumeValue(newObs);
125 
126  // The we go across the tree
127  NodeId currentNodeId = _root;
128 
129  while (_nodeSonsMap.exists(currentNodeId)) {
130  // On each encountered node, we update the database
131  _updateNodeWithObservation(newObs, currentNodeId);
132 
133  // The we select the next to go throught
134  currentNodeId =
135  _nodeSonsMap[currentNodeId]
136  [__branchObs(newObs, _nodeVarMap[currentNodeId])];
137  }
138 
139  // On final insertion into the leave we reach
140  _updateNodeWithObservation(newObs, currentNodeId);
141  _leafDatabase[currentNodeId]->insert(newObs);
142  }
143 
144 
145  // ============================================================================
147  // ============================================================================
148 
149  // ############################################################################
153  // ############################################################################
154  template < TESTNAME AttributeSelection, bool isScalar >
156  const DiscreteVariable* var) {
157  Link< NodeId >* nodIter = _var2Node[var]->list();
158  Link< NodeId >* nni = nullptr;
159  while (nodIter) {
160  nni = nodIter->nextLink();
161  _convertNode2Leaf(nodIter->element());
162  nodIter = nni;
163  }
164  }
165 
166 
167  // ############################################################################
175  // ############################################################################
176  template < TESTNAME AttributeSelection, bool isScalar >
178  NodeId updatedNode, Set< const DiscreteVariable* >& varsOfInterest) {
179  // If this node has no interesting variable, we turn it into a leaf
180  if (varsOfInterest.empty()) {
181  _convertNode2Leaf(updatedNode);
182  return;
183  }
184 
185  // If this node has already one of the best variable intalled as test, we
186  // move on
187  if (_nodeVarMap.exists(updatedNode)
188  && varsOfInterest.exists(_nodeVarMap[updatedNode])) {
189  return;
190  }
191 
192  // In any other case we have to install variable as best test
193  Idx randy = (Idx)(std::rand() / RAND_MAX) * varsOfInterest.size(), basc = 0;
194  SetConstIteratorSafe< const DiscreteVariable* > varIter;
195  for (varIter = varsOfInterest.cbeginSafe(), basc = 0;
196  varIter != varsOfInterest.cendSafe() && basc < randy;
197  ++varIter, basc++)
198  ;
199 
200  _transpose(updatedNode, *varIter);
201  }
202 
203 
204  // ############################################################################
206  // ############################################################################
207  template < TESTNAME AttributeSelection, bool isScalar >
209  NodeId currentNodeId) {
210  if (_nodeVarMap[currentNodeId] != _value) {
211  _leafDatabase.insert(currentNodeId, new Set< const Observation* >());
212 
213  // Resolving potential sons issue
214  for (Idx modality = 0; modality < _nodeVarMap[currentNodeId]->domainSize();
215  ++modality) {
216  NodeId sonId = _nodeSonsMap[currentNodeId][modality];
217  _convertNode2Leaf(sonId);
218  (*_leafDatabase[currentNodeId]) =
219  (*_leafDatabase[currentNodeId]) + *(_leafDatabase[sonId]);
220  _removeNode(sonId);
221  }
222 
223  SOA_DEALLOCATE(_nodeSonsMap[currentNodeId],
224  sizeof(NodeId) * _nodeVarMap[currentNodeId]->domainSize());
225  _nodeSonsMap.erase(currentNodeId);
226 
227  _chgNodeBoundVar(currentNodeId, _value);
228  }
229  }
230 
231 
232  // ############################################################################
235  // ############################################################################
236  template < TESTNAME AttributeSelection, bool isScalar >
238  NodeId currentNodeId, const DiscreteVariable* desiredVar) {
239  // **************************************************************************************
240  // Si le noeud courant contient déjà la variable qu'on souhaite lui amener
241  // Il n'y a rien à faire
242  if (_nodeVarMap[currentNodeId] == desiredVar) { return; }
243 
244  // **************************************************************************************
245  // Si le noeud courant est terminal,
246  // Il faut artificiellement insérer un noeud liant à la variable
247  if (_nodeVarMap[currentNodeId] == _value) {
248  // We turned this leaf into an internal node.
249  // This mean that we'll need to install children leaves for each value of
250  // desiredVar
251 
252  // First We must prepare these new leaves NodeDatabases and Sets<const
253  // Observation*>
257  * desiredVar->domainSize()));
258  Set< const Observation* >** obsetMap =
259  static_cast< Set< const Observation* >** >(SOA_ALLOCATE(
260  sizeof(Set< const Observation* >*) * desiredVar->domainSize()));
261  for (Idx modality = 0; modality < desiredVar->domainSize(); ++modality) {
262  dbMap[modality] =
264  obsetMap[modality] = new Set< const Observation* >();
265  }
267  _leafDatabase[currentNodeId]->beginSafe();
268  _leafDatabase[currentNodeId]->endSafe() != obsIter;
269  ++obsIter) {
270  dbMap[__branchObs(*obsIter, desiredVar)]->addObservation(*obsIter);
271  obsetMap[__branchObs(*obsIter, desiredVar)]->insert(*obsIter);
272  }
273 
274  // Then we can install each new leaves (and put in place the sonsMap)
275  NodeId* sonsMap = static_cast< NodeId* >(
276  SOA_ALLOCATE(sizeof(NodeId) * desiredVar->domainSize()));
277  for (Idx modality = 0; modality < desiredVar->domainSize(); ++modality)
278  sonsMap[modality] =
279  _insertLeafNode(dbMap[modality], _value, obsetMap[modality]);
280 
281  // Some necessary clean up
282  SOA_DEALLOCATE(dbMap,
284  * desiredVar->domainSize());
286  obsetMap, sizeof(Set< const Observation* >*) * desiredVar->domainSize());
287 
288  // And finally we can turn the node into an internal node associated to
289  // desiredVar
290  _chgNodeBoundVar(currentNodeId, desiredVar);
291  _nodeSonsMap.insert(currentNodeId, sonsMap);
292 
293  return;
294  }
295 
296  // *************************************************************************************
297  // Remains the general case where currentNodeId is an internal node.
298 
299  // First we ensure that children node use desiredVar as variable
300  for (Idx modality = 0; modality < _nodeVarMap[currentNodeId]->domainSize();
301  ++modality)
302  _transpose(_nodeSonsMap[currentNodeId][modality], desiredVar);
303 
304  // Sequence<NodeDatabase<AttributeSelection, isScalar>*>
305  // sonsNodeDatabase =
306  // _nodeId2Database[currentNodeId]->splitOnVar(desiredVar);
307  NodeId* sonsMap = static_cast< NodeId* >(
308  SOA_ALLOCATE(sizeof(NodeId) * desiredVar->domainSize()));
309 
310  // Then we create the new mapping
311  for (Idx desiredVarModality = 0; desiredVarModality < desiredVar->domainSize();
312  ++desiredVarModality) {
313  NodeId* grandSonsMap = static_cast< NodeId* >(
314  SOA_ALLOCATE(sizeof(NodeId) * _nodeVarMap[currentNodeId]->domainSize()));
317  for (Idx currentVarModality = 0;
318  currentVarModality < _nodeVarMap[currentNodeId]->domainSize();
319  ++currentVarModality) {
320  grandSonsMap[currentVarModality] =
321  _nodeSonsMap[_nodeSonsMap[currentNodeId][currentVarModality]]
322  [desiredVarModality];
323  sonDB->operator+=((*_nodeId2Database[grandSonsMap[currentVarModality]]));
324  }
325 
326  sonsMap[desiredVarModality] =
327  _insertInternalNode(sonDB, _nodeVarMap[currentNodeId], grandSonsMap);
328  }
329 
330  // Finally we clean the old remaining nodes
331  for (Idx currentVarModality = 0;
332  currentVarModality < _nodeVarMap[currentNodeId]->domainSize();
333  ++currentVarModality) {
334  _removeNode(_nodeSonsMap[currentNodeId][currentVarModality]);
335  }
336 
337  // We suppress the old sons map and remap to the new one
338  SOA_DEALLOCATE(_nodeSonsMap[currentNodeId],
339  sizeof(NodeId) * _nodeVarMap[currentNodeId]->domainSize());
340  _nodeSonsMap[currentNodeId] = sonsMap;
341 
342  _chgNodeBoundVar(currentNodeId, desiredVar);
343  }
344 
345 
346  // ############################################################################
353  // ############################################################################
354  template < TESTNAME AttributeSelection, bool isScalar >
357  const DiscreteVariable* boundVar) {
358  NodeId newNodeId = _model.addNode();
359  _nodeVarMap.insert(newNodeId, boundVar);
360  _nodeId2Database.insert(newNodeId, nDB);
361  _var2Node[boundVar]->addLink(newNodeId);
362 
363  _needUpdate = true;
364 
365  return newNodeId;
366  }
367 
368 
369  // ############################################################################
377  // ############################################################################
378  template < TESTNAME AttributeSelection, bool isScalar >
379  NodeId
382  const DiscreteVariable* boundVar,
383  NodeId* sonsMap) {
384  NodeId newNodeId = this->_insertNode(nDB, boundVar);
385  _nodeSonsMap.insert(newNodeId, sonsMap);
386  return newNodeId;
387  }
388 
389 
390  // ############################################################################
398  // ############################################################################
399  template < TESTNAME AttributeSelection, bool isScalar >
402  const DiscreteVariable* boundVar,
403  Set< const Observation* >* obsSet) {
404  NodeId newNodeId = this->_insertNode(nDB, boundVar);
405  _leafDatabase.insert(newNodeId, obsSet);
406  return newNodeId;
407  }
408 
409 
410  // ############################################################################
416  // ############################################################################
417  template < TESTNAME AttributeSelection, bool isScalar >
419  NodeId currentNodeId, const DiscreteVariable* desiredVar) {
420  if (_nodeVarMap[currentNodeId] == desiredVar) return;
421 
422  _var2Node[_nodeVarMap[currentNodeId]]->searchAndRemoveLink(currentNodeId);
423  _var2Node[desiredVar]->addLink(currentNodeId);
424  _nodeVarMap[currentNodeId] = desiredVar;
425 
426  if (_nodeVarMap[currentNodeId] != _value
427  && _leafDatabase.exists(currentNodeId)) {
428  delete _leafDatabase[currentNodeId];
429  _leafDatabase.erase(currentNodeId);
430  }
431 
432  if (_nodeVarMap[currentNodeId] == _value
433  && !_leafDatabase.exists(currentNodeId)) {
434  _leafDatabase.insert(currentNodeId, new Set< const Observation* >());
435  }
436 
437  _needUpdate = true;
438  }
439 
440 
441  // ############################################################################
446  // ############################################################################
447  template < TESTNAME AttributeSelection, bool isScalar >
449  NodeId currentNodeId) {
450  // Retriat de l'id
451  _model.eraseNode(currentNodeId);
452 
453  // Retrait du vecteur fils
454  if (_nodeSonsMap.exists(currentNodeId)) {
455  SOA_DEALLOCATE(_nodeSonsMap[currentNodeId],
456  sizeof(NodeId) * _nodeVarMap[currentNodeId]->domainSize());
457  _nodeSonsMap.erase(currentNodeId);
458  }
459 
460  if (_leafDatabase.exists(currentNodeId)) {
461  delete _leafDatabase[currentNodeId];
462  _leafDatabase.erase(currentNodeId);
463  }
464 
465  // Retrait de la variable
466  _var2Node[_nodeVarMap[currentNodeId]]->searchAndRemoveLink(currentNodeId);
467  _nodeVarMap.erase(currentNodeId);
468 
469  // Retrait du NodeDatabase
470  delete _nodeId2Database[currentNodeId];
471  _nodeId2Database.erase(currentNodeId);
472 
473  _needUpdate = true;
474  }
475 } // namespace gum
void __assumeValue(const Observation *obs)
Get value assumed by studied variable for current observation.
Useful macros for maths.
virtual void _updateNodeWithObservation(const Observation *newObs, NodeId currentNodeId)
Will update internal graph&#39;s NodeDatabase of given node with the new observation. ...
HashTable< NodeId, NodeId *> _nodeSonsMap
A table giving for any node a table mapping to its son idx is the modality of associated variable...
Priority queues in which the same element can appear several times.
Provides basic types used in aGrUM.
HashTable< const DiscreteVariable *, LinkedList< NodeId > *> _var2Node
Associates to any variable the list of all nodes associated to this variable.
IncrementalGraphLearner(MultiDimFunctionGraph< double > *target, Set< const DiscreteVariable * > attributesSet, const DiscreteVariable *learnVariable)
Default constructor.
Set< const DiscreteVariable *> _setOfVars
bool empty() const noexcept
Indicates whether the set is the empty set.
Definition: set_tpl.h:704
HashTable< NodeId, NodeDatabase< AttributeSelection, isScalar > *> _nodeId2Database
This hashtable binds every node to an associated NodeDatabase which handles every observation that co...
Base class for discrete random variable.
void _updateNode(NodeId nody, Set< const DiscreteVariable * > &bestVars)
From the given sets of node, selects randomly one and installs it on given node.
const iterator_safe & endSafe() noexcept
Returns the safe iterator pointing to the end of the hashtable.
Safe iterators for the Set classDevelopers may consider using Set<x>::iterator_safe instead of SetIte...
Definition: set.h:808
virtual NodeId _insertInternalNode(NodeDatabase< AttributeSelection, isScalar > *nDB, const DiscreteVariable *boundVar, NodeId *sonsMap)
inserts a new internal node in internal graph
Idx __branchObs(const Observation *obs, const DiscreteVariable *var)
Seek modality assumed in obs for given var.
<agrum/FMDP/learning/datastructure/incrementalGraphLearner>
virtual ~IncrementalGraphLearner()
Default destructor.
void erase(const Key &key)
Removes a given element from the hash table.
virtual NodeId _insertNode(NodeDatabase< AttributeSelection, isScalar > *nDB, const DiscreteVariable *boundVar)
inserts a new node in internal graph
#define SOA_DEALLOCATE(x, y)
virtual void _convertNode2Leaf(NodeId)
Turns the given node into a leaf if not already so.
bool exists(const Key &key) const
Checks whether there exists an element with a given key in the hashtable.
Base class for discrete random variable.
void __clearValue()
Template function dispatcher.
gum is the global namespace for all aGrUM entities
Definition: agrum.h:25
virtual NodeId _insertLeafNode(NodeDatabase< AttributeSelection, isScalar > *nDB, const DiscreteVariable *boundVar, Set< const Observation * > *obsSet)
inserts a new leaf node in internal graohs
virtual NodeId addNode()
insert a new node and return its id
Headers of the ChiSquare class.
Representation of a setA Set is a structure that contains arbitrary elements.
Definition: set.h:162
virtual Size domainSize() const =0
bool exists(const Key &k) const
Indicates whether a given elements belong to the set.
Definition: set_tpl.h:604
virtual void addObservation(const Observation *obs)
Inserts a new observation.
const const_iterator_safe & cendSafe() const noexcept
The usual safe end iterator to parse the set.
Definition: set_tpl.h:507
HashTable< NodeId, Set< const Observation *> *> _leafDatabase
This hashtable binds to every leaf an associated set of all hte observations compatible with it...
virtual void _transpose(NodeId, const DiscreteVariable *)
Installs given variable to the given node, ensuring that the variable is not present in its subtree...
virtual void _removeNode(NodeId removedNodeId)
Removes a node from the internal graph.
void addObservation(const Observation *)
Nb observation taken into account by this instance.
const_iterator_safe cbeginSafe() const
The usual safe begin iterator to parse the set.
Definition: set_tpl.h:492
Headers of the interface specifying functions to be implemented by any incremental learner...
Chain list allocated using the SmallObjectAllocator.
Definition: link.h:131
virtual void _chgNodeBoundVar(NodeId chgedNodeId, const DiscreteVariable *desiredVar)
Changes the associated variable of a node.
iterator_safe beginSafe()
Returns the safe iterator pointing to the beginning of the hashtable.
NodeId _root
The root of the ordered tree.
Size Idx
Type for indexes.
Definition: types.h:50
virtual void updateVar(const DiscreteVariable *)
If a new modality appears to exists for given variable, call this method to turn every associated nod...
NodeGraphPart _model
The source of nodeId.
Size size() const noexcept
Returns the number of elements in the set.
Definition: set_tpl.h:698
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
HashTable< NodeId, const DiscreteVariable *> _nodeVarMap
Gives for any node its associated variable.
Size NodeId
Type for node ids.
Definition: graphElements.h:97
void insert(const Key &k)
Inserts a new element into the set.
Definition: set_tpl.h:610
virtual void eraseNode(const NodeId id)
erase the node with the given id
<agrum/FMDP/learning/datastructure/nodeDatabase.h>
Definition: nodeDatabase.h:55
#define SOA_ALLOCATE(x)