45using TreeIter = tree<Node>::pre_order_iterator;
54extern std::unordered_map<std::size_t, std::string>
ArgsName;
154 template<
typename PT>
187 SearchSpace(
const Dataset& d,
const unordered_map<string,float>& user_ops = {},
bool weights_init =
true){
188 init(d,user_ops,weights_init);
195 void init(
const Dataset& d,
const unordered_map<string,float>& user_ops = {},
bool weights_init =
true);
202 auto msg = fmt::format(
"{} not in node_map\n",R);
216 auto msg = fmt::format(
"{} not in node_map.at({})\n", sig_hash, R);
230 if (
check(R,sig_hash)){
231 if (
node_map.at(R).at(sig_hash).find(type) ==
node_map.at(R).at(sig_hash).end()){
233 auto msg = fmt::format(
"{} not in node_map[{}][{}]\n",type, sig_hash, R);
246 template<
typename Iter>
248 return !std::all_of(start, end, [](
const auto& w) {
return w<=0.0; });
258 check(R, sig_hash, type);
259 return node_map.at(R).at(sig_hash).at(type);
279 for (
const auto& [arg, name_map] : arg_w_map)
281 for (
const auto& [name, w]: name_map)
299 for (
const auto& [name, w]: name_map)
333 std::fill(data_type_weights.begin(), data_type_weights.end(), 1.0f);
340 data_type_weights.begin(),
342 return std::reduce(tw.second.begin(), tw.second.end()); }
346 data_type_weights.end()))
352 auto match = *r.select_randomly(
355 data_type_weights.begin(),
356 data_type_weights.end()
360 vector<float> match_weights(match.second.size());
363 std::fill(match_weights.begin(), match_weights.end(), 1.0f);
370 match_weights.begin(),
371 [](
const auto& w){ return w; });
374 match_weights.end()))
378 return *r.select_randomly(match.second.begin(), match.second.end(),
379 match_weights.begin(), match_weights.end());
399 std::fill(match_weights.begin(), match_weights.end(), 1.0f);
409 match_weights.begin(),
410 [](
const auto& w){ return w; }
414 match_weights.end()))
420 match_weights.begin(),
421 match_weights.end());
441 auto arg_match = *r.select_randomly(ret_match.begin(),
446 vector<float> name_w =
get_weights(ret, arg_match.first);
451 return (*r.select_randomly(arg_match.second.begin(),
452 arg_match.second.end(),
454 name_w.end())).second;
469 vector<Node> matches;
470 vector<float> weights;
471 for (
const auto& [arg_hash, node_type_map]: ret_match)
473 if (node_type_map.find(type) != node_type_map.end())
476 matches.push_back(node_type_map.at(type));
483 std::fill(weights.begin(), weights.end(), 1.0f);
486 if ( (weights.size()==0)
491 return (*r.select_randomly(matches.begin(),
500 bool force_return=
false)
const
506 vector<Node> matches;
507 vector<float> weights;
508 for (
const auto& [arg_hash, node_type_map] :
node_map.at(R))
510 auto node = node_type_map.find(type);
511 if (node != node_type_map.end()
512 && node->second.arg_types.size() == arg_count)
514 matches.push_back(node->second);
520 std::fill(weights.begin(), weights.end(), 1.0f);
524 return *r.select_randomly(matches.begin(), matches.end(),
525 weights.begin(), weights.end());
535 bool terminal_compatible=
true,
536 int max_args=0)
const
546 vector<Node> matches;
547 vector<float> weights;
549 for (
const auto& [args_type, name_map]: args_map) {
550 for (
const auto& [name, node]: name_map) {
551 auto node_arg_types = node.get_arg_types();
555 auto within_size_limit = !(max_args) || (node.get_arg_count() <= max_args);
558 if (
in(node_arg_types, arg)
564 if (terminal_compatible) {
565 bool compatible =
true;
566 for (
const auto& arg_type: node_arg_types) {
567 if (arg_type != arg) {
578 matches.push_back(node);
584 if ( (weights.size()==0)
589 return (*r.select_randomly(matches.begin(), matches.end(),
590 weights.begin(), weights.end()));
605 if ( (match_weights.size()==0)
607 match_weights.end())) )
610 return (*r.select_randomly(matches.begin(),
612 match_weights.begin(),
629 string output =
"=== Search space ===\n";
630 output += fmt::format(
"terminal_map: {}\n", this->terminal_map);
631 output += fmt::format(
"terminal_weights: {}\n", this->terminal_weights);
633 for (
const auto& [ret_type, v] : this->node_map) {
634 for (
const auto& [args_type, v2] : v) {
635 for (
const auto& [node_type, node] : v2) {
636 output += fmt::format(
"{} node_map[{}][{}][{}] = {}, weight = {}\n",
642 this->node_map_weights.at(ret_type).at(args_type).at(node_type)
651 tree<Node>&
PTC2(tree<Node>& Tree, tree<Node>::iterator root,
int max_d,
int max_size,
bool start_from_decision_trees)
const;
653 template<NodeType NT,
typename S>
654 requires (!is_in_v<NT, NodeType::Terminal, NodeType::Constant, NodeType::MeanLabel>)
656 const auto& unique_data_types,
663 for (
auto arg: S::get_arg_types()){
664 if (!
in(unique_data_types,arg) ){
668 ArgsName[S::hash()] = fmt::format(
"{}", S::get_arg_types());
669 return Node(
NT, S{}, weighted);
672 template<NodeType NT,
typename S>
674 const unordered_map<string,float>& user_ops,
675 const vector<DataType>& unique_data_types
678 bool use_all = user_ops.size() == 0;
681 bool weighted =
false;
688 auto n = n_maybe.value();
689 node_map[n.ret_type][n.args_type()][n.node_type] = n;
691 float w = use_all? 1.0 : user_ops.at(name);
696 template <
NodeType NT,
typename Sigs, std::size_t...
Is>
697 constexpr void AddNodes(
const unordered_map<string, float> &user_ops,
698 const vector<DataType> &unique_data_types,
699 std::index_sequence<Is...>)
704 template<NodeType NT>
705 void MakeNodes(
const unordered_map<string,float>& user_ops,
706 const vector<DataType>& unique_data_types
712 bool use_all = user_ops.size() == 0;
716 if (!use_all & user_ops.find(name) == user_ops.end())
720 constexpr auto size = std::tuple_size<signatures>::value;
724 std::make_index_sequence<size>()
728 template<std::size_t...
Is>
730 const vector<DataType>& unique_data_types,
731 std::index_sequence<Is...>
734 auto nt = [](
auto i) {
return static_cast<NodeType>(1UL << i); };
743 int loc = r.rnd_int(0, Q.size()-1);
744 std::swap(Q[loc], Q[Q.size()-1]);
758 max_size = r.rnd_int(1, params.
max_size);
763 auto Tree = tree<Node>();
764 tree<Node>::iterator spot;
776 auto spot_logit = Tree.insert(Tree.begin(), node_logit);
785 auto spot_offset = Tree.append_child(spot_logit);
787 spot = Tree.replace(spot_offset, node_offset);
800 "Multiclass Softmax supports between 2 and {} classes; got {}.\n",
810 spot = Tree.insert(Tree.begin(), node_softmax);
815 std::optional<Node> opt=std::nullopt;
817 if (max_size>1 && max_d>1){
831 spot = Tree.insert(Tree.begin(), root);
848 return P(*
this, Tree);
858 template <
typename FormatContext>
860 string output =
SS.
repr();
861 return formatter<string_view>::format(output, ctx);
holds variable type data.
#define HANDLE_ERROR_THROW(err)
namespace containing Data structures used in Brush
namespace containing various utility functions
void print(T t)
prints comma delimited container contents.
vector< T > softmax(const vector< T > &w)
return the softmax transformation of a vector.
bool in(const V &v, const T &i)
check if element is in vector.
< nsga2 selection operator for getting the front
Program< PT::Representer > RepresenterProgram
Program< PT::BinaryClassifier > ClassifierProgram
auto Is(NodeType nt) -> bool
std::unordered_map< std::size_t, std::string > ArgsName
vector< Node > generate_terminals(const Dataset &d, const bool weights_init)
generate terminals from the dataset features and random constants.
T RandomDequeue(std::vector< T > &Q)
queue for make program
tree< Node >::pre_order_iterator Iter
tree< Node >::pre_order_iterator TreeIter
std::map< NodeType, std::string > NodeTypeName
Program< PT::Regressor > RegressorProgram
Program< PT::MulticlassClassifier > MulticlassClassifierProgram
class holding the data for a node in a tree.
bool weight_is_fixed
whether the weight should be kept during variation. Notice that weight_is_fixed alows us to fix the w...
NodeType node_type
the node type
DataType ret_type
return data type
void set_is_weighted(bool is_weighted)
std::size_t args_type() const
bool node_is_fixed
whether the node is replaceable. Weights are still optimized.
void set_prob_change(float w)
bool start_from_decision_trees
Holds a search space, consisting of operations and terminals and functions, and methods to sample tha...
Node get(NodeType type, DataType R, S sig) const
get a typed node.
static constexpr std::optional< Node > CreateNode(const auto &unique_data_types, bool use_all, bool weighted)
Node get(NodeType type, DataType R, size_t sig_hash) const
get a typed node
unordered_map< DataType, unordered_map< ArgsHash, unordered_map< NodeType, T > > > Map
constexpr void AddNode(const unordered_map< string, float > &user_ops, const vector< DataType > &unique_data_types)
Map< Node > node_map
Maps return types to argument types to node types.
unordered_map< DataType, vector< Node > > terminal_map
Maps return types to terminals.
constexpr void AddNodes(const unordered_map< string, float > &user_ops, const vector< DataType > &unique_data_types, std::index_sequence< Is... >)
std::optional< Node > sample_terminal(DataType R, bool force_return=false) const
Get a random terminal with return type R.
void init(const Dataset &d, const unordered_map< string, float > &user_ops={}, bool weights_init=true)
Called by the constructor to initialize the search space.
RegressorProgram make_regressor(int max_d=0, int max_size=0, const Parameters ¶ms=Parameters())
Makes a random regressor program. Convenience wrapper for make_program.
bool check(DataType R, size_t sig_hash, NodeType type) const
check if a typed Node is in the search space
bool check(DataType R) const
check if a return type is in the node map
std::optional< Node > sample_op(NodeType type, DataType R, size_t arg_count, bool force_return=false) const
Get a specific operator with an exact number of arguments.
std::optional< Node > sample_op(NodeType type, DataType R, bool force_return=false) const
Get a specific node type that matches a return value.
unordered_map< DataType, vector< float > > terminal_weights
A map of weights corresponding to elements in terminal_map, used to weight probabilities of each term...
vector< float > get_weights() const
get weights of the return types
vector< string > op_names
A vector storing the available operator names (used by bandits).
vector< float > get_weights(DataType ret) const
get weights of the argument types matching return type ret.
bool check(DataType R, size_t sig_hash) const
check if a function signature is in the search space
tree< Node > & PTC2(tree< Node > &Tree, tree< Node >::iterator root, int max_d, int max_size, bool start_from_decision_trees) const
void GenerateNodeMap(const unordered_map< string, float > &user_ops, const vector< DataType > &unique_data_types, std::index_sequence< Is... >)
std::optional< Node > sample_op(DataType ret) const
get an operator matching return type ret.
SearchSpace(const Dataset &d, const unordered_map< string, float > &user_ops={}, bool weights_init=true)
Construct a search space.
std::string repr() const
returns a string with a json representation of the search space map
std::optional< Node > get_node_like(Node node) const
get a node with a signature matching node
vector< float > get_weights(DataType ret, ArgsHash sig_hash) const
get the weights of nodes matching a signature.
RepresenterProgram make_representer(int max_d=0, int max_size=0, const Parameters ¶ms=Parameters())
Makes a random representer program. Convenience wrapper for make_program.
std::optional< Node > sample_op_with_arg(DataType ret, DataType arg, bool terminal_compatible=true, int max_args=0) const
get operator with at least one argument matching arg
Map< float > node_map_weights
A map of weights corresponding to elements in node_map, used to weight probabilities of each node bei...
MulticlassClassifierProgram make_multiclass_classifier(int max_d=0, int max_size=0, const Parameters ¶ms=Parameters())
Makes a random multiclass classifier program. Convenience wrapper for make_program.
std::optional< tree< Node > > sample_subtree(Node root, int max_d, int max_size) const
create a subtree with maximum size and depth restrictions and root of type root_type
PT make_program(const Parameters ¶ms, int max_d=0, int max_size=0)
Makes a random program.
vector< DataType > terminal_types
A vector storing the available return types of terminals.
bool has_solution_space(Iter start, Iter end) const
Takes iterators to weight vectors and checks if they have a non-empty solution space....
void MakeNodes(const unordered_map< string, float > &user_ops, const vector< DataType > &unique_data_types)
ClassifierProgram make_classifier(int max_d=0, int max_size=0, const Parameters ¶ms=Parameters())
Makes a random classifier program. Convenience wrapper for make_program.
std::optional< Node > sample_terminal(bool force_return=false) const
Get a random terminal.