aGrUM  0.16.0
incrementalGraphLearner_tpl.h
Go to the documentation of this file.
1 
29 // =======================================================
30 #include <queue>
31 // =======================================================
32 #include <agrum/core/math/math.h>
34 #include <agrum/core/types.h>
35 // =======================================================
38 // =======================================================
40 // =======================================================
41 
42 namespace gum {
43 
44  // ============================================================================
46  // ============================================================================
47 
48  // ############################################################################
59  // ############################################################################
60  template < TESTNAME AttributeSelection, bool isScalar >
64  const DiscreteVariable* value) :
65  _target(target),
66  _setOfVars(varList), _value(value) {
67  GUM_CONSTRUCTOR(IncrementalGraphLearner);
68 
69  for (auto varIter = _setOfVars.cbeginSafe(); varIter != _setOfVars.cendSafe();
70  ++varIter)
71  _var2Node.insert(*varIter, new LinkedList< NodeId >());
72  _var2Node.insert(_value, new LinkedList< NodeId >());
73 
74  _model.addNode();
75  this->_root = _insertLeafNode(
77  _value,
79  }
80 
81 
82  // ############################################################################
84  // ############################################################################
85  template < TESTNAME AttributeSelection, bool isScalar >
86  IncrementalGraphLearner< AttributeSelection,
88  for (auto nodeIter = _nodeId2Database.beginSafe();
89  nodeIter != _nodeId2Database.endSafe();
90  ++nodeIter)
91  delete nodeIter.val();
92 
93  for (auto nodeIter = _nodeSonsMap.beginSafe();
94  nodeIter != _nodeSonsMap.endSafe();
95  ++nodeIter)
96  SOA_DEALLOCATE(nodeIter.val(),
97  sizeof(NodeId) * _nodeVarMap[nodeIter.key()]->domainSize());
98 
99  for (auto varIter = _var2Node.beginSafe(); varIter != _var2Node.endSafe();
100  ++varIter)
101  delete varIter.val();
102 
103  for (auto nodeIter = _leafDatabase.beginSafe();
104  nodeIter != _leafDatabase.endSafe();
105  ++nodeIter)
106  delete nodeIter.val();
107 
108  __clearValue();
109 
110  GUM_DESTRUCTOR(IncrementalGraphLearner);
111  }
112 
113 
114  // ============================================================================
116  // ============================================================================
117 
118  // ############################################################################
123  // ############################################################################
124  template < TESTNAME AttributeSelection, bool isScalar >
126  const Observation* newObs) {
127  __assumeValue(newObs);
128 
129  // The we go across the tree
130  NodeId currentNodeId = _root;
131 
132  while (_nodeSonsMap.exists(currentNodeId)) {
133  // On each encountered node, we update the database
134  _updateNodeWithObservation(newObs, currentNodeId);
135 
136  // The we select the next to go throught
137  currentNodeId =
138  _nodeSonsMap[currentNodeId]
139  [__branchObs(newObs, _nodeVarMap[currentNodeId])];
140  }
141 
142  // On final insertion into the leave we reach
143  _updateNodeWithObservation(newObs, currentNodeId);
144  _leafDatabase[currentNodeId]->insert(newObs);
145  }
146 
147 
148  // ============================================================================
150  // ============================================================================
151 
152  // ############################################################################
156  // ############################################################################
157  template < TESTNAME AttributeSelection, bool isScalar >
159  const DiscreteVariable* var) {
160  Link< NodeId >* nodIter = _var2Node[var]->list();
161  Link< NodeId >* nni = nullptr;
162  while (nodIter) {
163  nni = nodIter->nextLink();
164  _convertNode2Leaf(nodIter->element());
165  nodIter = nni;
166  }
167  }
168 
169 
170  // ############################################################################
178  // ############################################################################
179  template < TESTNAME AttributeSelection, bool isScalar >
181  NodeId updatedNode, Set< const DiscreteVariable* >& varsOfInterest) {
182  // If this node has no interesting variable, we turn it into a leaf
183  if (varsOfInterest.empty()) {
184  _convertNode2Leaf(updatedNode);
185  return;
186  }
187 
188  // If this node has already one of the best variable intalled as test, we
189  // move on
190  if (_nodeVarMap.exists(updatedNode)
191  && varsOfInterest.exists(_nodeVarMap[updatedNode])) {
192  return;
193  }
194 
195  // In any other case we have to install variable as best test
196  Idx randy = (Idx)(std::rand() / RAND_MAX) * varsOfInterest.size(), basc = 0;
197  SetConstIteratorSafe< const DiscreteVariable* > varIter;
198  for (varIter = varsOfInterest.cbeginSafe(), basc = 0;
199  varIter != varsOfInterest.cendSafe() && basc < randy;
200  ++varIter, basc++)
201  ;
202 
203  _transpose(updatedNode, *varIter);
204  }
205 
206 
207  // ############################################################################
209  // ############################################################################
210  template < TESTNAME AttributeSelection, bool isScalar >
212  NodeId currentNodeId) {
213  if (_nodeVarMap[currentNodeId] != _value) {
214  _leafDatabase.insert(currentNodeId, new Set< const Observation* >());
215 
216  // Resolving potential sons issue
217  for (Idx modality = 0; modality < _nodeVarMap[currentNodeId]->domainSize();
218  ++modality) {
219  NodeId sonId = _nodeSonsMap[currentNodeId][modality];
220  _convertNode2Leaf(sonId);
221  (*_leafDatabase[currentNodeId]) =
222  (*_leafDatabase[currentNodeId]) + *(_leafDatabase[sonId]);
223  _removeNode(sonId);
224  }
225 
226  SOA_DEALLOCATE(_nodeSonsMap[currentNodeId],
227  sizeof(NodeId) * _nodeVarMap[currentNodeId]->domainSize());
228  _nodeSonsMap.erase(currentNodeId);
229 
230  _chgNodeBoundVar(currentNodeId, _value);
231  }
232  }
233 
234 
235  // ############################################################################
238  // ############################################################################
239  template < TESTNAME AttributeSelection, bool isScalar >
241  NodeId currentNodeId, const DiscreteVariable* desiredVar) {
242  // **************************************************************************************
243  // Si le noeud courant contient déjà la variable qu'on souhaite lui amener
244  // Il n'y a rien à faire
245  if (_nodeVarMap[currentNodeId] == desiredVar) { return; }
246 
247  // **************************************************************************************
248  // Si le noeud courant est terminal,
249  // Il faut artificiellement insérer un noeud liant à la variable
250  if (_nodeVarMap[currentNodeId] == _value) {
251  // We turned this leaf into an internal node.
252  // This mean that we'll need to install children leaves for each value of
253  // desiredVar
254 
255  // First We must prepare these new leaves NodeDatabases and Sets<const
256  // Observation*>
260  * desiredVar->domainSize()));
261  Set< const Observation* >** obsetMap =
262  static_cast< Set< const Observation* >** >(SOA_ALLOCATE(
263  sizeof(Set< const Observation* >*) * desiredVar->domainSize()));
264  for (Idx modality = 0; modality < desiredVar->domainSize(); ++modality) {
265  dbMap[modality] =
267  obsetMap[modality] = new Set< const Observation* >();
268  }
270  _leafDatabase[currentNodeId]->beginSafe();
271  _leafDatabase[currentNodeId]->endSafe() != obsIter;
272  ++obsIter) {
273  dbMap[__branchObs(*obsIter, desiredVar)]->addObservation(*obsIter);
274  obsetMap[__branchObs(*obsIter, desiredVar)]->insert(*obsIter);
275  }
276 
277  // Then we can install each new leaves (and put in place the sonsMap)
278  NodeId* sonsMap = static_cast< NodeId* >(
279  SOA_ALLOCATE(sizeof(NodeId) * desiredVar->domainSize()));
280  for (Idx modality = 0; modality < desiredVar->domainSize(); ++modality)
281  sonsMap[modality] =
282  _insertLeafNode(dbMap[modality], _value, obsetMap[modality]);
283 
284  // Some necessary clean up
285  SOA_DEALLOCATE(dbMap,
287  * desiredVar->domainSize());
289  obsetMap, sizeof(Set< const Observation* >*) * desiredVar->domainSize());
290 
291  // And finally we can turn the node into an internal node associated to
292  // desiredVar
293  _chgNodeBoundVar(currentNodeId, desiredVar);
294  _nodeSonsMap.insert(currentNodeId, sonsMap);
295 
296  return;
297  }
298 
299  // *************************************************************************************
300  // Remains the general case where currentNodeId is an internal node.
301 
302  // First we ensure that children node use desiredVar as variable
303  for (Idx modality = 0; modality < _nodeVarMap[currentNodeId]->domainSize();
304  ++modality)
305  _transpose(_nodeSonsMap[currentNodeId][modality], desiredVar);
306 
307  // Sequence<NodeDatabase<AttributeSelection, isScalar>*>
308  // sonsNodeDatabase =
309  // _nodeId2Database[currentNodeId]->splitOnVar(desiredVar);
310  NodeId* sonsMap = static_cast< NodeId* >(
311  SOA_ALLOCATE(sizeof(NodeId) * desiredVar->domainSize()));
312 
313  // Then we create the new mapping
314  for (Idx desiredVarModality = 0; desiredVarModality < desiredVar->domainSize();
315  ++desiredVarModality) {
316  NodeId* grandSonsMap = static_cast< NodeId* >(
317  SOA_ALLOCATE(sizeof(NodeId) * _nodeVarMap[currentNodeId]->domainSize()));
320  for (Idx currentVarModality = 0;
321  currentVarModality < _nodeVarMap[currentNodeId]->domainSize();
322  ++currentVarModality) {
323  grandSonsMap[currentVarModality] =
324  _nodeSonsMap[_nodeSonsMap[currentNodeId][currentVarModality]]
325  [desiredVarModality];
326  sonDB->operator+=((*_nodeId2Database[grandSonsMap[currentVarModality]]));
327  }
328 
329  sonsMap[desiredVarModality] =
330  _insertInternalNode(sonDB, _nodeVarMap[currentNodeId], grandSonsMap);
331  }
332 
333  // Finally we clean the old remaining nodes
334  for (Idx currentVarModality = 0;
335  currentVarModality < _nodeVarMap[currentNodeId]->domainSize();
336  ++currentVarModality) {
337  _removeNode(_nodeSonsMap[currentNodeId][currentVarModality]);
338  }
339 
340  // We suppress the old sons map and remap to the new one
341  SOA_DEALLOCATE(_nodeSonsMap[currentNodeId],
342  sizeof(NodeId) * _nodeVarMap[currentNodeId]->domainSize());
343  _nodeSonsMap[currentNodeId] = sonsMap;
344 
345  _chgNodeBoundVar(currentNodeId, desiredVar);
346  }
347 
348 
349  // ############################################################################
356  // ############################################################################
357  template < TESTNAME AttributeSelection, bool isScalar >
360  const DiscreteVariable* boundVar) {
361  NodeId newNodeId = _model.addNode();
362  _nodeVarMap.insert(newNodeId, boundVar);
363  _nodeId2Database.insert(newNodeId, nDB);
364  _var2Node[boundVar]->addLink(newNodeId);
365 
366  _needUpdate = true;
367 
368  return newNodeId;
369  }
370 
371 
372  // ############################################################################
380  // ############################################################################
381  template < TESTNAME AttributeSelection, bool isScalar >
382  NodeId
385  const DiscreteVariable* boundVar,
386  NodeId* sonsMap) {
387  NodeId newNodeId = this->_insertNode(nDB, boundVar);
388  _nodeSonsMap.insert(newNodeId, sonsMap);
389  return newNodeId;
390  }
391 
392 
393  // ############################################################################
401  // ############################################################################
402  template < TESTNAME AttributeSelection, bool isScalar >
405  const DiscreteVariable* boundVar,
406  Set< const Observation* >* obsSet) {
407  NodeId newNodeId = this->_insertNode(nDB, boundVar);
408  _leafDatabase.insert(newNodeId, obsSet);
409  return newNodeId;
410  }
411 
412 
413  // ############################################################################
419  // ############################################################################
420  template < TESTNAME AttributeSelection, bool isScalar >
422  NodeId currentNodeId, const DiscreteVariable* desiredVar) {
423  if (_nodeVarMap[currentNodeId] == desiredVar) return;
424 
425  _var2Node[_nodeVarMap[currentNodeId]]->searchAndRemoveLink(currentNodeId);
426  _var2Node[desiredVar]->addLink(currentNodeId);
427  _nodeVarMap[currentNodeId] = desiredVar;
428 
429  if (_nodeVarMap[currentNodeId] != _value
430  && _leafDatabase.exists(currentNodeId)) {
431  delete _leafDatabase[currentNodeId];
432  _leafDatabase.erase(currentNodeId);
433  }
434 
435  if (_nodeVarMap[currentNodeId] == _value
436  && !_leafDatabase.exists(currentNodeId)) {
437  _leafDatabase.insert(currentNodeId, new Set< const Observation* >());
438  }
439 
440  _needUpdate = true;
441  }
442 
443 
444  // ############################################################################
449  // ############################################################################
450  template < TESTNAME AttributeSelection, bool isScalar >
452  NodeId currentNodeId) {
453  // Retriat de l'id
454  _model.eraseNode(currentNodeId);
455 
456  // Retrait du vecteur fils
457  if (_nodeSonsMap.exists(currentNodeId)) {
458  SOA_DEALLOCATE(_nodeSonsMap[currentNodeId],
459  sizeof(NodeId) * _nodeVarMap[currentNodeId]->domainSize());
460  _nodeSonsMap.erase(currentNodeId);
461  }
462 
463  if (_leafDatabase.exists(currentNodeId)) {
464  delete _leafDatabase[currentNodeId];
465  _leafDatabase.erase(currentNodeId);
466  }
467 
468  // Retrait de la variable
469  _var2Node[_nodeVarMap[currentNodeId]]->searchAndRemoveLink(currentNodeId);
470  _nodeVarMap.erase(currentNodeId);
471 
472  // Retrait du NodeDatabase
473  delete _nodeId2Database[currentNodeId];
474  _nodeId2Database.erase(currentNodeId);
475 
476  _needUpdate = true;
477  }
478 } // namespace gum
void __assumeValue(const Observation *obs)
Get value assumed by studied variable for current observation.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
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...
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
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:707
HashTable< NodeId, NodeDatabase< AttributeSelection, isScalar > *> _nodeId2Database
This hashtable binds every node to an associated NodeDatabase which handles every observation that co...
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
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:811
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.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
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
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Representation of a setA Set is a structure that contains arbitrary elements.
Definition: set.h:165
virtual Size domainSize() const =0
bool exists(const Key &k) const
Indicates whether a given elements belong to the set.
Definition: set_tpl.h:607
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:510
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:495
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Chain list allocated using the SmallObjectAllocator.
Definition: link.h:134
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:53
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:701
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:98
void insert(const Key &k)
Inserts a new element into the set.
Definition: set_tpl.h:613
virtual void eraseNode(const NodeId id)
erase the node with the given id
<agrum/FMDP/learning/datastructure/nodeDatabase.h>
Definition: nodeDatabase.h:58
#define SOA_ALLOCATE(x)