37typedef tree<Node>::pre_order_iterator
Iter;
38typedef tree<Node>::post_order_iterator
PostIter;
76 std::optional<std::reference_wrapper<SearchSpace>>
SSref;
79 Program(
const std::reference_wrapper<SearchSpace> s,
const tree<Node> t)
82 SSref = std::optional<std::reference_wrapper<SearchSpace>>{s};
89 SSref = std::optional<std::reference_wrapper<SearchSpace>>{s};
95 auto head =
Tree.begin();
97 return head.node->get_complexity();
103 auto head =
Tree.begin();
105 return head.node->get_linear_complexity();
111 int size(
bool include_weight=
true)
const{
112 auto head =
Tree.begin();
114 return head.node->get_size(include_weight);
124 return top.node->get_size(include_weight);
132 return 1+
Tree.max_depth();
140 return 1+
Tree.max_depth(top);
148 return 1+
Tree.depth(top);
154 this->is_fitted_ =
true;
168 this->Tree = new_program.
Tree;
169 this->is_fitted_ =
false;
172 if (new_program.
SSref.has_value())
173 this->SSref = new_program.
SSref;
191 template <
typename R,
typename W>
197 return Tree.begin().node->predict<R>(d, weights);
202 float const * wptr = weights.data();
214 template <
typename R = RetType>
227 template <
typename R = RetType>
240 template <
typename R = RetType>
252 template <PT P = PType>
285 template <PT P = PType>
307 const auto& node = i.node->data;
313 if (node.weight_is_fixed)
320 || (node.get_is_weighted() &&
IsWeighable(node.ret_type)) )
337 const auto& node = t.node->data;
340 if (node.weight_is_fixed)
344 || (node.get_is_weighted() &&
IsWeighable(node.ret_type)) )
369 auto& node = i.node->data;
372 if (node.weight_is_fixed)
376 || (node.get_is_weighted() &&
IsWeighable(node.node_type)) )
394 void lock_nodes(
int end_depth=0,
bool keep_leaves_unlocked=
true,
bool keep_current_weights=
false)
411 auto tree_iter =
Tree.begin();
413 std::for_each(
Tree.begin(),
Tree.end(),
415 auto d = Tree.depth(tree_iter);
416 std::advance(tree_iter, 1);
419 if (n.get_is_weighted() && d<end_depth)
420 n.weight_is_fixed = keep_current_weights;
422 n.weight_is_fixed = false;
426 if (
IsLeaf(n.node_type)) {
427 if (d<end_depth && !keep_leaves_unlocked)
428 n.node_is_fixed = true;
432 n.node_is_fixed = false;
440 n.node_is_fixed =
true;
442 n.node_is_fixed =
false;
449 if (keep_leaves_unlocked)
451 n.set_keep_split_feature(false);
456 n.set_keep_split_feature(d+1<end_depth);
475 string get_model(
string fmt=
"compact",
bool pretty=
false)
const
477 auto head =
Tree.begin();
479 return head.node->get_tree_model(pretty);
482 return head.node->get_model(pretty);
495 string out =
"digraph G {\n";
496 if (! extras.empty())
497 out += fmt::format(
"{}\n", extras);
499 auto get_id = [](
const auto& n){
501 return n->data.get_name(
false);
503 return fmt::format(
"{}",fmt::ptr(n)).substr(2);
506 std::map<string, unsigned int> node_count;
508 for (
Iter iter =
Tree.begin(); iter!=
Tree.end(); iter++)
510 const auto& parent = iter.node;
513 string parent_id = get_id(parent);
524 if (i==0 && parent->data.get_is_weighted())
527 string font_color =
"";
528 if (parent->data.weight_is_fixed) {
529 font_color =
", fontcolor=lightcoral";
532 out +=
"y [shape=box];\n";
533 out += fmt::format(
"y -> \"{}\" [label=\"{:.2f}\"{}];\n",
543 string node_label = parent->data.get_name(is_constant);
546 std::string feature = parent->data.get_feature();
547 std::string threshold = fmt::format(
"{:.2f}", parent->data.W);
550 if (parent->data.keep_split_feature)
552 if (parent->data.weight_is_fixed)
555 node_label = fmt::format(
"{} >= {}?", feature, threshold);
558 node_label = fmt::format(
"Add");
561 string node_style = parent->data.get_prob_change() >0.0 ?
"" :
", style=filled, fillcolor=lightcoral";
562 out += fmt::format(
"\"{}\" [label=\"{}\"{}];\n", parent_id, node_label, node_style);
565 auto kid = iter.node->first_child;
566 for (
int j = 0; j < iter.number_of_children(); ++j)
568 string edge_label=
"";
569 string head_label=
"";
570 string tail_label=
"";
571 bool use_head_tail_labels =
false;
573 string kid_id = get_id(kid);
577 if (kid->data.get_is_weighted()
581 edge_label = fmt::format(
"{:.2f}",kid->data.W);
585 use_head_tail_labels=
true;
587 tail_label = fmt::format(
">= {:.2f}",parent->data.W);
593 head_label=edge_label;
596 use_head_tail_labels=
true;
603 head_label = edge_label;
607 string font_color =
"";
608 if (kid->data.weight_is_fixed) {
609 font_color =
", fontcolor=lightcoral";
612 if (use_head_tail_labels){
613 out += fmt::format(
"\"{}\" -> \"{}\" [headlabel=\"{}\",taillabel=\"{}\"{}];\n",
622 out += fmt::format(
"\"{}\" -> \"{}\" [label=\"{}\"{}];\n",
629 kid = kid->next_sibling;
635 out += fmt::format(
"\"{}\" -> \"{}\" [label=\"\"];\n",
641 out += fmt::format(
"\"{}\" [label=\"{:.2f}\"{}];\n",
651 out +=
"label=\"^ split feature fixed, * split threshold fixed\";\nlabelloc=bottom;\nfontsize=10;";
660 vector<Node> linear_program;
662 linear_program.push_back(i.node->data);
663 return linear_program;
674template<ProgramType PType>
681 WO.update((*
this), d);
688template<ProgramType PType>
694template<ProgramType PType>
697 j.at(
"Tree").get_to(p.
Tree);
holds variable type data.
#define HANDLE_ERROR_THROW(err)
< nsga2 selection operator for getting the front
auto Isnt(DataType dt) -> bool
Eigen::Array< bool, Eigen::Dynamic, 1 > ArrayXb
auto IsWeighable() noexcept -> bool
void from_json(const json &j, Fitness &f)
auto IsLeaf(NodeType nt) noexcept -> bool
auto Is(NodeType nt) -> bool
tree< Node >::pre_order_iterator Iter
tree< Node >::post_order_iterator PostIter
void to_json(json &j, const Fitness &f)
Eigen::Array< int, Eigen::Dynamic, 1 > ArrayXi
An individual program, a.k.a. model.
Program(const std::reference_wrapper< SearchSpace > s, const tree< Node > t)
Program< PType > & replace_program(const json &j)
Replace the current program from a JSON representation, invalidating fitness.
TreeType predict_proba(const Dataset &d)
void lock_nodes(int end_depth=0, bool keep_leaves_unlocked=true, bool keep_current_weights=false)
Iterates over the program, locking the nodes until it reaches a certain depth. If the node is a Split...
void update_weights(const Dataset &d)
Updates the program's weights using non-linear least squares.
typename std::conditional_t< PType==PT::Regressor, ArrayXf, std::conditional_t< PType==PT::BinaryClassifier, ArrayXb, std::conditional_t< PType==PT::MulticlassClassifier, ArrayXi, std::conditional_t< PType==PT::Representer, ArrayXXf, ArrayXf > > > > RetType
the return type of the tree when calling :func:predict.
std::optional< std::reference_wrapper< SearchSpace > > SSref
int linear_complexity() const
count the linear complexity of the program.
RetType predict(const Ref< const ArrayXXf > &X)
Convenience function to call predict directly from X data.
void set_weights(const ArrayXf &weights)
Set the weights in the tree from an array of weights.
TreeType predict(const Dataset &d)
the standard predict function. Returns the output of the Tree directly.
static constexpr PT program_type
R predict_with_weights(const Dataset &d, const W **weights)
std::conditional_t< PType==PT::BinaryClassifier, ArrayXf, std::conditional_t< PType==PT::MulticlassClassifier, ArrayXXf, RetType > > TreeType
the type of output from the tree object
int complexity() const
count the (recursive) complexity of the program.
Program< PType > & replace_program(const Program< PType > &new_program)
Replace the current program with a new program, invalidating fitness.
int size_at(Iter &top, bool include_weight=true) const
count the size of a given subtree, optionally including the weights in weighted nodes....
ArrayXf get_weights()
Get the weights of the tree as an array.
Program< PType > & fit(const Dataset &d)
int depth() const
count the tree depth of the program. The depth is not influenced by weighted nodes.
auto predict_with_weights(const Dataset &d, const ArrayXf &weights)
int get_n_weights() const
returns the number of weights in the program.
int depth_at(Iter &top) const
count the depth of a given subtree. The depth is not influenced by weighted nodes....
vector< Node > linearize() const
turns program tree into a linear program.
ArrayXi predict(const Dataset &d)
Specialized predict function for multiclass classification.
void set_search_space(const std::reference_wrapper< SearchSpace > s)
ArrayXb predict(const Dataset &d)
Specialized predict function for binary classification.
string get_dot_model(string extras="") const
string get_model(string fmt="compact", bool pretty=false) const
Get the model as a string.
TreeType predict_proba(const Ref< const ArrayXXf > &X)
Predict probabilities from X.
int depth_to_reach(Iter &top) const
count the depth until reaching the given subtree. The depth is not influenced by weighted nodes....
Program< PType > & fit(const Ref< const ArrayXXf > &X, const Ref< const ArrayXf > &y)
Convenience function to call fit directly from X,y data.
int size(bool include_weight=true) const
count the tree size of the program, including the weights in weighted nodes.
Holds a search space, consisting of operations and terminals and functions, and methods to sample tha...