Commit 1c409541 authored by Thomas Purcell's avatar Thomas Purcell
Browse files

Merge branch 'master' of gitlab.mpcdf.mpg.de:tpurcell/cpp_sisso into joss

parents 3f4a6356 2834505a
......@@ -41,6 +41,11 @@ SISSOSolver::SISSOSolver(
_n_models_store(inputs.n_models_store()),
_fix_intercept(inputs.fix_intercept())
{
if(node_value_arrs::TASK_SZ_TEST.size() == 0)
{
node_value_arrs::set_task_sz_test(_task_sizes_test);
}
_loss = loss_function_util::get_loss_function(
inputs.calc_type(),
inputs.prop_train(),
......
......@@ -83,6 +83,22 @@ FeatureSpace::FeatureSpace(InputParser inputs):
_n_samp_train(inputs.n_samp_train()),
_n_rung_generate(inputs.n_rung_generate())
{
if(node_value_arrs::N_PRIMARY_FEATURES == 0)
{
node_value_arrs::initialize_values_arr(_phi_0.back()->n_samp(), _phi_0.back()->n_samp_test(), _phi_0.size());
node_value_arrs::set_task_sz_train(_task_sizes_train);
#ifdef PARAMETERIZE
node_value_arrs::set_max_rung(_max_rung, inputs.allowed_param_ops().size() > 0);
#else
node_value_arrs::set_max_rung(_max_rung);
#endif
for(auto& feat: _phi_0)
{
feat->set_value();
feat->set_test_value();
}
}
#ifdef PARAMETERIZE
_end_no_params.resize(1, inputs.phi_0().size());
_start_rung_reparam.resize(1, 0);
......@@ -174,6 +190,206 @@ FeatureSpace::FeatureSpace(InputParser inputs):
_scores.resize(_phi.size());
}
FeatureSpace::FeatureSpace(
std::string feature_file,
std::vector<node_ptr> phi_0,
std::vector<double> prop,
std::vector<int> task_sizes,
std::string project_type,
int n_sis_select,
double cross_corr_max,
std::vector<int> excluded_inds
):
_phi_0(phi_0),
_prop_train(prop),
_scores(phi_0.size(), 0.0),
_start_rung(1, 0),
_task_sizes_train(task_sizes),
_feature_space_file("feature_space/selected_features.txt"),
_feature_space_summary_file("feature_space/SIS_summary.txt"),
_project_type(project_type),
_mpi_comm(mpi_setup::comm),
_cross_cor_max(cross_corr_max),
_l_bound(1e-50),
_u_bound(1e50),
_n_sis_select(n_sis_select),
_n_feat(phi_0.size()),
_n_rung_store(0),
_n_rung_generate(0),
_n_samp_train(_phi_0[0]->n_samp())
{
assert(_n_samp_train == std::accumulate(_task_sizes_train.begin(), _task_sizes_train.end(), 0));
if(node_value_arrs::N_PRIMARY_FEATURES == 0)
{
node_value_arrs::initialize_values_arr(_phi_0.back()->n_samp(), _phi_0.back()->n_samp_test(), _phi_0.size());
node_value_arrs::set_task_sz_train(_task_sizes_train);
for(auto& feat: _phi_0)
{
feat->set_value();
feat->set_test_value();
}
}
#ifdef PARAMETERIZE
_max_param_depth = -1;
_reparam_residual = false;
#endif
comp_feats::set_is_valid_fxn(project_type, _cross_cor_max, _n_samp_train, _is_valid, _is_valid_feat_list);
mpi_reduce_op::set_op(_project_type, _cross_cor_max, _n_sis_select);
std::vector<node_ptr> phi_temp = str2node::phi_from_file(feature_file, _phi_0, excluded_inds);
phi_temp.insert(phi_temp.begin(), _phi_0.begin(), _phi_0.end());
_n_feat = phi_temp.size();
_phi.resize(_n_feat);
std::vector<int> rungs(_n_feat, 0);
for(int ff = 0; ff < _n_feat; ++ff)
{
rungs[ff] = phi_temp[ff]->rung();
if(phi_temp[ff]->type() == NODE_TYPE::FEAT)
{
continue;
}
std::string nt = node_identifier::feature_type_to_string(phi_temp[ff]->type());
if(nt.substr(0, 2) == "p:")
{
#ifdef PARAMETERIZE
if(std::find(_allowed_param_ops.begin(), _allowed_param_ops.end(), nt) == _allowed_param_ops.end())
{
_allowed_param_ops.push_back(nt.substr(2, nt.size() - 2));
}
#else
throw std::logic_error("Parameterized features are not currently built, recompile with BUILD_PARAMS=ON.");
#endif
}
else
{
if(std::find(_allowed_ops.begin(), _allowed_ops.end(), nt) == _allowed_ops.end())
{
_allowed_ops.push_back(nt);
}
}
}
for(auto & op : _allowed_ops)
{
if((op.compare("add") == 0) || (op.compare("sub") == 0) || (op.compare("mult") == 0) || (op.compare("abs_diff") == 0))
{
_com_bin_operators.push_back(allowed_op_maps::binary_operator_map[op]);
}
else if((op.compare("div") == 0))
{
_bin_operators.push_back(allowed_op_maps::binary_operator_map[op]);
}
else
{
_un_operators.push_back(allowed_op_maps::unary_operator_map[op]);
}
}
std::vector<int> rung_inds = util_funcs::argsort<int>(rungs);
_max_rung = *std::max_element(rungs.begin(), rungs.end());
#ifdef PARAMETERIZE
node_value_arrs::set_max_rung(_max_rung, _allowed_param_ops.size() > 0);
#else
node_value_arrs::set_max_rung(_max_rung);
#endif
_phi[0] = phi_temp[rung_inds[0]];
for(int ff = 1; ff < _n_feat; ++ff)
{
_phi[ff] = phi_temp[rung_inds[ff]];
if(_phi[ff]->rung() != _phi[ff - 1]->rung())
{
_start_rung.push_back(ff);
}
}
#ifdef PARAMETERIZE
for(auto & op : _allowed_param_ops)
{
if((op.compare("add") == 0) || (op.compare("sub") == 0) || (op.compare("abs_diff") == 0))
{
_com_bin_param_operators.push_back(allowed_op_maps::binary_param_operator_map[op]);
}
else if((op.compare("div") == 0) || (op.compare("mult") == 0))
{
_bin_param_operators.push_back(allowed_op_maps::binary_param_operator_map[op]);
}
else
{
_un_param_operators.push_back(allowed_op_maps::unary_param_operator_map[op]);
}
}
_start_rung_reparam = {0};
_end_no_params = {0};
for(int rr = 1; rr < _max_rung; ++rr)
{
nlopt_wrapper::MAX_PARAM_DEPTH = rr;
bool is_correct = true;
for(auto& feat : _phi)
{
int param_size = feat->parameters().size();
if((param_size > 0) && (param_size != feat->n_params_possible()))
{
is_correct = false;
break;
}
}
if(is_correct)
{
_max_param_depth = rr;
break;
}
}
if(_max_param_depth == -1)
{
throw std::logic_error("The maximum parameter depth could not be determined from the file.");
}
node_value_arrs::initialize_param_storage();
for(int rr = 1; rr <= _max_rung; ++rr)
{
int n_feat_in_rung = (rr < _max_rung ?_start_rung[rr + 1] : _phi.size()) - _start_rung[rr];
// Reorder features based on the number of parameters they have (none goes first)
std::vector<int> feat_n_params(n_feat_in_rung);
std::transform(
_phi.begin() + _start_rung[rr],
_phi.begin() + _start_rung[rr] + n_feat_in_rung,
feat_n_params.begin(),
[](node_ptr feat){return feat->n_params();}
);
std::vector<int> inds = util_funcs::argsort<int>(feat_n_params);
std::vector<node_ptr>phi_copy(n_feat_in_rung);
std::copy_n(_phi.begin() + _start_rung[rr], n_feat_in_rung, phi_copy.begin());
std::transform(
inds.begin(),
inds.end(),
_phi.begin() + _start_rung[rr],
[&phi_copy](int ind){return phi_copy[ind];}
);
// Set how many features have no parameters
_end_no_params.push_back(
std::count_if(feat_n_params.begin(), feat_n_params.end(), [](int n_param){return n_param == 0;})
);
}
#endif
for(int ff = 0; ff < _phi.size(); ++ff)
{
_phi[ff]->reindex(ff, ff);
}
_scores.resize(_n_feat);
initialize_fs_output_files();
}
FeatureSpace::~FeatureSpace()
{}
void FeatureSpace::set_op_lists()
{
for(auto & op : _allowed_ops)
......
......@@ -109,6 +109,33 @@ public:
*/
FeatureSpace(InputParser inputs);
/**
* @brief FeatureSpace constructor that uses a file containing postfix feature expressions to describe all features in Phi, and a primary feature setn <python/feature_creation/FeatureSpace.cpp>)
*
* @param feature_file The file containing the postfix expressions of all features in the FeatureSpace
* @param phi_0 The set of primary features
* @param prop List containing the property vector (training data only)
* @param task_sizes_train The number of samples in the training data per task
* @param project_type The type of loss function/projection operator to use
* @param n_sis_select The number of features to select during each SIS step
* @param cross_corr_max The maximum allowed cross-correlation value between selected features
*/
FeatureSpace(
std::string feature_file,
std::vector<node_ptr> phi_0,
std::vector<double> prop,
std::vector<int> task_sizes_train,
std::string project_type="regression",
int n_sis_select=1,
double cross_corr_max=1.0,
std::vector<int> excluded_inds = std::vector<int>()
);
/**
* @brief Destructor
*/
~FeatureSpace();
/**
* @brief Populate the operator lists using _allowed_ops and _allowed_param_ops
*/
......
......@@ -53,9 +53,9 @@ FeatureNode::FeatureNode(const unsigned long int feat_ind, const std::string exp
")"
);
}
else if(feat_ind >= node_value_arrs::N_STORE_FEATURES)
else if(feat_ind >= node_value_arrs::N_PRIMARY_FEATURES)
{
node_value_arrs::resize_values_arr(0, node_value_arrs::N_STORE_FEATURES + 1);
node_value_arrs::resize_values_arr(0, node_value_arrs::N_PRIMARY_FEATURES + 1);
}
set_value();
set_test_value();
......
......@@ -32,7 +32,8 @@ void generateAddNode(std::vector<node_ptr>& feat_list, const node_ptr feat_1, co
(feat_1->type() == NODE_TYPE::PARAM_ADD) ||
(feat_1->type() == NODE_TYPE::PARAM_SUB) ||
(feat_2->type() == NODE_TYPE::PARAM_ADD) ||
(feat_2->type() == NODE_TYPE::PARAM_SUB)
(feat_2->type() == NODE_TYPE::PARAM_SUB) ||
((feat_1->type() == NODE_TYPE::LOG) && (feat_2->type() == NODE_TYPE::LOG))
)
{
return;
......@@ -94,7 +95,8 @@ AddNode::AddNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned lo
(feat_1->type() == NODE_TYPE::PARAM_ADD) ||
(feat_1->type() == NODE_TYPE::PARAM_SUB) ||
(feat_2->type() == NODE_TYPE::PARAM_ADD) ||
(feat_2->type() == NODE_TYPE::PARAM_SUB)
(feat_2->type() == NODE_TYPE::PARAM_SUB) ||
((feat_1->type() == NODE_TYPE::LOG) && (feat_2->type() == NODE_TYPE::LOG))
)
{
throw InvalidFeatureException();
......
......@@ -37,9 +37,7 @@ void generateLogNode(
(feat->unit() != Unit()) ||
(feat->type() == NODE_TYPE::NEG_EXP) ||
(feat->type() == NODE_TYPE::EXP) ||
(feat->type() == NODE_TYPE::DIV) ||
(feat->type() == NODE_TYPE::INV) ||
(feat->type() == NODE_TYPE::MULT) ||
(feat->type() == NODE_TYPE::LOG) ||
(feat->type() == NODE_TYPE::SIX_POW) ||
(feat->type() == NODE_TYPE::CB) ||
......@@ -92,9 +90,7 @@ LogNode::LogNode(const node_ptr feat, const unsigned long int feat_ind, const do
(feat->unit() != Unit()) ||
(feat->type() == NODE_TYPE::NEG_EXP) ||
(feat->type() == NODE_TYPE::EXP) ||
(feat->type() == NODE_TYPE::DIV) ||
(feat->type() == NODE_TYPE::INV) ||
(feat->type() == NODE_TYPE::MULT) ||
(feat->type() == NODE_TYPE::LOG) ||
(feat->type() == NODE_TYPE::SIX_POW) ||
(feat->type() == NODE_TYPE::CB) ||
......
......@@ -32,7 +32,8 @@ void generateSubNode(std::vector<node_ptr>& feat_list, const node_ptr feat_1, co
(feat_1->type() == NODE_TYPE::PARAM_ADD) ||
(feat_1->type() == NODE_TYPE::PARAM_SUB) ||
(feat_2->type() == NODE_TYPE::PARAM_ADD) ||
(feat_2->type() == NODE_TYPE::PARAM_SUB)
(feat_2->type() == NODE_TYPE::PARAM_SUB) ||
((feat_1->type() == NODE_TYPE::LOG) && (feat_2->type() == NODE_TYPE::LOG))
)
{
return;
......@@ -94,7 +95,8 @@ SubNode::SubNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned lo
(feat_1->type() == NODE_TYPE::PARAM_ADD) ||
(feat_1->type() == NODE_TYPE::PARAM_SUB) ||
(feat_2->type() == NODE_TYPE::PARAM_ADD) ||
(feat_2->type() == NODE_TYPE::PARAM_SUB)
(feat_2->type() == NODE_TYPE::PARAM_SUB) ||
((feat_1->type() == NODE_TYPE::LOG) && (feat_2->type() == NODE_TYPE::LOG))
)
{
throw InvalidFeatureException();
......
......@@ -74,16 +74,16 @@ node_ptr str2node::postfix2node(const std::string postfix_expr, const std::vecto
if(op_terms[0] == "add")
{
#ifndef PARAMETERIZE
stack[stack.size() - 2] = std::make_shared<AddNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<AddNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
#else
if(op_terms.size() > 1)
{
stack[stack.size() - 2] = std::make_shared<AddParamNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<AddParamNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
set_parameters(stack[stack.size() - 2], op_terms);
}
else
{
stack[stack.size() - 2] = std::make_shared<AddNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<AddNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
}
#endif
stack.pop_back();
......@@ -91,16 +91,16 @@ node_ptr str2node::postfix2node(const std::string postfix_expr, const std::vecto
else if(op_terms[0] == "sub")
{
#ifndef PARAMETERIZE
stack[stack.size() - 2] = std::make_shared<SubNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<SubNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
#else
if(op_terms.size() > 1)
{
stack[stack.size() - 2] = std::make_shared<SubParamNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<SubParamNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
set_parameters(stack[stack.size() - 2], op_terms);
}
else
{
stack[stack.size() - 2] = std::make_shared<SubNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<SubNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
}
#endif
stack.pop_back();
......@@ -108,16 +108,16 @@ node_ptr str2node::postfix2node(const std::string postfix_expr, const std::vecto
else if(op_terms[0] == "abd")
{
#ifndef PARAMETERIZE
stack[stack.size() - 2] = std::make_shared<AbsDiffNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<AbsDiffNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
#else
if(op_terms.size() > 1)
{
stack[stack.size() - 2] = std::make_shared<AbsDiffParamNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<AbsDiffParamNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
set_parameters(stack[stack.size() - 2], op_terms);
}
else
{
stack[stack.size() - 2] = std::make_shared<AbsDiffNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<AbsDiffNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
}
#endif
stack.pop_back();
......@@ -125,16 +125,16 @@ node_ptr str2node::postfix2node(const std::string postfix_expr, const std::vecto
else if(op_terms[0] == "mult")
{
#ifndef PARAMETERIZE
stack[stack.size() - 2] = std::make_shared<MultNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<MultNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
#else
if(op_terms.size() > 1)
{
stack[stack.size() - 2] = std::make_shared<MultParamNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<MultParamNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
set_parameters(stack[stack.size() - 2], op_terms);
}
else
{
stack[stack.size() - 2] = std::make_shared<MultNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<MultNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
}
#endif
stack.pop_back();
......@@ -142,16 +142,16 @@ node_ptr str2node::postfix2node(const std::string postfix_expr, const std::vecto
else if(op_terms[0] == "div")
{
#ifndef PARAMETERIZE
stack[stack.size() - 2] = std::make_shared<DivNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<DivNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
#else
if(op_terms.size() > 1)
{
stack[stack.size() - 2] = std::make_shared<DivParamNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<DivParamNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
set_parameters(stack[stack.size() - 2], op_terms);
}
else
{
stack[stack.size() - 2] = std::make_shared<DivNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 2] = std::make_shared<DivNode>(stack[stack.size() - 2], stack[stack.size() - 1], feat_ind);
}
#endif
stack.pop_back();
......@@ -159,193 +159,193 @@ node_ptr str2node::postfix2node(const std::string postfix_expr, const std::vecto
else if(op_terms[0] == "abs")
{
#ifndef PARAMETERIZE
stack[stack.size() - 1] = std::make_shared<AbsNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<AbsNode>(stack[stack.size() - 1], feat_ind);
#else
if(op_terms.size() > 1)
{
stack[stack.size() - 1] = std::make_shared<AbsParamNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<AbsParamNode>(stack[stack.size() - 1], feat_ind);
set_parameters(stack[stack.size() - 1], op_terms);
set_parameters(stack[stack.size() - 1], op_terms);
}
else
{
stack[stack.size() - 1] = std::make_shared<AbsNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<AbsNode>(stack[stack.size() - 1], feat_ind);
}
#endif
}
else if(op_terms[0] == "inv")
{
#ifndef PARAMETERIZE
stack[stack.size() - 1] = std::make_shared<InvNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<InvNode>(stack[stack.size() - 1], feat_ind);
#else
if(op_terms.size() > 1)
{
stack[stack.size() - 1] = std::make_shared<InvParamNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<InvParamNode>(stack[stack.size() - 1], feat_ind);
set_parameters(stack[stack.size() - 1], op_terms);
}
else
{
stack[stack.size() - 1] = std::make_shared<InvNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<InvNode>(stack[stack.size() - 1], feat_ind);
}
#endif
}
else if(op_terms[0] == "exp")
{
#ifndef PARAMETERIZE
stack[stack.size() - 1] = std::make_shared<ExpNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<ExpNode>(stack[stack.size() - 1], feat_ind);
#else
if(op_terms.size() > 1)
{
stack[stack.size() - 1] = std::make_shared<ExpParamNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<ExpParamNode>(stack[stack.size() - 1], feat_ind);
set_parameters(stack[stack.size() - 1], op_terms);
}
else
{
stack[stack.size() - 1] = std::make_shared<ExpNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<ExpNode>(stack[stack.size() - 1], feat_ind);
}
#endif
}
else if(op_terms[0] == "nexp")
{
#ifndef PARAMETERIZE
stack[stack.size() - 1] = std::make_shared<NegExpNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<NegExpNode>(stack[stack.size() - 1], feat_ind);
#else
if(op_terms.size() > 1)
{
stack[stack.size() - 1] = std::make_shared<NegExpParamNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<NegExpParamNode>(stack[stack.size() - 1], feat_ind);
set_parameters(stack[stack.size() - 1], op_terms);
}
else
{
stack[stack.size() - 1] = std::make_shared<NegExpNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<NegExpNode>(stack[stack.size() - 1], feat_ind);
}
#endif
}
else if(op_terms[0] == "log")
{
#ifndef PARAMETERIZE
stack[stack.size() - 1] = std::make_shared<LogNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<LogNode>(stack[stack.size() - 1], feat_ind);
#else
if(op_terms.size() > 1)
{
stack[stack.size() - 1] = std::make_shared<LogParamNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<LogParamNode>(stack[stack.size() - 1], feat_ind);
set_parameters(stack[stack.size() - 1], op_terms);
}
else
{
stack[stack.size() - 1] = std::make_shared<LogNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<LogNode>(stack[stack.size() - 1], feat_ind);
}
#endif
}
else if(op_terms[0] == "sin")
{
#ifndef PARAMETERIZE
stack[stack.size() - 1] = std::make_shared<SinNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);
stack[stack.size() - 1] = std::make_shared<SinNode>(stack[stack.size() - 1], feat_ind);
#else
if(op_terms.size() > 1)
{
stack[stack.size() - 1] = std::make_shared<SinParamNode>(stack[stack.size() - 1], feat_ind, 1e-50, 1e50);