aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
regress_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 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 >
46  INLINE
50  const Set< const DiscreteVariable* >* primedVars,
52  const GUM_SCALAR neutral) :
53  DG1__(DG1),
55  DG1InstantiationNeeded__(DG1->realSize(), true, false),
56  DG2InstantiationNeeded__(DG2->realSize(), true, false) {
60  nbVar__ = 0;
61  default__ = nullptr;
64  }
65 
66  template < typename GUM_SCALAR,
67  template < typename >
68  class COMBINEOPERATOR,
69  template < typename >
70  class PROJECTOPERATOR,
71  template < typename >
72  class TerminalNodePolicy >
73  INLINE
75  ~Regress() {
77 
80  ++instIter)
81  DEALLOCATE(instIter.val(), sizeof(short int) * nbVar__);
82 
85  ++instIter)
86  DEALLOCATE(instIter.val(), sizeof(short int) * nbVar__);
87 
88  if (nbVar__ != 0) DEALLOCATE(default__, sizeof(short int) * nbVar__);
89  }
90 
91 
92  // This function is the main function. To be call every time an operation
93  // between the two given Function Graphs is required
94  template < typename GUM_SCALAR,
95  template < typename >
96  class COMBINEOPERATOR,
97  template < typename >
98  class PROJECTOPERATOR,
99  template < typename >
100  class TerminalNodePolicy >
107 
108  Idx* varInst = nullptr;
109  if (nbVar__ != 0) {
110  varInst = static_cast< Idx* >(ALLOCATE(sizeof(Idx) * nbVar__));
111  for (Idx i = 0; i < nbVar__; i++)
112  varInst[i] = (Idx)0;
113  }
114 
118 
119  NodeId root = compute__(conti, (Idx)0 - 1);
121 
122  if (nbVar__ != 0) DEALLOCATE(varInst, sizeof(Idx) * nbVar__);
123 
125 
126  return rd__;
127  }
128 
129  // This function computes an efficient order for the final decision diagrams.
130  // Its main criterion to do so is the number of
131  // re-exploration to be done
132  template < typename GUM_SCALAR,
133  template < typename >
134  class COMBINEOPERATOR,
135  template < typename >
136  class PROJECTOPERATOR,
137  template < typename >
138  class TerminalNodePolicy >
139  INLINE void
146 
147  while (fite != DG1__->variablesSequence().endSafe()
148  && site != DG2__->variablesSequence().endSafe()) {
149  // Test : if var from first order is already in final order
150  // we move onto the next one
151  if (rd__->variablesSequence().exists(*fite)) {
152  ++fite;
153  continue;
154  }
155 
156  // Test : if var from second order is already in final order
157  // we move onto the next one
158  if (rd__->variablesSequence().exists(*site)) {
159  ++site;
160  continue;
161  }
162 
163  // Test : is current var of the first order present in the second order.
164  // if not we add it to final order
166  && !primedVars__->exists(*fite)) {
167  rd__->add(**fite);
168  ++fite;
169  continue;
170  }
171 
172  // Test : is current var of the second order present in the first order.
173  // if not we add it to final order
175  && !primedVars__->exists(*site)) {
176  rd__->add(**site);
177  ++site;
178  continue;
179  }
180 
181  // Test : is current var of the second order present in the first order.
182  // if not we add it to final order
183  if (*fite == *site) {
184  rd__->add(**fite);
185  ++fite;
186  ++site;
187  continue;
188  }
189 
190  // Test : if chosing first order var cost less in terms or re exploration,
191  // we chose it
192  rd__->add(**fite);
193  ++fite;
194  }
195 
196  // Whenever an iterator has finished its sequence,
197  // the other may still be in the middle of its one.
198  // Hence, this part ensures that any variables remaining
199  // will be added to the final sequence if needed.
200  if (fite == DG1__->variablesSequence().endSafe()) {
201  for (; site != DG2__->variablesSequence().endSafe(); ++site)
202  if (!rd__->variablesSequence().exists(*site)) rd__->add(**site);
203  } else {
204  for (; fite != DG1__->variablesSequence().endSafe(); ++fite)
205  if (!rd__->variablesSequence().exists(*fite)) rd__->add(**fite);
206  }
207 
208  // Various initialization needed now that we have a bigger picture
210 
211  if (nbVar__ != 0) {
212  default__ = static_cast< short int* >(ALLOCATE(sizeof(short int) * nbVar__));
213  for (Idx i = 0; i < nbVar__; i++)
214  default__[i] = (short int)0;
215  }
216  }
217 
218  // This function computes for every nodes if any retrograde variable is
219  // present below
220  template < typename GUM_SCALAR,
221  template < typename >
222  class COMBINEOPERATOR,
223  template < typename >
224  class PROJECTOPERATOR,
225  template < typename >
226  class TerminalNodePolicy >
227  INLINE void
231  HashTable< NodeId, short int* >& dgInstNeed) {
232  HashTable< NodeId, short int* > nodesVarDescendant;
233  Size tableSize = Size(nbVar__ * sizeof(short int));
234 
235  for (auto varIter = dg->variablesSequence().rbeginSafe();
237  --varIter) {
239 
240  const Link< NodeId >* nodeIter = dg->varNodeListe(*varIter)->list();
241  while (nodeIter != nullptr) {
242  short int* instantiationNeeded
243  = static_cast< short int* >(ALLOCATE(tableSize));
245  short int* varDescendant = static_cast< short int* >(ALLOCATE(tableSize));
247  for (Idx j = 0; j < nbVar__; j++) {
248  instantiationNeeded[j] = (short int)0;
249  varDescendant[j] = (short int)0;
250  }
251 
252 
253  varDescendant[varPos] = (short int)1;
254  for (Idx modality = 0; modality < dg->node(nodeIter->element())->nbSons();
255  ++modality) {
257  short int* sonVarDescendant
259  for (Idx varIdx = 0; varIdx < nbVar__; varIdx++) {
261  if (varDescendant[varIdx] && varIdx < varPos)
262  instantiationNeeded[varIdx] = (short int)1;
263  }
264  }
265  }
267  }
268  }
269 
270  for (auto varIter = dg->variablesSequence().beginSafe();
272  ++varIter) {
273  const Link< NodeId >* nodeIter = dg->varNodeListe(*varIter)->list();
274  while (nodeIter != nullptr) {
275  for (Idx modality = 0; modality < dg->node(nodeIter->element())->nbSons();
276  ++modality) {
278  if (!dg->isTerminalNode(sonId)) {
279  for (Idx varIdx = 0; varIdx < nbVar__; ++varIdx) {
282  dgInstNeed[sonId][varIdx] = (short int)1;
283  }
284  }
285  }
286  }
288  }
289  }
290 
291  for (HashTableIterator< NodeId, short int* > it = nodesVarDescendant.begin();
293  ++it) {
295  }
296 
298  }
299 
300  // A key is used for prunning uneccesary operations since once a node has been
301  // visited in a given context, there's no use to revisit him,
302  // the result will be the same node, so we just have to do an association
303  // context - node.
304  // The context consists in :
305  // _ Leader node we are visiting.
306  // _ Follower node we are visiting.
307  // _ For all retrograde variables, if it has been instanciated
308  // before, current modality instanciated, meaning :
309  // _ 0 means the variable hasn't be instanciated yet,
310  // _ From 1 to domainSize + 1 means that current modality
311  // index of variable is value - 1,
312  // _ domainSize + 2 means variable is on default mode.
313  // A key - node association is made each time we create a node in resulting
314  // diagram.
315  // Since GUM_MULTI_DIM_DECISION_DIAGRAM_RECUR_FUNCTION is a corner step in
316  // algorithm ( meaning each time we explore a node we go trought
317  // this function ), check only have to be at the beginning of that function.
318  template < typename GUM_SCALAR,
319  template < typename >
320  class COMBINEOPERATOR,
321  template < typename >
322  class PROJECTOPERATOR,
323  template < typename >
324  class TerminalNodePolicy >
325  INLINE NodeId
328  NodeId newNode = 0;
329 
330  // If both current nodes are terminal,
331  // we only have to compute the resulting value
334  // We have to compute new valueand we insert a new node in diagram with
335  // this value, ...
340  ++targetModa)
342  return rd__->manager()->addTerminalNode(newVal);
343  }
344 
345  // If not,
346  // we'll have to do some exploration
347 
348  // First we ensure that we hadn't already visit this pair of node under hte
349  // same circumstances
350  short int* dg1NeededVar
353  : default__;
355  ? nbVar__
358  short int* dg2NeededVar
361  : default__;
363  ? nbVar__
366 
367  short int* instNeeded
368  = static_cast< short int* >(ALLOCATE(sizeof(short int) * nbVar__));
369 
370  for (Idx i = 0; i < nbVar__; i++) {
372  }
373 
375 
377  DEALLOCATE(instNeeded, sizeof(short int) * nbVar__);
378 
380  }
381 
382  // ====================================================
383 
386 
388  = nullptr;
389  NodeId leadNodeId = 0;
391  typedef void (O4DGContext::*SetNodeFunction)(const NodeId&);
392  SetNodeFunction leadFunction = nullptr;
393 
394  bool sameVar = false;
395 
398  // If var associated to current node has already been instanciated, we
399  // have to jump it
403 
408 
409  DEALLOCATE(instNeeded, sizeof(short int) * nbVar__);
410 
411  return newNode;
412  }
413 
414  leaddg = DG1__;
418  }
419 
422  // If var associated to current node has already been instanciated, we
423  // have to jump it
427 
432 
433  DEALLOCATE(instNeeded, sizeof(short int) * nbVar__);
434 
435  return newNode;
436  }
437 
438  if (leadVarPos == dg2CurrentVarPos) { sameVar = true; }
439 
441  leaddg = DG2__;
445  }
446  }
447 
448  // ====================================================
449  // Anticipated Exploration
450 
451  // Before exploring nodes, we have to ensure that every anticipated
452  // exploration is done
453  for (Idx varPos = lastInstVarPos + 1; varPos < leadVarPos; ++varPos) {
454  if (instNeeded[varPos]) {
456  NodeId* sonsIds = static_cast< NodeId* >(
457  ALLOCATE(sizeof(NodeId) * curVar->domainSize()));
458 
459  for (Idx modality = 0; modality < curVar->domainSize(); modality++) {
461 
463  }
464 
466 
471 
472  DEALLOCATE(instNeeded, sizeof(short int) * nbVar__);
473 
474  return newNode;
475  }
476  }
477 
478  // ====================================================
479  // Terminal Exploration
480  if (sameVar && DG1__->node(origDG1)->nodeVar() == targetVar__) {
483  ++targetModa)
484  newVal = project__(
485  newVal,
490  DEALLOCATE(instNeeded, sizeof(short int) * nbVar__);
491  return newNode;
492  }
493  if (DG1__->isTerminalNode(origDG1)) {
494  if (DG2__->node(origDG2)->nodeVar() == targetVar__) {
497  ++targetModa)
498  newVal = project__(
499  newVal,
504  DEALLOCATE(instNeeded, sizeof(short int) * nbVar__);
505  return newNode;
506  }
507  } else {
508  if (DG1__->node(origDG1)->nodeVar() == targetVar__
512  ++targetModa)
513  newVal = project__(
514  newVal,
516  DG2__->nodeValue(origDG2)));
519  DEALLOCATE(instNeeded, sizeof(short int) * nbVar__);
520  return newNode;
521  }
522  }
523 
524  // ====================================================
525  // Normal Exploration
526 
527  // If only one of the current node is terminal,
528  // we have to pursue deeper on the other diagram
529  if (sameVar) {
530  // If so - meaning it's the same variable - we have to go
531  // down on both
534 
537  NodeId* sonsIds
538  = static_cast< NodeId* >(ALLOCATE(sizeof(NodeId) * curVar->domainSize()));
539 
540  for (Idx modality = 0; modality < curVar->domainSize(); modality++) {
544 
546  }
547 
549 
554 
555  DEALLOCATE(instNeeded, sizeof(short int) * nbVar__);
556 
557  return newNode;
558  }
559  // ====================================================
560  else {
562 
564  NodeId* sonsIds
565  = static_cast< NodeId* >(ALLOCATE(sizeof(NodeId) * curVar->domainSize()));
566 
567  for (Idx modality = 0; modality < curVar->domainSize(); modality++) {
570 
572  }
573 
575 
580 
581  DEALLOCATE(instNeeded, sizeof(short int) * nbVar__);
582 
583  return newNode;
584  }
585  }
586 
587 } // namespace gum
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669
#define DEALLOCATE(x, y)
#define ALLOCATE(x)