36typedef tree<Node>::pre_order_iterator
Iter;
37typedef tree<Node>::post_order_iterator
PostIter;
75 std::optional<std::reference_wrapper<SearchSpace>>
SSref;
78 Program(
const std::reference_wrapper<SearchSpace> s,
const tree<Node> t)
81 SSref = std::optional<std::reference_wrapper<SearchSpace>>{s};
88 SSref = std::optional<std::reference_wrapper<SearchSpace>>{s};
94 auto head =
Tree.begin();
96 return head.node->get_complexity();
102 auto head =
Tree.begin();
104 return head.node->get_linear_complexity();
110 int size(
bool include_weight=
true)
const{
111 auto head =
Tree.begin();
113 return head.node->get_size(include_weight);
123 return top.node->get_size(include_weight);
131 return 1+
Tree.max_depth();
139 return 1+
Tree.max_depth(top);
147 return 1+
Tree.depth(top);
157 const vector<float>& class_weights)
160 this->is_fitted_ =
true;
174 this->Tree = new_program.
Tree;
175 this->is_fitted_ =
false;
178 if (new_program.
SSref.has_value())
179 this->SSref = new_program.
SSref;
197 template <
typename R,
typename W>
203 return Tree.begin().node->predict<R>(d, weights);
208 float const * wptr = weights.data();
220 template <
typename R = RetType>
233 template <
typename R = RetType>
246 template <
typename R = RetType>
258 template <PT P = PType>
291 template <PT P = PType>
305 const vector<float>& class_weights);
314 const auto& node = i.node->data;
320 if (node.weight_is_fixed)
327 || (node.get_is_weighted() &&
IsWeighable(node.ret_type)
345 const auto& node = t.node->data;
348 if (node.weight_is_fixed)
352 || (node.get_is_weighted() &&
IsWeighable(node.ret_type)
378 auto& node = i.node->data;
381 if (node.weight_is_fixed)
385 || (node.get_is_weighted() &&
IsWeighable(node.ret_type)
404 void lock_nodes(
int end_depth=0,
bool keep_leaves_unlocked=
true,
bool keep_current_weights=
false)
421 auto tree_iter =
Tree.begin();
423 std::for_each(
Tree.begin(),
Tree.end(),
425 auto d = Tree.depth(tree_iter);
426 std::advance(tree_iter, 1);
429 if (n.get_is_weighted() && d<end_depth)
430 n.weight_is_fixed = keep_current_weights;
432 n.weight_is_fixed = false;
436 if (
IsLeaf(n.node_type)) {
437 if (d<end_depth && !keep_leaves_unlocked)
438 n.node_is_fixed = true;
442 n.node_is_fixed = false;
450 n.node_is_fixed =
true;
452 n.node_is_fixed =
false;
459 if (keep_leaves_unlocked)
461 n.set_keep_split_feature(false);
466 n.set_keep_split_feature(d+1<end_depth);
485 string get_model(
string fmt=
"compact",
bool pretty=
false)
const
487 auto head =
Tree.begin();
489 return head.node->get_tree_model(pretty);
492 return head.node->get_model(pretty);
505 string out =
"digraph G {\n";
506 if (! extras.empty())
507 out += fmt::format(
"{}\n", extras);
509 auto get_id = [](
const auto& n){
511 return n->data.get_name(
false);
513 return fmt::format(
"{}",fmt::ptr(n)).substr(2);
516 std::map<string, unsigned int> node_count;
518 for (
Iter iter =
Tree.begin(); iter!=
Tree.end(); iter++)
520 const auto& parent = iter.node;
523 string parent_id = get_id(parent);
534 if (i==0 && parent->data.get_is_weighted())
537 string font_color =
"";
538 if (parent->data.weight_is_fixed) {
539 font_color =
", fontcolor=lightcoral";
542 out +=
"y [shape=box];\n";
543 out += fmt::format(
"y -> \"{}\" [label=\"{:.2f}\"{}];\n",
553 string node_label = parent->data.get_name(is_constant);
556 std::string feature = parent->data.get_feature();
557 std::string threshold = fmt::format(
"{:.2f}", parent->data.W);
560 if (parent->data.keep_split_feature)
562 if (parent->data.weight_is_fixed)
565 node_label = fmt::format(
"{} >= {}?", feature, threshold);
568 node_label = fmt::format(
"Add");
571 string node_style = parent->data.get_prob_change() >0.0 ?
"" :
", style=filled, fillcolor=lightcoral";
572 out += fmt::format(
"\"{}\" [label=\"{}\"{}];\n", parent_id, node_label, node_style);
575 auto kid = iter.node->first_child;
576 for (
int j = 0; j < iter.number_of_children(); ++j)
578 string edge_label=
"";
579 string head_label=
"";
580 string tail_label=
"";
581 bool use_head_tail_labels =
false;
583 string kid_id = get_id(kid);
587 if (kid->data.get_is_weighted()
591 edge_label = fmt::format(
"{:.2f}",kid->data.W);
595 use_head_tail_labels=
true;
597 tail_label = fmt::format(
">= {:.2f}",parent->data.W);
603 head_label=edge_label;
606 use_head_tail_labels=
true;
613 head_label = edge_label;
617 edge_label = fmt::format(
"class {}", j);
621 string font_color =
"";
622 if (kid->data.weight_is_fixed) {
623 font_color =
", fontcolor=lightcoral";
626 if (use_head_tail_labels){
627 out += fmt::format(
"\"{}\" -> \"{}\" [headlabel=\"{}\",taillabel=\"{}\"{}];\n",
636 out += fmt::format(
"\"{}\" -> \"{}\" [label=\"{}\"{}];\n",
643 kid = kid->next_sibling;
649 out += fmt::format(
"\"{}\" -> \"{}\" [label=\"\"];\n",
655 out += fmt::format(
"\"{}\" [label=\"{:.2f}\"{}];\n",
665 out +=
"label=\"^ split feature fixed, * split threshold fixed\";\nlabelloc=bottom;\nfontsize=10;";
674 vector<Node> linear_program;
676 linear_program.push_back(i.node->data);
677 return linear_program;
688template<ProgramType PType>
690 const vector<float>& class_weights)
696 WO.update((*
this), d, class_weights);
703template<ProgramType PType>
709template<ProgramType PType>
712 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)
std::conditional_t< PType==PT::BinaryClassifier, ArrayXf, std::conditional_t< PType==PT::MulticlassClassifier, ArrayXXf, RetType > > TreeType
the type of output from the tree object
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...
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
Program< PType > & fit(const Dataset &d, const vector< float > &class_weights)
Fit the program with optional per-class weights for classification.
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.
void update_weights(const Dataset &d, const vector< float > &class_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)
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...