aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
regress_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by 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 Class used to compute the operation between two decision diagrams
25  *
26  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
27  * @author Pierre-Henri WUILLEMIN(@LIP6) and Jean-Christophe MAGNAN and Christophe
28  * GONZALES(@AMU)
29  */
30 
31 #include <agrum/tools/multidim/utils/FunctionGraphUtilities/internalNode.h>
32 #include <agrum/tools/multidim/utils/FunctionGraphUtilities/operators/regress.h>
33 
34 #define ALLOCATE(x) SmallObjectAllocator::instance().allocate(x)
35 #define DEALLOCATE(x, y) SmallObjectAllocator::instance().deallocate(x, y)
36 
37 namespace gum {
38 
39  template < typename GUM_SCALAR,
40  template < typename >
41  class COMBINEOPERATOR,
42  template < typename >
43  class PROJECTOPERATOR,
44  template < typename >
45  class TerminalNodePolicy >
49  const Set< const DiscreteVariable* >* primedVars,
51  const GUM_SCALAR neutral) :
52  _DG1_(DG1),
54  _DG1InstantiationNeeded_(DG1->realSize(), true, false),
55  _DG2InstantiationNeeded_(DG2->realSize(), true, false) {
58  _nbVar_ = 0;
59  _default_ = nullptr;
62  }
63 
64  template < typename GUM_SCALAR,
65  template < typename >
66  class COMBINEOPERATOR,
67  template < typename >
68  class PROJECTOPERATOR,
69  template < typename >
70  class TerminalNodePolicy >
73 
76  ++instIter)
77  DEALLOCATE(instIter.val(), sizeof(short int) * _nbVar_);
78 
81  ++instIter)
82  DEALLOCATE(instIter.val(), sizeof(short int) * _nbVar_);
83 
84  if (_nbVar_ != 0) DEALLOCATE(_default_, sizeof(short int) * _nbVar_);
85  }
86 
87 
88  // This function is the main function. To be call every time an operation
89  // between the two given Function Graphs is required
90  template < typename GUM_SCALAR,
91  template < typename >
92  class COMBINEOPERATOR,
93  template < typename >
94  class PROJECTOPERATOR,
95  template < typename >
96  class TerminalNodePolicy >
102 
103  Idx* varInst = nullptr;
104  if (_nbVar_ != 0) {
105  varInst = static_cast< Idx* >(ALLOCATE(sizeof(Idx) * _nbVar_));
106  for (Idx i = 0; i < _nbVar_; i++)
107  varInst[i] = (Idx)0;
108  }
109 
113 
114  NodeId root = _compute_(conti, (Idx)0 - 1);
116 
117  if (_nbVar_ != 0) DEALLOCATE(varInst, sizeof(Idx) * _nbVar_);
118 
120 
121  return _rd_;
122  }
123 
124  // This function computes an efficient order for the final decision diagrams.
125  // Its main criterion to do so is the number of
126  // re-exploration to be done
127  template < typename GUM_SCALAR,
128  template < typename >
129  class COMBINEOPERATOR,
130  template < typename >
131  class PROJECTOPERATOR,
132  template < typename >
133  class TerminalNodePolicy >
138 
139  while (fite != _DG1_->variablesSequence().endSafe()
140  && site != _DG2_->variablesSequence().endSafe()) {
141  // Test : if var from first order is already in final order
142  // we move onto the next one
143  if (_rd_->variablesSequence().exists(*fite)) {
144  ++fite;
145  continue;
146  }
147 
148  // Test : if var from second order is already in final order
149  // we move onto the next one
150  if (_rd_->variablesSequence().exists(*site)) {
151  ++site;
152  continue;
153  }
154 
155  // Test : is current var of the first order present in the second order.
156  // if not we add it to final order
158  _rd_->add(**fite);
159  ++fite;
160  continue;
161  }
162 
163  // Test : is current var of the second order present in the first order.
164  // if not we add it to final order
166  _rd_->add(**site);
167  ++site;
168  continue;
169  }
170 
171  // Test : is current var of the second order present in the first order.
172  // if not we add it to final order
173  if (*fite == *site) {
174  _rd_->add(**fite);
175  ++fite;
176  ++site;
177  continue;
178  }
179 
180  // Test : if chosing first order var cost less in terms or re exploration,
181  // we chose it
182  _rd_->add(**fite);
183  ++fite;
184  }
185 
186  // Whenever an iterator has finished its sequence,
187  // the other may still be in the middle of its one.
188  // Hence, this part ensures that any variables remaining
189  // will be added to the final sequence if needed.
190  if (fite == _DG1_->variablesSequence().endSafe()) {
191  for (; site != _DG2_->variablesSequence().endSafe(); ++site)
192  if (!_rd_->variablesSequence().exists(*site)) _rd_->add(**site);
193  } else {
194  for (; fite != _DG1_->variablesSequence().endSafe(); ++fite)
195  if (!_rd_->variablesSequence().exists(*fite)) _rd_->add(**fite);
196  }
197 
198  // Various initialization needed now that we have a bigger picture
200 
201  if (_nbVar_ != 0) {
202  _default_ = static_cast< short int* >(ALLOCATE(sizeof(short int) * _nbVar_));
203  for (Idx i = 0; i < _nbVar_; i++)
204  _default_[i] = (short int)0;
205  }
206  }
207 
208  // This function computes for every nodes if any retrograde variable is
209  // present below
210  template < typename GUM_SCALAR,
211  template < typename >
212  class COMBINEOPERATOR,
213  template < typename >
214  class PROJECTOPERATOR,
215  template < typename >
216  class TerminalNodePolicy >
219  HashTable< NodeId, short int* >& dgInstNeed) {
220  HashTable< NodeId, short int* > nodesVarDescendant;
221  Size tableSize = Size(_nbVar_ * sizeof(short int));
222 
223  for (auto varIter = dg->variablesSequence().rbeginSafe();
225  --varIter) {
227 
228  const Link< NodeId >* nodeIter = dg->varNodeListe(*varIter)->list();
229  while (nodeIter != nullptr) {
230  short int* instantiationNeeded = static_cast< short int* >(ALLOCATE(tableSize));
232  short int* varDescendant = static_cast< short int* >(ALLOCATE(tableSize));
234  for (Idx j = 0; j < _nbVar_; j++) {
235  instantiationNeeded[j] = (short int)0;
236  varDescendant[j] = (short int)0;
237  }
238 
239 
240  varDescendant[varPos] = (short int)1;
241  for (Idx modality = 0; modality < dg->node(nodeIter->element())->nbSons(); ++modality) {
243  short int* sonVarDescendant
245  for (Idx varIdx = 0; varIdx < _nbVar_; varIdx++) {
247  if (varDescendant[varIdx] && varIdx < varPos)
248  instantiationNeeded[varIdx] = (short int)1;
249  }
250  }
251  }
253  }
254  }
255 
256  for (auto varIter = dg->variablesSequence().beginSafe();
258  ++varIter) {
259  const Link< NodeId >* nodeIter = dg->varNodeListe(*varIter)->list();
260  while (nodeIter != nullptr) {
261  for (Idx modality = 0; modality < dg->node(nodeIter->element())->nbSons(); ++modality) {
263  if (!dg->isTerminalNode(sonId)) {
264  for (Idx varIdx = 0; varIdx < _nbVar_; ++varIdx) {
266  dgInstNeed[sonId][varIdx] = (short int)1;
267  }
268  }
269  }
270  }
272  }
273  }
274 
275  for (HashTableIterator< NodeId, short int* > it = nodesVarDescendant.begin();
277  ++it) {
279  }
280 
282  }
283 
284  // A key is used for prunning uneccesary operations since once a node has been
285  // visited in a given context, there's no use to revisit him,
286  // the result will be the same node, so we just have to do an association
287  // context - node.
288  // The context consists in :
289  // _ Leader node we are visiting.
290  // _ Follower node we are visiting.
291  // _ For all retrograde variables, if it has been instanciated
292  // before, current modality instanciated, meaning :
293  // _ 0 means the variable hasn't be instanciated yet,
294  // _ From 1 to domainSize + 1 means that current modality
295  // index of variable is value - 1,
296  // _ domainSize + 2 means variable is on default mode.
297  // A key - node association is made each time we create a node in resulting
298  // diagram.
299  // Since GUM_MULTI_DIM_DECISION_DIAGRAM_RECUR_FUNCTION is a corner step in
300  // algorithm ( meaning each time we explore a node we go trought
301  // this function ), check only have to be at the beginning of that function.
302  template < typename GUM_SCALAR,
303  template < typename >
304  class COMBINEOPERATOR,
305  template < typename >
306  class PROJECTOPERATOR,
307  template < typename >
308  class TerminalNodePolicy >
309  INLINE NodeId
313  NodeId newNode = 0;
314 
315  // If both current nodes are terminal,
316  // we only have to compute the resulting value
319  // We have to compute new valueand we insert a new node in diagram with
320  // this value, ...
326  return _rd_->manager()->addTerminalNode(newVal);
327  }
328 
329  // If not,
330  // we'll have to do some exploration
331 
332  // First we ensure that we hadn't already visit this pair of node under hte
333  // same circumstances
336  : _default_;
339  ? _nbVar_
343  : _default_;
346  ? _nbVar_
348 
349  short int* instNeeded = static_cast< short int* >(ALLOCATE(sizeof(short int) * _nbVar_));
350 
351  for (Idx i = 0; i < _nbVar_; i++) {
353  }
354 
356 
358  DEALLOCATE(instNeeded, sizeof(short int) * _nbVar_);
359 
361  }
362 
363  // ====================================================
364 
366 
368  NodeId leadNodeId = 0;
370  typedef void (O4DGContext::*SetNodeFunction)(const NodeId&);
371  SetNodeFunction leadFunction = nullptr;
372 
373  bool sameVar = false;
374 
377  // If var associated to current node has already been instanciated, we
378  // have to jump it
381 
386 
387  DEALLOCATE(instNeeded, sizeof(short int) * _nbVar_);
388 
389  return newNode;
390  }
391 
392  leaddg = _DG1_;
396  }
397 
400  // If var associated to current node has already been instanciated, we
401  // have to jump it
404 
409 
410  DEALLOCATE(instNeeded, sizeof(short int) * _nbVar_);
411 
412  return newNode;
413  }
414 
415  if (leadVarPos == dg2CurrentVarPos) { sameVar = true; }
416 
418  leaddg = _DG2_;
422  }
423  }
424 
425  // ====================================================
426  // Anticipated Exploration
427 
428  // Before exploring nodes, we have to ensure that every anticipated
429  // exploration is done
430  for (Idx varPos = lastInstVarPos + 1; varPos < leadVarPos; ++varPos) {
431  if (instNeeded[varPos]) {
433  NodeId* sonsIds = static_cast< NodeId* >(ALLOCATE(sizeof(NodeId) * curVar->domainSize()));
434 
435  for (Idx modality = 0; modality < curVar->domainSize(); modality++) {
437 
439  }
440 
442 
447 
448  DEALLOCATE(instNeeded, sizeof(short int) * _nbVar_);
449 
450  return newNode;
451  }
452  }
453 
454  // ====================================================
455  // Terminal Exploration
456  if (sameVar && _DG1_->node(origDG1)->nodeVar() == _targetVar_) {
464  DEALLOCATE(instNeeded, sizeof(short int) * _nbVar_);
465  return newNode;
466  }
467  if (_DG1_->isTerminalNode(origDG1)) {
468  if (_DG2_->node(origDG2)->nodeVar() == _targetVar_) {
476  DEALLOCATE(instNeeded, sizeof(short int) * _nbVar_);
477  return newNode;
478  }
479  } else {
485  _DG2_->nodeValue(origDG2)));
488  DEALLOCATE(instNeeded, sizeof(short int) * _nbVar_);
489  return newNode;
490  }
491  }
492 
493  // ====================================================
494  // Normal Exploration
495 
496  // If only one of the current node is terminal,
497  // we have to pursue deeper on the other diagram
498  if (sameVar) {
499  // If so - meaning it's the same variable - we have to go
500  // down on both
503 
506  NodeId* sonsIds = static_cast< NodeId* >(ALLOCATE(sizeof(NodeId) * curVar->domainSize()));
507 
508  for (Idx modality = 0; modality < curVar->domainSize(); modality++) {
512 
514  }
515 
517 
522 
523  DEALLOCATE(instNeeded, sizeof(short int) * _nbVar_);
524 
525  return newNode;
526  }
527  // ====================================================
528  else {
530 
532  NodeId* sonsIds = static_cast< NodeId* >(ALLOCATE(sizeof(NodeId) * curVar->domainSize()));
533 
534  for (Idx modality = 0; modality < curVar->domainSize(); modality++) {
537 
539  }
540 
542 
547 
548  DEALLOCATE(instNeeded, sizeof(short int) * _nbVar_);
549 
550  return newNode;
551  }
552  }
553 
554 } // namespace gum
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643
#define DEALLOCATE(x, y)
#define ALLOCATE(x)