gtsam  3.2.1
gtsam
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DecisionTree-inl.h
1 /* ----------------------------------------------------------------------------
2 
3  * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4  * Atlanta, Georgia 30332-0415
5  * All Rights Reserved
6  * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7 
8  * See LICENSE for the license information
9 
10  * -------------------------------------------------------------------------- */
11 
20 #pragma once
21 
23 #include <gtsam/base/Testable.h>
24 
25 #include <boost/format.hpp>
26 #include <boost/optional.hpp>
27 #include <boost/foreach.hpp>
28 #include <boost/tuple/tuple.hpp>
29 #include <boost/assign/std/vector.hpp>
30 using boost::assign::operator+=;
31 #include <boost/unordered_set.hpp>
32 #include <boost/noncopyable.hpp>
33 
34 #include <list>
35 #include <cmath>
36 #include <fstream>
37 #include <sstream>
38 
39 namespace gtsam {
40 
41  /*********************************************************************************/
42  // Node
43  /*********************************************************************************/
44 #ifdef DT_DEBUG_MEMORY
45  template<typename L, typename Y>
46  int DecisionTree<L, Y>::Node::nrNodes = 0;
47 #endif
48 
49  /*********************************************************************************/
50  // Leaf
51  /*********************************************************************************/
52  template<typename L, typename Y>
53  class DecisionTree<L, Y>::Leaf: public DecisionTree<L, Y>::Node {
54 
56  Y constant_;
57 
58  public:
59 
61  Leaf(const Y& constant) :
62  constant_(constant) {}
63 
65  const Y& constant() const {
66  return constant_;
67  }
68 
70  bool sameLeaf(const Leaf& q) const {
71  return constant_ == q.constant_;
72  }
73 
75  bool sameLeaf(const Node& q) const {
76  return (q.isLeaf() && q.sameLeaf(*this));
77  }
78 
80  bool equals(const Node& q, double tol) const {
81  const Leaf* other = dynamic_cast<const Leaf*> (&q);
82  if (!other) return false;
83  return fabs(double(this->constant_ - other->constant_)) < tol;
84  }
85 
87  void print(const std::string& s) const {
88  bool showZero = true;
89  if (showZero || constant_) std::cout << s << " Leaf " << constant_ << std::endl;
90  }
91 
93  void dot(std::ostream& os, bool showZero) const {
94  if (showZero || constant_) os << "\"" << this->id() << "\" [label=\""
95  << boost::format("%4.2g") % constant_
96  << "\", shape=box, rank=sink, height=0.35, fixedsize=true]\n"; // width=0.55,
97  }
98 
100  const Y& operator()(const Assignment<L>& x) const {
101  return constant_;
102  }
103 
105  NodePtr apply(const Unary& op) const {
106  NodePtr f(new Leaf(op(constant_)));
107  return f;
108  }
109 
110  // Apply binary operator "h = f op g" on Leaf node
111  // Note op is not assumed commutative so we need to keep track of order
112  // Simply calls apply on argument to call correct virtual method:
113  // fL.apply_f_op_g(gL) -> gL.apply_g_op_fL(fL) (below)
114  // fL.apply_f_op_g(gC) -> gC.apply_g_op_fL(fL) (Choice)
115  NodePtr apply_f_op_g(const Node& g, const Binary& op) const {
116  return g.apply_g_op_fL(*this, op);
117  }
118 
119  // Applying binary operator to two leaves results in a leaf
120  NodePtr apply_g_op_fL(const Leaf& fL, const Binary& op) const {
121  NodePtr h(new Leaf(op(fL.constant_, constant_))); // fL op gL
122  return h;
123  }
124 
125  // If second argument is a Choice node, call it's apply with leaf as second
126  NodePtr apply_g_op_fC(const Choice& fC, const Binary& op) const {
127  return fC.apply_fC_op_gL(*this, op); // operand order back to normal
128  }
129 
131  NodePtr choose(const L& label, size_t index) const {
132  return NodePtr(new Leaf(constant()));
133  }
134 
135  bool isLeaf() const { return true; }
136 
137  }; // Leaf
138 
139  /*********************************************************************************/
140  // Choice
141  /*********************************************************************************/
142  template<typename L, typename Y>
143  class DecisionTree<L, Y>::Choice: public DecisionTree<L, Y>::Node {
144 
146  L label_;
147 
149  std::vector<NodePtr> branches_;
150 
151  private:
153  size_t allSame_;
154 
155  typedef boost::shared_ptr<const Choice> ChoicePtr;
156 
157  public:
158 
159  virtual ~Choice() {
160 #ifdef DT_DEBUG_MEMORY
161  std::std::cout << Node::nrNodes << " destructing (Choice) " << this->id() << std::std::endl;
162 #endif
163  }
164 
166  static NodePtr Unique(const ChoicePtr& f) {
167 #ifndef DT_NO_PRUNING
168  if (f->allSame_) {
169  assert(f->branches().size() > 0);
170  NodePtr f0 = f->branches_[0];
171  assert(f0->isLeaf());
172  NodePtr newLeaf(new Leaf(boost::dynamic_pointer_cast<const Leaf>(f0)->constant()));
173  return newLeaf;
174  } else
175 #endif
176  return f;
177  }
178 
179  bool isLeaf() const { return false; }
180 
182  Choice(const L& label, size_t count) :
183  label_(label), allSame_(true) {
184  branches_.reserve(count);
185  }
186 
190  Choice(const Choice& f, const Choice& g, const Binary& op) :
191  allSame_(true) {
192 
193  // Choose what to do based on label
194  if (f.label() > g.label()) {
195  // f higher than g
196  label_ = f.label();
197  size_t count = f.nrChoices();
198  branches_.reserve(count);
199  for (size_t i = 0; i < count; i++)
200  push_back(f.branches_[i]->apply_f_op_g(g, op));
201  } else if (g.label() > f.label()) {
202  // f lower than g
203  label_ = g.label();
204  size_t count = g.nrChoices();
205  branches_.reserve(count);
206  for (size_t i = 0; i < count; i++)
207  push_back(g.branches_[i]->apply_g_op_fC(f, op));
208  } else {
209  // f same level as g
210  label_ = f.label();
211  size_t count = f.nrChoices();
212  branches_.reserve(count);
213  for (size_t i = 0; i < count; i++)
214  push_back(f.branches_[i]->apply_f_op_g(*g.branches_[i], op));
215  }
216  }
217 
218  const L& label() const {
219  return label_;
220  }
221 
222  size_t nrChoices() const {
223  return branches_.size();
224  }
225 
226  const std::vector<NodePtr>& branches() const {
227  return branches_;
228  }
229 
231  void push_back(const NodePtr& node) {
232  // allSame_ is restricted to leaf nodes in a decision tree
233  if (allSame_ && !branches_.empty()) {
234  allSame_ = node->sameLeaf(*branches_.back());
235  }
236  branches_.push_back(node);
237  }
238 
240  void print(const std::string& s) const {
241  std::cout << s << " Choice(";
242  // std::cout << this << ",";
243  std::cout << label_ << ") " << std::endl;
244  for (size_t i = 0; i < branches_.size(); i++)
245  branches_[i]->print((boost::format("%s %d") % s % i).str());
246  }
247 
249  void dot(std::ostream& os, bool showZero) const {
250  os << "\"" << this->id() << "\" [shape=circle, label=\"" << label_
251  << "\"]\n";
252  for (size_t i = 0; i < branches_.size(); i++) {
253  NodePtr branch = branches_[i];
254 
255  // Check if zero
256  if (!showZero) {
257  const Leaf* leaf = dynamic_cast<const Leaf*> (branch.get());
258  if (leaf && !leaf->constant()) continue;
259  }
260 
261  os << "\"" << this->id() << "\" -> \"" << branch->id() << "\"";
262  if (i == 0) os << " [style=dashed]";
263  if (i > 1) os << " [style=bold]";
264  os << std::endl;
265  branch->dot(os, showZero);
266  }
267  }
268 
270  bool sameLeaf(const Leaf& q) const {
271  return false;
272  }
273 
275  bool sameLeaf(const Node& q) const {
276  return (q.isLeaf() && q.sameLeaf(*this));
277  }
278 
280  bool equals(const Node& q, double tol) const {
281  const Choice* other = dynamic_cast<const Choice*> (&q);
282  if (!other) return false;
283  if (this->label_ != other->label_) return false;
284  if (branches_.size() != other->branches_.size()) return false;
285  // we don't care about shared pointers being equal here
286  for (size_t i = 0; i < branches_.size(); i++)
287  if (!(branches_[i]->equals(*(other->branches_[i]), tol))) return false;
288  return true;
289  }
290 
292  const Y& operator()(const Assignment<L>& x) const {
293 #ifndef NDEBUG
294  typename Assignment<L>::const_iterator it = x.find(label_);
295  if (it == x.end()) {
296  std::cout << "Trying to find value for " << label_ << std::endl;
297  throw std::invalid_argument(
298  "DecisionTree::operator(): value undefined for a label");
299  }
300 #endif
301  size_t index = x.at(label_);
302  NodePtr child = branches_[index];
303  return (*child)(x);
304  }
305 
309  Choice(const L& label, const Choice& f, const Unary& op) :
310  label_(label), allSame_(true) {
311 
312  branches_.reserve(f.branches_.size()); // reserve space
313  BOOST_FOREACH (const NodePtr& branch, f.branches_)
314  push_back(branch->apply(op));
315  }
316 
318  NodePtr apply(const Unary& op) const {
319  boost::shared_ptr<Choice> r(new Choice(label_, *this, op));
320  return Unique(r);
321  }
322 
323  // Apply binary operator "h = f op g" on Choice node
324  // Note op is not assumed commutative so we need to keep track of order
325  // Simply calls apply on argument to call correct virtual method:
326  // fC.apply_f_op_g(gL) -> gL.apply_g_op_fC(fC) -> (Leaf)
327  // fC.apply_f_op_g(gC) -> gC.apply_g_op_fC(fC) -> (below)
328  NodePtr apply_f_op_g(const Node& g, const Binary& op) const {
329  return g.apply_g_op_fC(*this, op);
330  }
331 
332  // If second argument of binary op is Leaf node, recurse on branches
333  NodePtr apply_g_op_fL(const Leaf& fL, const Binary& op) const {
334  boost::shared_ptr<Choice> h(new Choice(label(), nrChoices()));
335  BOOST_FOREACH(NodePtr branch, branches_)
336  h->push_back(fL.apply_f_op_g(*branch, op));
337  return Unique(h);
338  }
339 
340  // If second argument of binary op is Choice, call constructor
341  NodePtr apply_g_op_fC(const Choice& fC, const Binary& op) const {
342  boost::shared_ptr<Choice> h(new Choice(fC, *this, op));
343  return Unique(h);
344  }
345 
346  // If second argument of binary op is Leaf
347  template<typename OP>
348  NodePtr apply_fC_op_gL(const Leaf& gL, OP op) const {
349  boost::shared_ptr<Choice> h(new Choice(label(), nrChoices()));
350  BOOST_FOREACH(const NodePtr& branch, branches_)
351  h->push_back(branch->apply_f_op_g(gL, op));
352  return Unique(h);
353  }
354 
356  NodePtr choose(const L& label, size_t index) const {
357  if (label_ == label)
358  return branches_[index]; // choose branch
359 
360  // second case, not label of interest, just recurse
361  boost::shared_ptr<Choice> r(new Choice(label_, branches_.size()));
362  BOOST_FOREACH(const NodePtr& branch, branches_)
363  r->push_back(branch->choose(label, index));
364  return Unique(r);
365  }
366 
367  }; // Choice
368 
369  /*********************************************************************************/
370  // DecisionTree
371  /*********************************************************************************/
372  template<typename L, typename Y>
374  }
375 
376  template<typename L, typename Y>
378  root_(root) {
379  }
380 
381  /*********************************************************************************/
382  template<typename L, typename Y>
384  root_ = NodePtr(new Leaf(y));
385  }
386 
387  /*********************************************************************************/
388  template<typename L, typename Y>
390  const L& label, const Y& y1, const Y& y2) {
391  boost::shared_ptr<Choice> a(new Choice(label, 2));
392  NodePtr l1(new Leaf(y1)), l2(new Leaf(y2));
393  a->push_back(l1);
394  a->push_back(l2);
395  root_ = Choice::Unique(a);
396  }
397 
398  /*********************************************************************************/
399  template<typename L, typename Y>
401  const LabelC& labelC, const Y& y1, const Y& y2) {
402  if (labelC.second != 2) throw std::invalid_argument(
403  "DecisionTree: binary constructor called with non-binary label");
404  boost::shared_ptr<Choice> a(new Choice(labelC.first, 2));
405  NodePtr l1(new Leaf(y1)), l2(new Leaf(y2));
406  a->push_back(l1);
407  a->push_back(l2);
408  root_ = Choice::Unique(a);
409  }
410 
411  /*********************************************************************************/
412  template<typename L, typename Y>
413  DecisionTree<L, Y>::DecisionTree(const std::vector<LabelC>& labelCs,
414  const std::vector<Y>& ys) {
415  // call recursive Create
416  root_ = create(labelCs.begin(), labelCs.end(), ys.begin(), ys.end());
417  }
418 
419  /*********************************************************************************/
420  template<typename L, typename Y>
421  DecisionTree<L, Y>::DecisionTree(const std::vector<LabelC>& labelCs,
422  const std::string& table) {
423 
424  // Convert std::string to values of type Y
425  std::vector<Y> ys;
426  std::istringstream iss(table);
427  copy(std::istream_iterator<Y>(iss), std::istream_iterator<Y>(),
428  back_inserter(ys));
429 
430  // now call recursive Create
431  root_ = create(labelCs.begin(), labelCs.end(), ys.begin(), ys.end());
432  }
433 
434  /*********************************************************************************/
435  template<typename L, typename Y>
436  template<typename Iterator> DecisionTree<L, Y>::DecisionTree(
437  Iterator begin, Iterator end, const L& label) {
438  root_ = compose(begin, end, label);
439  }
440 
441  /*********************************************************************************/
442  template<typename L, typename Y>
444  const DecisionTree& f0, const DecisionTree& f1) {
445  std::vector<DecisionTree> functions;
446  functions += f0, f1;
447  root_ = compose(functions.begin(), functions.end(), label);
448  }
449 
450  /*********************************************************************************/
451  template<typename L, typename Y>
452  template<typename M, typename X>
454  const std::map<M, L>& map, boost::function<Y(const X&)> op) {
455  root_ = convert(other.root_, map, op);
456  }
457 
458  /*********************************************************************************/
459  // Called by two constructors above.
460  // Takes a label and a corresponding range of decision trees, and creates a new
461  // decision tree. However, the order of the labels needs to be respected, so we
462  // cannot just create a root Choice node on the label: if the label is not the
463  // highest label, we need to do a complicated and expensive recursive call.
464  template<typename L, typename Y> template<typename Iterator>
466  Iterator begin, Iterator end, const L& label) const {
467 
468  // find highest label among branches
469  boost::optional<L> highestLabel;
470  boost::optional<size_t> nrChoices;
471  for (Iterator it = begin; it != end; it++) {
472  if (it->root_->isLeaf()) continue;
473  boost::shared_ptr<const Choice> c = boost::dynamic_pointer_cast<const Choice> (it->root_);
474  if (!highestLabel || c->label() > *highestLabel) {
475  highestLabel.reset(c->label());
476  nrChoices.reset(c->nrChoices());
477  }
478  }
479 
480  // if label is already in correct order, just put together a choice on label
481  if (!highestLabel || label > *highestLabel) {
482  boost::shared_ptr<Choice> choiceOnLabel(new Choice(label, end - begin));
483  for (Iterator it = begin; it != end; it++)
484  choiceOnLabel->push_back(it->root_);
485  return Choice::Unique(choiceOnLabel);
486  }
487 
488  // Set up a new choice on the highest label
489  boost::shared_ptr<Choice> choiceOnHighestLabel(new Choice(*highestLabel, *nrChoices));
490  // now, for all possible values of highestLabel
491  for (size_t index = 0; index < *nrChoices; index++) {
492  // make a new set of functions for composing by iterating over the given
493  // functions, and selecting the appropriate branch.
494  std::vector<DecisionTree> functions;
495  for (Iterator it = begin; it != end; it++) {
496  // by restricting the input functions to value i for labelBelow
497  DecisionTree chosen = it->choose(*highestLabel, index);
498  functions.push_back(chosen);
499  }
500  // We then recurse, for all values of the highest label
501  NodePtr fi = compose(functions.begin(), functions.end(), label);
502  choiceOnHighestLabel->push_back(fi);
503  }
504  return Choice::Unique(choiceOnHighestLabel);
505  }
506 
507  /*********************************************************************************/
508  // "create" is a bit of a complicated thing, but very useful.
509  // It takes a range of labels and a corresponding range of values,
510  // and creates a decision tree, as follows:
511  // - if there is only one label, creates a choice node with values in leaves
512  // - otherwise, it evenly splits up the range of values and creates a tree for
513  // each sub-range, and assigns that tree to first label's choices
514  // Example:
515  // create([B A],[1 2 3 4]) would call
516  // create([A],[1 2])
517  // create([A],[3 4])
518  // and produce
519  // B=0
520  // A=0: 1
521  // A=1: 2
522  // B=1
523  // A=0: 3
524  // A=1: 4
525  // Note, through the magic of "compose", create([A B],[1 2 3 4]) will produce
526  // exactly the same tree as above: the highest label is always the root.
527  // However, it will be *way* faster if labels are given highest to lowest.
528  template<typename L, typename Y>
529  template<typename It, typename ValueIt>
530  typename DecisionTree<L, Y>::NodePtr DecisionTree<L, Y>::create(
531  It begin, It end, ValueIt beginY, ValueIt endY) const {
532 
533  // get crucial counts
534  size_t nrChoices = begin->second;
535  size_t size = endY - beginY;
536 
537  // Find the next key to work on
538  It labelC = begin + 1;
539  if (labelC == end) {
540  // Base case: only one key left
541  // Create a simple choice node with values as leaves.
542  if (size != nrChoices) {
543  std::cout << "Trying to create DD on " << begin->first << std::endl;
544  std::cout << boost::format("DecisionTree::create: expected %d values but got %d instead") % nrChoices % size << std::endl;
545  throw std::invalid_argument("DecisionTree::create invalid argument");
546  }
547  boost::shared_ptr<Choice> choice(new Choice(begin->first, endY - beginY));
548  for (ValueIt y = beginY; y != endY; y++)
549  choice->push_back(NodePtr(new Leaf(*y)));
550  return Choice::Unique(choice);
551  }
552 
553  // Recursive case: perform "Shannon expansion"
554  // Creates one tree (i.e.,function) for each choice of current key
555  // by calling create recursively, and then puts them all together.
556  std::vector<DecisionTree> functions;
557  size_t split = size / nrChoices;
558  for (size_t i = 0; i < nrChoices; i++, beginY += split) {
559  NodePtr f = create<It, ValueIt>(labelC, end, beginY, beginY + split);
560  functions += DecisionTree(f);
561  }
562  return compose(functions.begin(), functions.end(), begin->first);
563  }
564 
565  /*********************************************************************************/
566  template<typename L, typename Y>
567  template<typename M, typename X>
568  typename DecisionTree<L, Y>::NodePtr DecisionTree<L, Y>::convert(
569  const typename DecisionTree<M, X>::NodePtr& f, const std::map<M, L>& map,
570  boost::function<Y(const X&)> op) {
571 
572  typedef DecisionTree<M, X> MX;
573  typedef typename MX::Leaf MXLeaf;
574  typedef typename MX::Choice MXChoice;
575  typedef typename MX::NodePtr MXNodePtr;
576  typedef DecisionTree<L, Y> LY;
577 
578  // ugliness below because apparently we can't have templated virtual functions
579  // If leaf, apply unary conversion "op" and create a unique leaf
580  const MXLeaf* leaf = dynamic_cast<const MXLeaf*> (f.get());
581  if (leaf) return NodePtr(new Leaf(op(leaf->constant())));
582 
583  // Check if Choice
584  boost::shared_ptr<const MXChoice> choice = boost::dynamic_pointer_cast<const MXChoice> (f);
585  if (!choice) throw std::invalid_argument(
586  "DecisionTree::Convert: Invalid NodePtr");
587 
588  // get new label
589  M oldLabel = choice->label();
590  L newLabel = map.at(oldLabel);
591 
592  // put together via Shannon expansion otherwise not sorted.
593  std::vector<LY> functions;
594  BOOST_FOREACH(const MXNodePtr& branch, choice->branches()) {
595  LY converted(convert<M, X>(branch, map, op));
596  functions += converted;
597  }
598  return LY::compose(functions.begin(), functions.end(), newLabel);
599  }
600 
601  /*********************************************************************************/
602  template<typename L, typename Y>
603  bool DecisionTree<L, Y>::equals(const DecisionTree& other, double tol) const {
604  return root_->equals(*other.root_, tol);
605  }
606 
607  template<typename L, typename Y>
608  void DecisionTree<L, Y>::print(const std::string& s) const {
609  root_->print(s);
610  }
611 
612  template<typename L, typename Y>
613  bool DecisionTree<L, Y>::operator==(const DecisionTree& other) const {
614  return root_->equals(*other.root_);
615  }
616 
617  template<typename L, typename Y>
619  return root_->operator ()(x);
620  }
621 
622  template<typename L, typename Y>
624  return DecisionTree(root_->apply(op));
625  }
626 
627  /*********************************************************************************/
628  template<typename L, typename Y>
630  const Binary& op) const {
631  // apply the operaton on the root of both diagrams
632  NodePtr h = root_->apply_f_op_g(*g.root_, op);
633  // create a new class with the resulting root "h"
634  DecisionTree result(h);
635  return result;
636  }
637 
638  /*********************************************************************************/
639  // The way this works:
640  // We have an ADT, picture it as a tree.
641  // At a certain depth, we have a branch on "label".
642  // The function "choose(label,index)" will return a tree of one less depth,
643  // where there is no more branch on "label": only the subtree under that
644  // branch point corresponding to the value "index" is left instead.
645  // The function below get all these smaller trees and "ops" them together.
646  // This implements marginalization in Darwiche09book, pg 330
647  template<typename L, typename Y>
649  size_t cardinality, const Binary& op) const {
650  DecisionTree result = choose(label, 0);
651  for (size_t index = 1; index < cardinality; index++) {
652  DecisionTree chosen = choose(label, index);
653  result = result.apply(chosen, op);
654  }
655  return result;
656  }
657 
658  /*********************************************************************************/
659  template<typename L, typename Y>
660  void DecisionTree<L, Y>::dot(std::ostream& os, bool showZero) const {
661  os << "digraph G {\n";
662  root_->dot(os, showZero);
663  os << " [ordering=out]}" << std::endl;
664  }
665 
666  template<typename L, typename Y>
667  void DecisionTree<L, Y>::dot(const std::string& name, bool showZero) const {
668  std::ofstream os((name + ".dot").c_str());
669  dot(os, showZero);
670  system(
671  ("dot -Tpdf " + name + ".dot -o " + name + ".pdf >& /dev/null").c_str());
672  }
673 
674 /*********************************************************************************/
675 
676 } // namespace gtsam
677 
678 
NodePtr apply(const Unary &op) const
apply unary operator
Definition: DecisionTree-inl.h:105
double dot(const V1 &a, const V2 &b)
Dot product.
Definition: Vector.h:259
NodePtr convert(const typename DecisionTree< M, X >::NodePtr &f, const std::map< M, L > &map, boost::function< Y(const X &)> op)
Convert to a different type.
boost::function< Y(const Y &)> Unary
Handy typedefs for unary and binary function types.
Definition: DecisionTree.h:41
Decision Tree for use in DiscreteFactors.
bool sameLeaf(const Leaf &q) const
Choice-Leaf equality: always false.
Definition: DecisionTree-inl.h:270
void push_back(const NodePtr &node)
add a branch: TODO merge into constructor
Definition: DecisionTree-inl.h:231
void print(const std::string &s="DecisionTree") const
GTSAM-style print.
Definition: DecisionTree-inl.h:608
void print(const std::string &s) const
print
Definition: DecisionTree-inl.h:87
bool sameLeaf(const Node &q) const
polymorphic equality: if q is a leaf, could be...
Definition: DecisionTree-inl.h:275
DecisionTree()
Default constructor.
Definition: DecisionTree-inl.h:373
Leaf(const Y &constant)
Constructor from constant.
Definition: DecisionTree-inl.h:61
DecisionTree combine(const L &label, size_t cardinality, const Binary &op) const
combine subtrees on key with binary operation "op"
Definition: DecisionTree-inl.h:648
const Y & operator()(const Assignment< L > &x) const
evaluate
Definition: DecisionTree-inl.h:618
NodePtr choose(const L &label, size_t index) const
choose a branch, create new memory !
Definition: DecisionTree-inl.h:131
bool equals(const Node &q, double tol) const
equality up to tolerance
Definition: DecisionTree-inl.h:280
void dot(std::ostream &os, bool showZero) const
output to graphviz (as a a graph)
Definition: DecisionTree-inl.h:249
bool sameLeaf(const Leaf &q) const
Leaf-Leaf equality.
Definition: DecisionTree-inl.h:70
const Y & operator()(const Assignment< L > &x) const
evaluate
Definition: DecisionTree-inl.h:292
An assignment from labels to value index (size_t).
Definition: Assignment.h:35
static NodePtr Unique(const ChoicePtr &f)
If all branches of a choice node f are the same, just return a branch.
Definition: DecisionTree-inl.h:166
Concept check for values that can be used in unit tests.
bool equals(const Node &q, double tol) const
equality up to tolerance
Definition: DecisionTree-inl.h:80
Template to create a binary predicate.
Definition: Testable.h:102
Node::Ptr NodePtr
------------------—— Node base class ---------------------——
Definition: DecisionTree.h:96
NodePtr apply(const Unary &op) const
apply unary operator
Definition: DecisionTree-inl.h:318
Decision Tree L = label for variables Y = function range (any algebra), e.g., bool, int, double.
Definition: DecisionTree.h:36
NodePtr create(It begin, It end, ValueIt beginY, ValueIt endY) const
Internal recursive function to create from keys, cardinalities, and Y values.
---------------------— Node base class ------------------------—
Definition: DecisionTree.h:52
Choice(const Choice &f, const Choice &g, const Binary &op)
Construct from applying binary op to two Choice nodes.
Definition: DecisionTree-inl.h:190
DecisionTree apply(const Unary &op) const
apply Unary operation "op" to f
Definition: DecisionTree-inl.h:623
void dot(std::ostream &os, bool showZero=true) const
output to graphviz format, stream version
Definition: DecisionTree-inl.h:660
Definition: DecisionTree-inl.h:143
Choice(const L &label, size_t count)
Constructor, given choice label and mandatory expected branch count.
Definition: DecisionTree-inl.h:182
const Y & constant() const
return the constant
Definition: DecisionTree-inl.h:65
bool sameLeaf(const Node &q) const
polymorphic equality: is q is a leaf, could be
Definition: DecisionTree-inl.h:75
std::pair< L, size_t > LabelC
A label annotated with cardinality.
Definition: DecisionTree.h:45
void split(const G &g, const PredecessorMap< KEY > &tree, G &Ab1, G &Ab2)
Split the graph into two parts: one corresponds to the given spanning tree, and the other corresponds...
Definition: graph-inl.h:257
Definition: DecisionTree-inl.h:53
DecisionTree choose(const L &label, size_t index) const
create a new function where value(label)==index It's like "restrict" in Darwiche09book pg329...
Definition: DecisionTree.h:180
void dot(std::ostream &os, bool showZero) const
to graphviz file
Definition: DecisionTree-inl.h:93
void print(const std::string &s) const
print (as a tree)
Definition: DecisionTree-inl.h:240
Choice(const L &label, const Choice &f, const Unary &op)
Construct from applying unary op to a Choice node.
Definition: DecisionTree-inl.h:309
const Y & operator()(const Assignment< L > &x) const
evaluate
Definition: DecisionTree-inl.h:100
bool operator==(const DecisionTree &q) const
equality
Definition: DecisionTree-inl.h:613