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>
44 #ifdef DT_DEBUG_MEMORY
45 template<
typename L,
typename Y>
46 int DecisionTree<L, Y>::Node::nrNodes = 0;
52 template<
typename L,
typename Y>
62 constant_(constant) {}
71 return constant_ == q.constant_;
76 return (q.isLeaf() && q.sameLeaf(*
this));
81 const Leaf* other =
dynamic_cast<const Leaf*
> (&q);
82 if (!other)
return false;
83 return fabs(
double(this->constant_ - other->constant_)) < tol;
87 void print(
const std::string& s)
const {
89 if (showZero || constant_) std::cout << s <<
" Leaf " << constant_ << std::endl;
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";
115 NodePtr apply_f_op_g(
const Node& g,
const Binary& op)
const {
116 return g.apply_g_op_fL(*
this, op);
120 NodePtr apply_g_op_fL(
const Leaf& fL,
const Binary& op)
const {
121 NodePtr h(
new Leaf(op(fL.constant_, constant_)));
126 NodePtr apply_g_op_fC(
const Choice& fC,
const Binary& op)
const {
127 return fC.apply_fC_op_gL(*
this, op);
135 bool isLeaf()
const {
return true; }
142 template<
typename L,
typename Y>
149 std::vector<NodePtr> branches_;
155 typedef boost::shared_ptr<const Choice> ChoicePtr;
160 #ifdef DT_DEBUG_MEMORY
161 std::std::cout << Node::nrNodes <<
" destructing (Choice) " << this->id() << std::std::endl;
167 #ifndef DT_NO_PRUNING
169 assert(f->branches().size() > 0);
171 assert(f0->isLeaf());
172 NodePtr newLeaf(
new Leaf(boost::dynamic_pointer_cast<const Leaf>(f0)->constant()));
179 bool isLeaf()
const {
return false; }
183 label_(label), allSame_(true) {
184 branches_.reserve(count);
194 if (f.label() > g.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()) {
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));
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));
218 const L& label()
const {
222 size_t nrChoices()
const {
223 return branches_.size();
226 const std::vector<NodePtr>& branches()
const {
233 if (allSame_ && !branches_.empty()) {
234 allSame_ = node->sameLeaf(*branches_.back());
236 branches_.push_back(node);
240 void print(
const std::string& s)
const {
241 std::cout << s <<
" Choice(";
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());
249 void dot(std::ostream& os,
bool showZero)
const {
250 os <<
"\"" << this->id() <<
"\" [shape=circle, label=\"" << label_
252 for (
size_t i = 0; i < branches_.size(); i++) {
257 const Leaf* leaf =
dynamic_cast<const Leaf*
> (branch.get());
258 if (leaf && !leaf->
constant())
continue;
261 os <<
"\"" << this->id() <<
"\" -> \"" << branch->id() <<
"\"";
262 if (i == 0) os <<
" [style=dashed]";
263 if (i > 1) os <<
" [style=bold]";
265 branch->dot(os, showZero);
276 return (q.isLeaf() && q.sameLeaf(*
this));
282 if (!other)
return false;
283 if (this->label_ != other->label_)
return false;
284 if (branches_.size() != other->branches_.size())
return false;
286 for (
size_t i = 0; i < branches_.size(); i++)
287 if (!(branches_[i]->
equals(*(other->branches_[i]), tol)))
return false;
296 std::cout <<
"Trying to find value for " << label_ << std::endl;
297 throw std::invalid_argument(
298 "DecisionTree::operator(): value undefined for a label");
301 size_t index = x.at(label_);
302 NodePtr child = branches_[index];
310 label_(label), allSame_(true) {
312 branches_.reserve(f.branches_.size());
313 BOOST_FOREACH (
const NodePtr& branch, f.branches_)
314 push_back(branch->apply(op));
319 boost::shared_ptr<Choice> r(
new Choice(label_, *
this, op));
328 NodePtr apply_f_op_g(
const Node& g,
const Binary& op)
const {
329 return g.apply_g_op_fC(*
this, op);
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));
341 NodePtr apply_g_op_fC(const Choice& fC, const Binary& op)
const {
342 boost::shared_ptr<Choice> h(
new Choice(fC, *
this, op));
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));
358 return branches_[index];
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));
372 template<
typename L,
typename Y>
376 template<
typename L,
typename Y>
382 template<
typename L,
typename Y>
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));
395 root_ = Choice::Unique(a);
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));
408 root_ = Choice::Unique(a);
412 template<
typename L,
typename Y>
414 const std::vector<Y>& ys) {
416 root_ = create(labelCs.begin(), labelCs.end(), ys.begin(), ys.end());
420 template<
typename L,
typename Y>
422 const std::string& table) {
426 std::istringstream iss(table);
427 copy(std::istream_iterator<Y>(iss), std::istream_iterator<Y>(),
431 root_ = create(labelCs.begin(), labelCs.end(), ys.begin(), ys.end());
435 template<
typename L,
typename Y>
437 Iterator begin, Iterator end,
const L& label) {
438 root_ = compose(begin, end, label);
442 template<
typename L,
typename Y>
445 std::vector<DecisionTree> functions;
447 root_ = compose(functions.begin(), functions.end(), label);
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);
464 template<
typename L,
typename Y>
template<
typename Iterator>
466 Iterator begin, Iterator end,
const L& label)
const {
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());
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);
489 boost::shared_ptr<Choice> choiceOnHighestLabel(
new Choice(*highestLabel, *nrChoices));
491 for (
size_t index = 0; index < *nrChoices; index++) {
494 std::vector<DecisionTree> functions;
495 for (Iterator it = begin; it != end; it++) {
497 DecisionTree chosen = it->choose(*highestLabel, index);
498 functions.push_back(chosen);
501 NodePtr fi = compose(functions.begin(), functions.end(), label);
502 choiceOnHighestLabel->push_back(fi);
504 return Choice::Unique(choiceOnHighestLabel);
528 template<
typename L,
typename Y>
529 template<
typename It,
typename ValueIt>
531 It begin, It end, ValueIt beginY, ValueIt endY)
const {
534 size_t nrChoices = begin->second;
535 size_t size = endY - beginY;
538 It labelC = begin + 1;
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");
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);
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);
562 return compose(functions.begin(), functions.end(), begin->first);
566 template<
typename L,
typename Y>
567 template<
typename M,
typename X>
569 const typename DecisionTree<M, X>::NodePtr& f,
const std::map<M, L>& map,
570 boost::function<Y(
const X&)> op) {
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;
580 const MXLeaf* leaf =
dynamic_cast<const MXLeaf*
> (f.get());
581 if (leaf)
return NodePtr(
new Leaf(op(leaf->constant())));
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");
589 M oldLabel = choice->label();
590 L newLabel = map.at(oldLabel);
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;
598 return LY::compose(functions.begin(), functions.end(), newLabel);
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);
607 template<
typename L,
typename Y>
612 template<
typename L,
typename Y>
614 return root_->equals(*other.root_);
617 template<
typename L,
typename Y>
619 return root_->operator ()(x);
622 template<
typename L,
typename Y>
628 template<
typename L,
typename Y>
630 const Binary& op)
const {
632 NodePtr h = root_->apply_f_op_g(*g.root_, op);
647 template<
typename L,
typename Y>
649 size_t cardinality,
const Binary& op)
const {
651 for (
size_t index = 1; index < cardinality; index++) {
653 result = result.
apply(chosen, op);
659 template<
typename L,
typename Y>
661 os <<
"digraph G {\n";
662 root_->dot(os, showZero);
663 os <<
" [ordering=out]}" << std::endl;
666 template<
typename L,
typename Y>
668 std::ofstream os((name +
".dot").c_str());
671 (
"dot -Tpdf " + name +
".dot -o " + name +
".pdf >& /dev/null").c_str());
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