aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
multiDimFunctionGraph_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 Template methods of MultiDimFunctionGraph.
25  *
26  * @author Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
27  * @author Pierre-Henri WUILLEMIN(@LIP6) and Jean-Christophe MAGNAN and Christophe
28  * GONZALES(@AMU)
29  */
30 #include <agrum/tools/multidim/implementations/multiDimFunctionGraph.h>
31 
32 namespace gum {
33 
34  // Default constructor.
35  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
36  INLINE MultiDimFunctionGraph< GUM_SCALAR, TerminalNodePolicy >::
39  name__("MultiDimFunctionGraph"), tableName__("NO NAME"), model__(500, true),
40  manager__(nullptr), root__(0), internalNodeMap__(500, true, false),
41  var2NodeIdMap__(500, true, false), isReduced__(isReduced) {
43  manager__ = nullptr;
44  // Pop up a first node so that id 0 is unavailable
45  model__.addNode();
46  }
47 
48  // Copy constructor.
49  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
54  name__("MultiDimFunctionGraph"), tableName__("No NAME"), model__(500, true),
55  manager__(nullptr), root__(0), internalNodeMap__(500, true, false),
56  var2NodeIdMap__(500, true, false), isReduced__(from.isReducedAndOrdered()) {
58  copy(from);
59  }
60 
61  // Copy Operator.
62  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
66  copy(from);
67  return *this;
68  }
69 
70  // Destructor.
71  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
74  // Manager deletion
76  if (manager__ != nullptr) delete manager__;
77  this->clear();
78  }
79 
80  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
83  if (isReduced__)
86  else
89  }
90 
91  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
92  INLINE const std::string&
94  return name__;
95  }
96 
97  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
99  const Instantiation& i,
100  const GUM_SCALAR& value) const {
102  "Function Graph can't be edited so "
103  "easily.\nMultiDimFunctionGraphManager "
104  "provides the framework to edit a "
105  "Function Graph.")
106  }
107 
108  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
110  const GUM_SCALAR& d) const {
112  "Function Graph can't be edited so "
113  "easily.\nMultiDimFunctionGraphManager "
114  "provides the framework to edit a "
115  "Function Graph.")
116  }
117 
118  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
120  const std::vector< GUM_SCALAR >& v) const {
122  "Function Graph can't be edited so "
123  "easily.\nMultiDimFunctionGraphManager "
124  "provides the framework to editaa "
125  "Function Graph.")
126  }
127  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
129  std::initializer_list< GUM_SCALAR > l) const {
131  "Function Graph can't be edited so "
132  "easily.\nMultiDimFunctionGraphManager "
133  "provides the framework to edit a "
134  "Function Graph.")
135  }
136 
137  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
139  const DiscreteVariable& v) {
140  if (!this->variablesSequence().exists(&v))
142 
143  if (!this->var2NodeIdMap__.exists(&v))
145  }
146 
147  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
149  const DiscreteVariable& v) {
150  if (this->var2NodeIdMap__.exists(&v)) {
151  while (var2NodeIdMap__[&v]->list() != nullptr) {
153  }
154  delete var2NodeIdMap__[&v];
156  }
157 
158  if (this->variablesSequence().exists(&v))
160  }
161 
162  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
163  INLINE Size
165  return internalNodeMap__.size(); // + valueMap__.size();
166  }
167 
168 
169  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
170  INLINE void
172  const Instantiation& i,
173  const DiscreteVariable* const var,
174  Idx oldval,
175  Idx newval) {}
176 
177  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
178  INLINE void
180  const Instantiation& i) {}
181 
182  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
183  INLINE void
185  const Instantiation& i) {}
186 
187  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
188  INLINE void
190  const Instantiation& i) {}
191 
192  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
193  INLINE void
195  const Instantiation& i) {}
196 
197  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
200 
201  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
202  INLINE std::string
204  const Instantiation* i) const {
206  sBuff << (*i) << " = " << this->get(*i);
207  return sBuff.str();
208  }
209 
210  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
212  const MultiDimContainer< GUM_SCALAR >& src,
213  Instantiation* p_i) const {
215  "You cannot copy another type of multiDim "
216  "into a MultiDimFunctionGraph.");
217  }
218 
219  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
221  const MultiDimContainer< GUM_SCALAR >& src) {
223  "You cannot copy another type of multiDim "
224  "into a MultiDimFunctionGraph.");
225  }
226 
227  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
230  if (this->isReduced__ != src.isReducedAndOrdered())
232  "Cannot copy a Reduced and Ordered "
233  "function graph into Tree function graph "
234  "(or vice-versa).")
235 
236  this->clear();
237 
238  // New variables insertion
242  ++varIter)
243  this->add(**varIter);
244 
245  std::vector< NodeId > lifo;
247 
248  if (src.isTerminalNode(src.root()))
249  this->manager()->setRootNode(
251  else {
252  this->manager()->setRootNode(
253  this->manager()->addInternalNode(src.node(src.root())->nodeVar()));
254  src2dest.insert(src.root(), this->root());
255  lifo.push_back(src.root());
256  }
257 
258  // Depth-first exploration and copy
259  while (!lifo.empty()) {
261  lifo.pop_back();
262 
264 
265  for (Idx index = 0; index < currentSrcNode->nbSons(); ++index) {
271  } else {
275  }
277  }
279  index,
281  }
282  }
283 
284  manager()->clean();
285  }
286 
287  // Copies src diagrams structure into this diagrams.
288  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
289  INLINE void
292  const Bijection< const DiscreteVariable*, const DiscreteVariable* >&
293  reassign) {
294  if (this->isReduced__ != src.isReducedAndOrdered())
296  "Cannot copy a Reduced and Ordered "
297  "function graph into Tree function graph "
298  "(or vice-versa).")
299 
300  this->clear();
301 
302  // New variables insertion
306  ++varIter) {
309  "Var " << (*varIter)->name() << " and var "
310  << reassign.second(*varIter)->name()
311  << " have different domain sizes ("
312  << (*varIter)->domainSize()
313  << "!=" << reassign.second(*varIter)->domainSize() << ")")
314  this->add(*(reassign.second(*varIter)));
315  }
316 
317  std::vector< NodeId > lifo;
319 
320  if (src.isTerminalNode(src.root())) {
321  this->manager()->setRootNode(
323  } else {
324  this->manager()->setRootNode(this->manager()->addInternalNode(
326  src2dest.insert(src.root(), this->root());
327  lifo.push_back(src.root());
328  }
329 
330  // Depth-first exploration and copy
331  while (!lifo.empty()) {
333  lifo.pop_back();
334 
336 
337  for (Idx index = 0; index < currentSrcNode->nbSons(); ++index) {
343  } else {
347  }
349  }
351  index,
353  }
354  }
355 
356  manager()->clean();
357  }
358 
359  // Copies src diagrams and multiply every value by the given scalar.
360  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
364  GUM_SCALAR gamma) {
365  if (this->isReduced__ != src.isReducedAndOrdered())
367  "Cannot copy a Reduced and Ordered "
368  "function graph into Tree function graph "
369  "(or vice-versa).")
370 
371  this->clear();
372 
373  // New variables insertion
377  ++varIter)
378  this->add(**varIter);
379 
380  std::vector< NodeId > lifo;
382 
383  if (src.isTerminalNode(src.root()))
384  this->manager()->setRootNode(
386  else {
387  this->manager()->setRootNode(
388  this->manager()->addInternalNode(src.node(src.root())->nodeVar()));
389  src2dest.insert(src.root(), this->root());
390  lifo.push_back(src.root());
391  }
392 
393  // Depth-first exploration an copy
394  while (!lifo.empty()) {
396  lifo.pop_back();
397 
399 
400  for (Idx index = 0; index < currentSrcNode->nbSons(); ++index) {
406  } else {
410  }
412  }
414  index,
416  }
417  }
418 
419  manager()->clean();
420  }
421 
422  // Clears the function graph
423  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
425  model__.clear();
426  // Always discard the nodeId 0
427  model__.addNode();
428 
429  this->clearAllTerminalNodes();
430 
431  // Nodes cleaning
435  ++nodeIter) {
436  delete nodeIter.val();
437  }
439 
440  // Cleaning the list of nodes for each variables
442  varIter
445  ++varIter) {
446  delete varIter.val();
447  }
449 
451  = this->variablesSequence().rbeginSafe();
452  varIter != this->variablesSequence().rendSafe();
453  --varIter) {
454  this->erase(**varIter);
455  }
456  }
457 
458 
459  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
460  INLINE std::string
462  bool withBackArcs) const {
467  // std::stringstream defaultarcstream;
468  output << std::endl << "digraph \" " << tableName__ << "\" {" << std::endl;
469 
470  terminalStream << "node [shape = box];" << std::endl;
471  nonTerminalStream << "node [shape = ellipse];" << std::endl;
472  std::string tab = " ";
473 
475  nodeIter != model__.end();
476  ++nodeIter)
477  if (*nodeIter != 0) {
478  if (this->isTerminalNode((NodeId)*nodeIter))
479  terminalStream << tab << *nodeIter << ";" << tab << *nodeIter
480  << " [label=\"" << *nodeIter << " - "
481  << std::setprecision(30)
482  << this->terminalNodeValue(*nodeIter) << "\"]"
483  << ";" << std::endl;
484  else {
486  nonTerminalStream << tab << *nodeIter << ";" << tab << *nodeIter
487  << " [label=\"" << *nodeIter << " - "
488  << currentNode->nodeVar()->name() << "\"]"
489  << ";" << std::endl;
490 
491  // if (arcMap_[*nodeIter] != NULL)
493  for (Idx sonIter = 0; sonIter < currentNode->nbSons(); ++sonIter) {
497  }
498 
499  for (auto sonIter = sonMap.beginSafe(); sonIter != sonMap.endSafe();
500  ++sonIter) {
501  arcstream << tab << *nodeIter << " -> " << sonIter.key()
502  << " [label=\" ";
503  Link< Idx >* modaIter = sonIter.val()->list();
504  while (modaIter) {
506  << ", ";
508  }
509  arcstream << "\",color=\"#0000ff\"]"
510  << ";" << std::endl;
511  delete sonIter.val();
512  }
513 
514  if (withBackArcs) {
516  while (parentIter != nullptr) {
517  arcstream << tab << *nodeIter << " -> "
518  << parentIter->element().parentId << " [label=\""
520  << "\",color=\"#ff0000\"]"
521  << ";" << std::endl;
523  }
524  }
525  }
526  }
527 
528  output << terminalStream.str() << std::endl
529  << nonTerminalStream.str() << std::endl
530  << arcstream.str() << std::endl
531  << "}" << std::endl;
532 
533  return output.str();
534  }
535 
536  // Returns a const reference to the manager of this diagram
537  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
538  INLINE const NodeGraphPart&
540  return model__;
541  }
542 
543  // Returns a const reference to the manager of this diagram
544  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
547  if (manager__ == nullptr) {
548  if (isReduced__)
549  manager__
551  this);
552  else
553  manager__
555  TerminalNodePolicy >(this);
556  }
557  return manager__;
558  }
559 
560  // Returns the id of the root node from the diagram
561  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
562  INLINE const NodeId&
564  return root__;
565  }
566 
567  // Indicates if given node is terminal or not
568  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
569  INLINE bool
571  const NodeId& node) const {
572  return this->existsTerminalNodeWithId(node);
573  }
574 
575  // Indicates if given node is terminal or not
576  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
577  INLINE bool
579  const NodeId& node) const {
580  return this->internalNodeMap__.exists(node);
581  }
582 
583  // Returns value associated to given node.
584  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
585  INLINE const GUM_SCALAR&
587  NodeId n) const {
588  if (!isTerminalNode(n))
590  "Id " << n << " is not bound to any terminal node")
591  return this->terminalNodeValue(n);
592  }
593 
594  // Returns internalNode structure associated to that nodeId
595  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
596  INLINE const InternalNode*
598  NodeId n) const {
599  if (!isInternalNode(n))
601  "Id " << n << " is not bound to any terminal node")
602  return this->internalNodeMap__[n];
603  }
604 
605  // Returns the list of node associated to given variable
606  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
607  INLINE const LinkedList< NodeId >*
609  const DiscreteVariable* var) const {
610  if (!this->variablesSequence().exists(var))
612  "Var " << var->name()
613  << " has not been inserted in the function graph")
614  return var2NodeIdMap__[var];
615  }
616 
617  // Returns the name of the table represented by this structure.
618  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
619  INLINE const std::string&
621  return tableName__;
622  }
623 
624  // Sets the name of the table represented by this structure.
625  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
626  INLINE void
628  const std::string& name) {
629  tableName__ = name;
630  }
631 
632  // Returns true if this MultiDimFunctionGraph is reduced and Ordered.
633  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
634  INLINE bool
636  const {
637  return isReduced__;
638  }
639 
640  // Returns a reduced and ordered instance.
641  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
646  }
647 
648  // Returns an arborescent instance
649  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
653  }
654 
655  // Not implemented yet
656  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
658  const DiscreteVariable* x,
659  const DiscreteVariable* y) {
660  GUM_ERROR(OperationNotAllowed, "Not Implemented Yet")
661  }
662 
663  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
665  const Instantiation& inst) const {
667  "You can't edit a function by other mean than the manager");
668  }
669 
670  // Return a data, given a Instantiation.
671  template < typename GUM_SCALAR, template < class > class TerminalNodePolicy >
673  const Instantiation& inst) const {
675  InternalNode* currentNode = nullptr;
676  while (!isTerminalNode(currentNodeId)) {
679  }
680  return this->terminalNodeValue(currentNodeId);
681  }
682 
683 } // namespace gum
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669