42 #ifdef DT_DEBUG_MEMORY 43 template<
typename L,
typename Y>
44 int DecisionTree<L, Y>::Node::nrNodes = 0;
50 template <
typename L,
typename Y>
64 Leaf(
const Y& constant,
size_t nrAssignments = 1)
65 : constant_(constant), nrAssignments_(nrAssignments) {}
82 return (q.isLeaf() && q.sameLeaf(*
this));
86 bool equals(
const Node& q,
const CompareFunc& compare)
const override {
87 const Leaf* other =
dynamic_cast<const Leaf*
>(&q);
88 if (!other)
return false;
89 return compare(this->constant_, other->
constant_);
93 void print(
const std::string& s,
const LabelFormatter& labelFormatter,
94 const ValueFormatter& valueFormatter)
const override {
95 std::cout << s <<
" Leaf " << valueFormatter(constant_) << std::endl;
99 void dot(std::ostream& os,
const LabelFormatter& labelFormatter,
100 const ValueFormatter& valueFormatter,
101 bool showZero)
const override {
102 std::string value = valueFormatter(constant_);
103 if (showZero || value.compare(
"0"))
104 os <<
"\"" << this->
id() <<
"\" [label=\"" << value
105 <<
"\", shape=box, rank=sink, height=0.35, fixedsize=true]\n";
115 NodePtr f(
new Leaf(op(constant_), nrAssignments_));
122 NodePtr f(
new Leaf(op(assignment, constant_), nrAssignments_));
131 NodePtr apply_f_op_g(
const Node& g,
const Binary& op)
const override {
132 return g.apply_g_op_fL(*
this, op);
136 NodePtr apply_g_op_fL(
const Leaf& fL,
const Binary& op)
const override {
143 NodePtr apply_g_op_fC(
const Choice& fC,
const Binary& op)
const override {
144 return fC.apply_fC_op_gL(*
this, op);
149 return NodePtr(
new Leaf(constant(), nrAssignments()));
152 bool isLeaf()
const override {
return true; }
157 #ifdef GTSAM_ENABLE_BOOST_SERIALIZATION 159 friend class boost::serialization::access;
160 template <
class ARCHIVE>
161 void serialize(ARCHIVE& ar,
const unsigned int ) {
162 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(
Base);
163 ar& BOOST_SERIALIZATION_NVP(constant_);
164 ar& BOOST_SERIALIZATION_NVP(nrAssignments_);
172 template<
typename L,
typename Y>
187 using ChoicePtr = std::shared_ptr<const Choice>;
194 #ifdef DT_DEBUG_MEMORY 195 std::cout << Node::nrNodes <<
" destructing (Choice) " << this->id()
202 #ifndef GTSAM_DT_NO_PRUNING 204 assert(f->branches().size() > 0);
207 size_t nrAssignments = 0;
208 for(
auto branch: f->branches()) {
209 assert(branch->isLeaf());
211 std::dynamic_pointer_cast<
const Leaf>(branch)->nrAssignments();
214 new Leaf(std::dynamic_pointer_cast<const Leaf>(f0)->constant(),
222 bool isLeaf()
const override {
return false; }
226 label_(label), allSame_(true) {
227 branches_.reserve(count);
237 size_t count = f.nrChoices();
238 branches_.reserve(count);
239 for (
size_t i = 0; i < count; i++)
240 push_back(f.
branches_[i]->apply_f_op_g(g, op));
244 size_t count = g.nrChoices();
245 branches_.reserve(count);
246 for (
size_t i = 0; i < count; i++)
247 push_back(g.
branches_[i]->apply_g_op_fC(f, op));
251 size_t count = f.nrChoices();
252 branches_.reserve(count);
253 for (
size_t i = 0; i < count; i++)
263 size_t nrChoices()
const {
264 return branches_.size();
267 const std::vector<NodePtr>& branches()
const {
274 if (allSame_ && !branches_.empty()) {
275 allSame_ = node->sameLeaf(*branches_.back());
277 branches_.push_back(node);
281 void print(
const std::string& s,
const LabelFormatter& labelFormatter,
282 const ValueFormatter& valueFormatter)
const override {
283 std::cout << s <<
" Choice(";
284 std::cout << labelFormatter(label_) <<
") " << std::endl;
285 for (
size_t i = 0; i < branches_.size(); i++) {
286 branches_[i]->print(s +
" " + std::to_string(i), labelFormatter, valueFormatter);
291 void dot(std::ostream& os,
const LabelFormatter& labelFormatter,
292 const ValueFormatter& valueFormatter,
293 bool showZero)
const override {
294 os <<
"\"" << this->id() <<
"\" [shape=circle, label=\"" << label_
296 size_t B = branches_.size();
297 for (
size_t i = 0; i < B; i++) {
298 const NodePtr& branch = branches_[i];
302 const Leaf* leaf =
dynamic_cast<const Leaf*
>(branch.get());
303 if (leaf && valueFormatter(leaf->
constant()).compare(
"0"))
continue;
306 os <<
"\"" << this->id() <<
"\" -> \"" << branch->id() <<
"\"";
307 if (B == 2 && i == 0) os <<
" [style=dashed]";
309 branch->dot(os, labelFormatter, valueFormatter, showZero);
320 return (q.isLeaf() && q.sameLeaf(*
this));
324 bool equals(
const Node& q,
const CompareFunc& compare)
const override {
326 if (!other)
return false;
327 if (this->label_ != other->
label_)
return false;
328 if (branches_.size() != other->
branches_.size())
return false;
330 for (
size_t i = 0; i < branches_.size(); i++)
341 std::cout <<
"Trying to find value for " << label_ << std::endl;
342 throw std::invalid_argument(
343 "DecisionTree::operator(): value undefined for a label");
346 size_t index = x.at(label_);
347 NodePtr child = branches_[index];
353 label_(label), allSame_(true) {
356 push_back(branch->apply(op));
372 : label_(label), allSame_(true) {
377 for (
size_t i = 0; i < f.
branches_.size(); i++) {
378 assignment_[label_] = i;
381 push_back(branch->apply(op, assignment_));
384 auto assignment_it = assignment_.find(label_);
385 assignment_.erase(assignment_it);
391 auto r = std::make_shared<Choice>(label_, *
this, op);
398 auto r = std::make_shared<Choice>(label_, *
this, op, assignment);
407 NodePtr apply_f_op_g(
const Node& g,
const Binary& op)
const override {
408 return g.apply_g_op_fC(*
this, op);
412 NodePtr apply_g_op_fL(
const Leaf& fL,
const Binary& op)
const override {
413 auto h = std::make_shared<Choice>(label(), nrChoices());
414 for (
auto&& branch : branches_)
415 h->push_back(fL.apply_f_op_g(*branch, op));
420 NodePtr apply_g_op_fC(
const Choice& fC,
const Binary& op)
const override {
421 auto h = std::make_shared<Choice>(fC, *
this, op);
426 template<
typename OP>
427 NodePtr apply_fC_op_gL(
const Leaf& gL, OP op)
const {
428 auto h = std::make_shared<Choice>(label(), nrChoices());
429 for (
auto&& branch : branches_)
430 h->push_back(branch->apply_f_op_g(gL, op));
436 if (label_ == label)
return branches_[index];
439 auto r = std::make_shared<Choice>(label_, branches_.size());
440 for (
auto&& branch : branches_)
441 r->push_back(branch->choose(label, index));
448 #ifdef GTSAM_ENABLE_BOOST_SERIALIZATION 450 friend class boost::serialization::access;
451 template <
class ARCHIVE>
452 void serialize(ARCHIVE& ar,
const unsigned int ) {
453 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(
Base);
454 ar& BOOST_SERIALIZATION_NVP(label_);
455 ar& BOOST_SERIALIZATION_NVP(branches_);
456 ar& BOOST_SERIALIZATION_NVP(allSame_);
464 template<
typename L,
typename Y>
468 template<
typename L,
typename Y>
474 template<
typename L,
typename Y>
480 template <
typename L,
typename Y>
482 auto a = std::make_shared<Choice>(label, 2);
483 NodePtr l1(
new Leaf(y1)), l2(
new Leaf(y2));
490 template <
typename L,
typename Y>
493 if (labelC.second != 2)
throw std::invalid_argument(
494 "DecisionTree: binary constructor called with non-binary label");
495 auto a = std::make_shared<Choice>(labelC.first, 2);
496 NodePtr l1(
new Leaf(y1)), l2(
new Leaf(y2));
503 template<
typename L,
typename Y>
505 const std::vector<Y>& ys) {
507 root_ =
create(labelCs.begin(), labelCs.end(), ys.begin(), ys.end());
511 template<
typename L,
typename Y>
513 const std::string& table) {
516 std::istringstream iss(table);
517 copy(std::istream_iterator<Y>(iss), std::istream_iterator<Y>(),
521 root_ =
create(labelCs.begin(), labelCs.end(), ys.begin(), ys.end());
525 template<
typename L,
typename Y>
527 Iterator begin, Iterator end,
const L& label) {
528 root_ = compose(begin, end, label);
532 template<
typename L,
typename Y>
535 const std::vector<DecisionTree> functions{f0, f1};
536 root_ = compose(functions.begin(), functions.end(), label);
540 template <
typename L,
typename Y>
541 template <
typename X,
typename Func>
545 auto L_of_L = [](
const L& label) {
return label; };
546 root_ = convertFrom<L, X>(other.
root_, L_of_L, Y_of_X);
550 template <
typename L,
typename Y>
551 template <
typename M,
typename X,
typename Func>
553 const std::map<M, L>& map, Func Y_of_X) {
554 auto L_of_M = [&map](
const M& label) -> L {
return map.at(label); };
555 root_ = convertFrom<M, X>(other.
root_, L_of_M, Y_of_X);
564 template <
typename L,
typename Y>
565 template <
typename Iterator>
567 Iterator begin, Iterator end,
const L& label)
const {
569 std::optional<L> highestLabel;
570 size_t nrChoices = 0;
571 for (Iterator it = begin; it != end; it++) {
572 if (it->root_->isLeaf())
574 std::shared_ptr<const Choice> c =
575 std::dynamic_pointer_cast<
const Choice>(it->root_);
576 if (!highestLabel || c->label() > *highestLabel) {
577 highestLabel = c->label();
578 nrChoices = c->nrChoices();
583 if (!nrChoices || !highestLabel || label > *highestLabel) {
584 auto choiceOnLabel = std::make_shared<Choice>(label, end - begin);
585 for (Iterator it = begin; it != end; it++)
586 choiceOnLabel->push_back(it->root_);
590 auto choiceOnHighestLabel =
591 std::make_shared<Choice>(*highestLabel, nrChoices);
593 for (
size_t index = 0; index < nrChoices; index++) {
596 std::vector<DecisionTree> functions;
597 for (Iterator it = begin; it != end; it++) {
600 functions.push_back(chosen);
603 NodePtr fi = compose(functions.begin(), functions.end(), label);
604 choiceOnHighestLabel->push_back(fi);
631 template<
typename L,
typename Y>
632 template<
typename It,
typename ValueIt>
634 It begin, It end, ValueIt beginY, ValueIt endY)
const {
636 size_t nrChoices = begin->second;
637 size_t size = endY - beginY;
640 It labelC = begin + 1;
644 if (size != nrChoices) {
645 std::cout <<
"Trying to create DD on " << begin->first << std::endl;
646 std::cout <<
"DecisionTree::create: expected " << nrChoices
647 <<
" values but got " << size <<
" instead" << std::endl;
648 throw std::invalid_argument(
"DecisionTree::create invalid argument");
650 auto choice = std::make_shared<Choice>(begin->first, endY - beginY);
651 for (ValueIt y = beginY; y != endY; y++)
652 choice->push_back(
NodePtr(
new Leaf(*y)));
659 std::vector<DecisionTree> functions;
660 size_t split = size / nrChoices;
661 for (
size_t i = 0; i < nrChoices; i++, beginY +=
split) {
662 NodePtr f = create<It, ValueIt>(labelC, end, beginY, beginY +
split);
663 functions.emplace_back(f);
665 return compose(functions.begin(), functions.end(), begin->first);
669 template <
typename L,
typename Y>
670 template <
typename M,
typename X>
673 std::function<L(
const M&)> L_of_M,
674 std::function<Y(
const X&)> Y_of_X)
const {
681 if (
auto leaf = std::dynamic_pointer_cast<const MXLeaf>(f)) {
682 return NodePtr(
new Leaf(Y_of_X(leaf->constant()), leaf->nrAssignments()));
687 auto choice = std::dynamic_pointer_cast<
const MXChoice>(f);
688 if (!choice)
throw std::invalid_argument(
689 "DecisionTree::convertFrom: Invalid NodePtr");
692 const M oldLabel = choice->label();
693 const L newLabel = L_of_M(oldLabel);
696 std::vector<LY> functions;
697 for (
auto&& branch : choice->branches()) {
698 functions.emplace_back(convertFrom<M, X>(branch, L_of_M, Y_of_X));
700 return LY::compose(functions.begin(), functions.end(), newLabel);
714 template <
typename L,
typename Y>
716 using F = std::function<void(const Y&)>;
723 if (
auto leaf = std::dynamic_pointer_cast<const Leaf>(node))
724 return f(leaf->constant());
727 auto choice = std::dynamic_pointer_cast<
const Choice>(node);
729 throw std::invalid_argument(
"DecisionTree::Visit: Invalid NodePtr");
730 for (
auto&& branch : choice->branches()) (*
this)(branch);
734 template <
typename L,
typename Y>
735 template <
typename Func>
751 template <
typename L,
typename Y>
753 using F = std::function<void(const typename DecisionTree<L, Y>::Leaf&)>;
760 if (
auto leaf = std::dynamic_pointer_cast<const Leaf>(node))
764 auto choice = std::dynamic_pointer_cast<
const Choice>(node);
766 throw std::invalid_argument(
"DecisionTree::VisitLeaf: Invalid NodePtr");
767 for (
auto&& branch : choice->branches()) (*
this)(branch);
771 template <
typename L,
typename Y>
772 template <
typename Func>
785 template <
typename L,
typename Y>
787 using F = std::function<void(const Assignment<L>&,
const Y&)>;
795 if (
auto leaf = std::dynamic_pointer_cast<const Leaf>(node))
796 return f(assignment, leaf->constant());
799 auto choice = std::dynamic_pointer_cast<
const Choice>(node);
801 throw std::invalid_argument(
"DecisionTree::VisitWith: Invalid NodePtr");
802 for (
size_t i = 0; i < choice->nrChoices(); i++) {
803 assignment[choice->label()] = i;
805 (*this)(choice->branches()[i]);
808 auto choice_it = assignment.find(choice->label());
809 assignment.erase(choice_it);
814 template <
typename L,
typename Y>
815 template <
typename Func>
822 template <
typename L,
typename Y>
825 visit([&total](
const Y& node) { total += 1; });
831 template <
typename L,
typename Y>
832 template <
typename Func,
typename X>
834 visit([&](
const Y& y) { x0 = f(y, x0); });
852 template <
typename L,
typename Y>
856 for (
auto&& kv : assignment) {
857 unique.insert(kv.first);
865 template <
typename L,
typename Y>
867 const CompareFunc& compare)
const {
871 template <
typename L,
typename Y>
873 const LabelFormatter& labelFormatter,
874 const ValueFormatter& valueFormatter)
const {
875 root_->print(s, labelFormatter, valueFormatter);
878 template<
typename L,
typename Y>
883 template<
typename L,
typename Y>
885 return root_->operator ()(x);
888 template<
typename L,
typename Y>
892 throw std::runtime_error(
893 "DecisionTree::apply(unary op) undefined for empty tree.");
899 template <
typename L,
typename Y>
901 const UnaryAssignment& op)
const {
904 throw std::runtime_error(
905 "DecisionTree::apply(unary op) undefined for empty tree.");
912 template<
typename L,
typename Y>
914 const Binary& op)
const {
917 throw std::runtime_error(
918 "DecisionTree::apply(binary op) undefined for empty trees.");
936 template<
typename L,
typename Y>
938 size_t cardinality,
const Binary& op)
const {
940 for (
size_t index = 1; index < cardinality; index++) {
942 result = result.
apply(chosen, op);
948 template <
typename L,
typename Y>
950 const LabelFormatter& labelFormatter,
951 const ValueFormatter& valueFormatter,
952 bool showZero)
const {
953 os <<
"digraph G {\n";
954 root_->dot(os, labelFormatter, valueFormatter, showZero);
955 os <<
" [ordering=out]}" << std::endl;
958 template <
typename L,
typename Y>
960 const LabelFormatter& labelFormatter,
961 const ValueFormatter& valueFormatter,
962 bool showZero)
const {
963 std::ofstream os((name +
".dot").c_str());
964 dot(os, labelFormatter, valueFormatter, showZero);
966 system((
"dot -Tpdf " + name +
".dot -o " + name +
".pdf >& /dev/null")
969 throw std::runtime_error(
"DecisionTree::dot system call failed");
972 template <
typename L,
typename Y>
974 const ValueFormatter& valueFormatter,
975 bool showZero)
const {
976 std::stringstream ss;
977 dot(ss, labelFormatter, valueFormatter, showZero);
const Y & operator()(const Assignment< L > &x) const override
evaluate
Definition: DecisionTree-inl.h:337
Decision Tree for use in DiscreteFactors.
NodePtr convertFrom(const typename DecisionTree< M, X >::NodePtr &f, std::function< L(const M &)> L_of_M, std::function< Y(const X &)> Y_of_X) const
Convert from a DecisionTree<M, X> to DecisionTree<L, Y>.
Definition: DecisionTree-inl.h:671
void print(const std::string &s, const LabelFormatter &labelFormatter, const ValueFormatter &valueFormatter) const override
print (as a tree).
Definition: DecisionTree-inl.h:281
NodePtr apply(const Unary &op) const override
apply unary operator.
Definition: DecisionTree-inl.h:390
void visit(Func f) const
Visit all leaves in depth-first fashion.
Definition: DecisionTree-inl.h:736
size_t nrAssignments() const
Return the number of assignments contained within this leaf.
Definition: DecisionTree-inl.h:73
L label_
Definition: DecisionTree-inl.h:175
std::vector< NodePtr > branches_
Definition: DecisionTree-inl.h:178
std::string serialize(const T &input)
serializes to a string
Definition: serialization.h:113
Definition: DecisionTree-inl.h:715
size_t nrAssignments_
Definition: DecisionTree-inl.h:58
Definition: DecisionTree-inl.h:752
VisitLeaf(F f)
Construct from folding function.
Definition: DecisionTree-inl.h:754
DecisionTree()
Definition: DecisionTree-inl.h:465
std::function< Y(const Y &)> Unary
Definition: DecisionTree.h:62
Choice(const Choice &f, const Choice &g, const Binary &op)
Construct from applying binary op to two Choice nodes.
Definition: DecisionTree-inl.h:231
std::set< L > labels() const
Definition: DecisionTree-inl.h:853
Choice(const L &label, const Choice &f, const Unary &op)
Construct from applying unary op to a Choice node.
Definition: DecisionTree-inl.h:352
NodePtr apply(const UnaryAssignment &op, const Assignment< L > &assignment) const override
Apply unary operator with assignment.
Definition: DecisionTree-inl.h:120
const L & label() const
Return the label of this choice node.
Definition: DecisionTree-inl.h:259
Definition: DecisionTree-inl.h:786
F f
folding function object.
Definition: DecisionTree-inl.h:755
Leaf(const Y &constant, size_t nrAssignments=1)
Constructor from constant.
Definition: DecisionTree-inl.h:64
NodePtr root_
A DecisionTree just contains the root. TODO(dellaert): make protected.
Definition: DecisionTree.h:136
void split(const G &g, const PredecessorMap< KEY > &tree, G &Ab1, G &Ab2)
Definition: graph-inl.h:245
NodePtr choose(const L &label, size_t index) const override
Definition: DecisionTree-inl.h:148
Definition: Testable.h:112
DecisionTree combine(const L &label, size_t cardinality, const Binary &op) const
Definition: DecisionTree-inl.h:937
Choice(const L &label, size_t count)
Constructor, given choice label and mandatory expected branch count.
Definition: DecisionTree-inl.h:225
void visitWith(Func f) const
Visit all leaves in depth-first fashion.
Definition: DecisionTree-inl.h:816
void operator()(const typename DecisionTree< L, Y >::NodePtr &node) const
Do a depth-first visit on the tree rooted at node.
Definition: DecisionTree-inl.h:758
Definition: DecisionTree.h:49
size_t nrLeaves() const
Return the number of leaves in the tree.
Definition: DecisionTree-inl.h:823
void dot(std::ostream &os, const LabelFormatter &labelFormatter, const ValueFormatter &valueFormatter, bool showZero) const override
Definition: DecisionTree-inl.h:99
void dot(std::ostream &os, const LabelFormatter &labelFormatter, const ValueFormatter &valueFormatter, bool showZero) const override
Definition: DecisionTree-inl.h:291
Y constant_
Definition: DecisionTree-inl.h:53
NodePtr apply(const UnaryAssignment &op, const Assignment< L > &assignment) const override
Apply unary operator with assignment.
Definition: DecisionTree-inl.h:396
bool sameLeaf(const Node &q) const override
polymorphic equality: is q a leaf and is it the same as this leaf?
Definition: DecisionTree-inl.h:81
void visitLeaf(Func f) const
Visit all leaves in depth-first fashion.
Definition: DecisionTree-inl.h:773
void print(const std::string &s, const LabelFormatter &labelFormatter, const ValueFormatter &valueFormatter) const override
print
Definition: DecisionTree-inl.h:93
void push_back(const NodePtr &node)
Definition: DecisionTree-inl.h:272
Leaf()
Default constructor for serialization.
Definition: DecisionTree-inl.h:61
Definition: DecisionTree-inl.h:173
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:201
X fold(Func f, X x0) const
Fold a binary function over the tree, returning accumulator.
Definition: DecisionTree-inl.h:833
NodePtr choose(const L &label, size_t index) const override
Definition: DecisionTree-inl.h:435
DecisionTree apply(const Unary &op) const
Definition: DecisionTree-inl.h:889
NodePtr create(It begin, It end, ValueIt beginY, ValueIt endY) const
Definition: DecisionTree-inl.h:633
typename Node::Ptr NodePtr
Definition: DecisionTree.h:133
void operator()(const typename DecisionTree< L, Y >::NodePtr &node)
Do a depth-first visit on the tree rooted at node.
Definition: DecisionTree-inl.h:793
Definition: Assignment.h:37
Definition: chartTesting.h:28
NodePtr apply(const Unary &op) const override
Definition: DecisionTree-inl.h:114
void print(const std::string &s, const LabelFormatter &labelFormatter, const ValueFormatter &valueFormatter) const
GTSAM-style print.
Definition: DecisionTree-inl.h:872
bool empty() const
Check if tree is empty.
Definition: DecisionTree.h:240
const Y & operator()(const Assignment< L > &x) const
Definition: DecisionTree-inl.h:884
bool equals(const Node &q, const CompareFunc &compare) const override
equality
Definition: DecisionTree-inl.h:324
Visit(F f)
Construct from folding function.
Definition: DecisionTree-inl.h:717
Definition: DecisionTree-inl.h:51
Assignment< L > assignment
Assignment, mutating through recursion.
Definition: DecisionTree-inl.h:789
bool operator==(const DecisionTree &q) const
Definition: DecisionTree-inl.h:879
void dot(std::ostream &os, const LabelFormatter &labelFormatter, const ValueFormatter &valueFormatter, bool showZero=true) const
Definition: DecisionTree-inl.h:949
bool sameLeaf(const Leaf &q) const override
Choice-Leaf equality: always false.
Definition: DecisionTree-inl.h:314
void operator()(const typename DecisionTree< L, Y >::NodePtr &node) const
Do a depth-first visit on the tree rooted at node.
Definition: DecisionTree-inl.h:721
F f
folding function object.
Definition: DecisionTree-inl.h:718
Definition: DecisionTree.h:74
bool equals(const Node &q, const CompareFunc &compare) const override
equality up to tolerance
Definition: DecisionTree-inl.h:86
std::pair< Key, size_t > LabelC
Definition: DecisionTree.h:67
VisitWith(F f)
Construct from folding function.
Definition: DecisionTree-inl.h:788
Choice(const L &label, const Choice &f, const UnaryAssignment &op, const Assignment< L > &assignment)
Constructor which accepts a UnaryAssignment op and the corresponding assignment.
Definition: DecisionTree-inl.h:370
bool sameLeaf(const Leaf &q) const override
Leaf-Leaf equality.
Definition: DecisionTree-inl.h:76
bool sameLeaf(const Node &q) const override
polymorphic equality: if q is a leaf, could be...
Definition: DecisionTree-inl.h:319
DecisionTree choose(const L &label, size_t index) const
Definition: DecisionTree.h:341
F f
folding function object.
Definition: DecisionTree-inl.h:790
const Y & constant() const
Return the constant.
Definition: DecisionTree-inl.h:68
const Y & operator()(const Assignment< L > &x) const override
Definition: DecisionTree-inl.h:109
Choice()
Default constructor for serialization.
Definition: DecisionTree-inl.h:191