diff --git a/src/feature_creation/feature_space/FeatureSpace.cpp b/src/feature_creation/feature_space/FeatureSpace.cpp
index 6e185735d4c930348bdb0470477388629a6f4c1a..4cee1bf875c69904308feffa101adb3ca12673f5 100644
--- a/src/feature_creation/feature_space/FeatureSpace.cpp
+++ b/src/feature_creation/feature_space/FeatureSpace.cpp
@@ -38,6 +38,24 @@ BOOST_CLASS_EXPORT_GUID(InvParamNode, "InvParamNode")
 BOOST_CLASS_EXPORT_GUID(SinParamNode, "SinParamNode")
 BOOST_CLASS_EXPORT_GUID(CosParamNode, "CosParamNode")
 
+BOOST_CLASS_EXPORT_GUID(AddParamTopLevNode, "AddParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(SubParamTopLevNode, "SubParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(AbsDiffParamTopLevNode, "AbsDiffParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(MultParamTopLevNode, "MultParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(DivParamTopLevNode, "DivParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(SqParamTopLevNode, "SqParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(SqrtParamTopLevNode, "SqrtParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(CbParamTopLevNode, "CbParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(CbrtParamTopLevNode, "CbrtParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(SixPowParamTopLevNode, "SixPowParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(ExpParamTopLevNode, "ExpParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(NegExpParamTopLevNode, "NegExpParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(LogParamTopLevNode, "LogParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(AbsParamTopLevNode, "AbsParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(InvParamTopLevNode, "InvParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(SinParamTopLevNode, "SinParamTopLevNode")
+BOOST_CLASS_EXPORT_GUID(CosParamTopLevNode, "CosParamTopLevNode")
+
 FeatureSpace::FeatureSpace(
     std::shared_ptr<MPI_Interface> mpi_comm,
     std::vector<node_ptr> phi_0,
@@ -52,7 +70,8 @@ FeatureSpace::FeatureSpace(
     int n_rung_generate,
     double cross_corr_max,
     double min_abs_feat_val,
-    double max_abs_feat_val
+    double max_abs_feat_val,
+    bool param_internal
 ):
     _phi(phi_0),
     _phi_0(phi_0),
@@ -73,7 +92,8 @@ FeatureSpace::FeatureSpace(
     _n_samp(phi_0[0]->n_samp()),
     _n_feat(phi_0.size()),
     _n_rung_store(max_store_rung),
-    _n_rung_generate(n_rung_generate)
+    _n_rung_generate(n_rung_generate),
+    _param_internal(param_internal)
 {
     initialize_fs(project_type);
 }
@@ -84,7 +104,7 @@ void FeatureSpace::initialize_fs(std::string project_type)
         if(_allowed_param_ops.size() != 0)
             throw std::logic_error("Parameterization is not possible recompile with -DPARAMETERIZE");
     #else
-        nlopt_wrapper::set_objective(project_type, _prop.data(), _task_sizes, _max_phi);
+        nlopt_wrapper::set_objective(project_type, _prop.data(), _task_sizes, _max_phi, _param_internal);
     #endif
 
     if(_n_rung_store == -1)
diff --git a/src/feature_creation/feature_space/FeatureSpace.hpp b/src/feature_creation/feature_space/FeatureSpace.hpp
index 1f4beba1784cd6d6f7f89f09b1c1cb9e0c4bb070..c828581a9037843cc7626afd0a5ce31fc8f83293 100644
--- a/src/feature_creation/feature_space/FeatureSpace.hpp
+++ b/src/feature_creation/feature_space/FeatureSpace.hpp
@@ -82,6 +82,8 @@ class FeatureSpace
     const int _n_sis_select; //!< Number of features to select for each dimensions
     const int _n_samp; //!< Number of samples (training data)
     const int _n_rung_generate; //!< Total number of rungs to generate on the fly
+
+    bool _param_internal; //!< True if parameterize all scale and shift parameters in a feature
 public:
 
     /**
@@ -117,7 +119,8 @@ public:
         int n_rung_generate=0,
         double cross_corr_max=1.0,
         double min_abs_feat_val=1e-50,
-        double max_abs_feat_val=1e50
+        double max_abs_feat_val=1e50,
+        bool param_internal=true
     );
 
     /**
@@ -299,7 +302,8 @@ public:
             int n_rung_generate=0,
             double cross_corr_max=1.0,
             double min_abs_feat_val=1e-50,
-            double max_abs_feat_val=1e50
+            double max_abs_feat_val=1e50,
+            bool param_internal=true
         );
 
         /**
@@ -333,7 +337,8 @@ public:
             int n_rung_generate=0,
             double cross_corr_max=1.0,
             double min_abs_feat_val=1e-50,
-            double max_abs_feat_val=1e50
+            double max_abs_feat_val=1e50,
+            bool param_internal=true
         );
 
         /**
diff --git a/src/feature_creation/node/operator_nodes/OperatorNode.hpp b/src/feature_creation/node/operator_nodes/OperatorNode.hpp
index 72203f05431443cf8d03233d51ef272713d87aaa..6faee746389e52c4ae36119ba3a9c605d7d19a1c 100644
--- a/src/feature_creation/node/operator_nodes/OperatorNode.hpp
+++ b/src/feature_creation/node/operator_nodes/OperatorNode.hpp
@@ -346,7 +346,7 @@ public:
          * @brief returns the number of theoretical parameters for this feature
          * @return the number of theoretical parameters
          */
-        inline int n_params(int n_cur = 0){return std::accumulate(_feats.begin(), _feats.end(), 2, [](double tot, node_ptr feat){return tot + feat->n_params();});}
+        virtual inline int n_params(int n_cur = 0){return std::accumulate(_feats.begin(), _feats.end(), 2, [](double tot, node_ptr feat){return tot + feat->n_params();});}
 
         /**
          * @brief Set the values of the training data for the feature inside of the value storage arrays
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterize_top_lev_absolute_value.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterize_top_lev_absolute_value.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..252cf5a21d7f012f7c3cff03cdd2c5310260daff
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterize_top_lev_absolute_value.cpp
@@ -0,0 +1,59 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterize_top_lev_absolute_value.hpp>
+
+void generateAbsParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+    node_ptr new_feat = std::make_shared<AbsParamTopLevNode>(feat, feat_ind, prop);
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+AbsParamTopLevNode::AbsParamTopLevNode()
+{}
+
+AbsParamTopLevNode::AbsParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    AbsParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+AbsParamTopLevNode::AbsParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    AbsParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+AbsParamTopLevNode::AbsParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    AbsParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void AbsParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::abs(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::abs(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+void AbsParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::abs(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void AbsParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[0] = _sign_alpha;
+    ub[0] = _sign_alpha;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterize_top_lev_absolute_value.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterize_top_lev_absolute_value.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..19fb2e0140da1debc256f4ef527d597d5cc4a53a
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterize_top_lev_absolute_value.hpp
@@ -0,0 +1,131 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterize_top_levabsolute_value.hpp
+ *  @brief Class describing the parameterized absolute value operator
+ *
+ *  This class represents the parameterized unary operator -> |alpha * A + a|
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_ABS_VAL_NODE
+#define PARAM_TOP_LEV_ABS_VAL_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterized_absolute_value.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief Node for the absolute value operator
+ *
+ */
+class AbsParamTopLevNode: public AbsParamNode
+{
+    using AbsParamNode::set_value;
+    using AbsParamNode::set_test_value;
+    using AbsParamNode::value_ptr;
+    using AbsParamNode::test_value_ptr;
+    using AbsParamNode::domain;
+    using AbsParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<AbsParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    AbsParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the Node from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     * @param prop The property to fit to
+     */
+    AbsParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the Node from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    AbsParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the Node from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    AbsParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: abs_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: abs_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: abs_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: abs_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "|" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + "|";}
+
+    // DocString: abs_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().abs(_params[0], _params[1]);}
+
+    // DocString: abs_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateAbsParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterized_absolute_value.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterized_absolute_value.cpp
index d5d66e3297f8067fbf4d09c1f8cef133d5eaca6a..08df4ae9c4a7dbbe999357f688b7fdde6f97c8a6 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterized_absolute_value.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterized_absolute_value.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterized_absolute_value.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(AbsParamNode)
+
 void generateAbsParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterized_absolute_value.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterized_absolute_value.hpp
index 8d6bc6a950795e9c65275f1399abbfb8aef75576..6f7674ae23598fa05208fabd570144b26e197bc3 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterized_absolute_value.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterized_absolute_value.hpp
@@ -19,13 +19,6 @@
  */
 class AbsParamNode: public AbsNode
 {
-    using AbsNode::set_value;
-    using AbsNode::set_test_value;
-    using AbsNode::value_ptr;
-    using AbsNode::test_value_ptr;
-    using AbsNode::domain;
-    using AbsNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -42,6 +35,12 @@ class AbsParamNode: public AbsNode
     }
 
 protected:
+    using AbsNode::set_value;
+    using AbsNode::set_test_value;
+    using AbsNode::value_ptr;
+    using AbsNode::test_value_ptr;
+    using AbsNode::domain;
+    using AbsNode::expr;
     std::vector<double> _params; //!< The parameters vector
     double _sign_alpha; //!< 1 if alpha is positive, -1 if alpha is negative
 
@@ -85,7 +84,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    AbsParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    AbsParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: abs_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterize_top_lev_absolute_difference.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterize_top_lev_absolute_difference.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9b76933d0f5157fc1732f012e349fa603457eb2f
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterize_top_lev_absolute_difference.cpp
@@ -0,0 +1,88 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterize_top_lev_absolute_difference.hpp>
+
+void generateAbsDiffParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+    node_ptr new_feat = std::make_shared<AbsDiffParamTopLevNode>(feat_1, feat_2, feat_ind, prop);
+
+    std::map<std::string, int> add_sub_leaves;
+    int expected_abs_tot = 0;
+    feat_1->update_add_sub_leaves(add_sub_leaves, 1, expected_abs_tot);
+    feat_2->update_add_sub_leaves(add_sub_leaves,-1, expected_abs_tot);
+
+    if((add_sub_leaves.size() < 2))
+        return;
+
+    double* params = new_feat->parameters().data();
+    double* val_ptr = new_feat->value_ptr();
+    const int offset = new_feat->rung();
+    allowed_op_funcs::sub(feat_1->n_samp(), feat_1->value_ptr(offset + 2), feat_2->value_ptr(offset + 1), params[0], params[1], val_ptr);
+    if(*std::min_element(val_ptr, val_ptr + new_feat->n_samp()) > l_bound)
+        return;
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound) || (util_funcs::max_abs_val<double>(val_ptr, feat_1->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+AbsDiffParamTopLevNode::AbsDiffParamTopLevNode()
+{}
+
+AbsDiffParamTopLevNode::AbsDiffParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop):
+    AbsDiffParamNode(feat_1, feat_2, feat_ind, l_bound, u_bound)
+{
+    std::map<std::string, int> add_sub_leaves;
+    int expected_abs_tot = 0;
+    feat_1->update_add_sub_leaves(add_sub_leaves, 1, expected_abs_tot);
+    feat_2->update_add_sub_leaves(add_sub_leaves,-1, expected_abs_tot);
+
+    if((add_sub_leaves.size() < 2))
+        throw InvalidFeatureException();
+
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    double* params = _params.data();
+    double* val_ptr = value_ptr();
+    const int offset = rung();
+
+    allowed_op_funcs::sub(feat_1->n_samp(), feat_1->value_ptr(offset + 2), feat_2->value_ptr(offset + 1), params[0], params[1], val_ptr);
+    if(*std::min_element(val_ptr, val_ptr + _n_samp) > l_bound)
+        throw InvalidFeatureException();
+
+    if(is_nan() || is_const()|| (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+AbsDiffParamTopLevNode::AbsDiffParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, std::vector<double>& prop):
+    AbsDiffParamNode(feat_1, feat_2, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+AbsDiffParamTopLevNode::AbsDiffParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound):
+    AbsDiffParamNode(feat_1, feat_2, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void AbsDiffParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+
+    if(_selected)
+        allowed_op_funcs::abs_diff(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+    allowed_op_funcs::abs_diff(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void AbsDiffParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::abs_diff(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _feats[1]->test_value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void AbsDiffParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterize_top_lev_absolute_difference.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterize_top_lev_absolute_difference.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6f4a1d11c3dc32deb7ab8b1bb4da60413683d8ce
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterize_top_lev_absolute_difference.hpp
@@ -0,0 +1,133 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterize_top_levabsolute_difference.hpp
+ *  @brief Class describing the parameterized absolute difference operator
+ *
+ *  This class represents the parameterized unary operator -> |A - alpha * B + a|
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_ABS_DIFF_NODE
+#define PARAM_TOP_LEV_ABS_DIFF_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterized_absolute_difference.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class AbsDiffParamTopLevNode: public AbsDiffParamNode
+{
+    using AbsDiffParamNode::set_value;
+    using AbsDiffParamNode::set_test_value;
+    using AbsDiffParamNode::value_ptr;
+    using AbsDiffParamNode::test_value_ptr;
+    using AbsDiffParamNode::domain;
+    using AbsDiffParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<AbsDiffParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    AbsDiffParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_2 shared_ptr of the feature to operate on (B)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    AbsDiffParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_2 shared_ptr of the feature to operate on (B)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    AbsDiffParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     * @param prop The property to fit to
+     */
+    AbsDiffParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: abs_diff_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: abs_diff_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: abs_diff_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: abs_diff_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "|(" + _feats[0]->expr() + ") - (" + std::to_string(_params[0]) + "*" + _feats[1]->expr() + " + " + std::to_string(_params[1]) + ")|";}
+
+    // DocString: abs_diff_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().sub(_feats[1]->domain(), _params[0], _params[1]).abs();}
+
+    // DocString: abs_diff_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateAbsDiffParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterized_absolute_difference.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterized_absolute_difference.cpp
index 025dc164c2285af06534babe878046b990d0c4f2..eab182e7f4329e3e359cf369aa9b9fa2a13ae644 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterized_absolute_difference.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterized_absolute_difference.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterized_absolute_difference.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(AbsDiffParamNode)
+
 void generateAbsDiffParamNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterized_absolute_difference.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterized_absolute_difference.hpp
index c7d27aad8a05eb0474a0e84c1d4f94831df479fb..059ca89a67ba8d8532dfabe00f4dba1fb226a4e1 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterized_absolute_difference.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterized_absolute_difference.hpp
@@ -19,13 +19,6 @@
  */
 class AbsDiffParamNode: public AbsDiffNode
 {
-    using AbsDiffNode::set_value;
-    using AbsDiffNode::set_test_value;
-    using AbsDiffNode::value_ptr;
-    using AbsDiffNode::test_value_ptr;
-    using AbsDiffNode::domain;
-    using AbsDiffNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -40,6 +33,13 @@ class AbsDiffParamNode: public AbsDiffNode
         ar & _params;
     }
 protected:
+    using AbsDiffNode::set_value;
+    using AbsDiffNode::set_test_value;
+    using AbsDiffNode::value_ptr;
+    using AbsDiffNode::test_value_ptr;
+    using AbsDiffNode::domain;
+    using AbsDiffNode::expr;
+
     std::vector<double> _params;
 public:
     /**
@@ -83,7 +83,7 @@ public:
      * @param param_list The list of parameters to optimize using non-linear least squares
      * @param prop The property to fit to
      */
-    AbsDiffParamNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound);
+    AbsDiffParamNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: abs_diff_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterize_top_lev_add.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterize_top_lev_add.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..42c5e98302d5de30784a8ab5b774acb11e046e70
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterize_top_lev_add.cpp
@@ -0,0 +1,62 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterize_top_lev_add.hpp>
+
+void generateAddParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+    node_ptr new_feat = std::make_shared<AddParamTopLevNode>(feat_1, feat_2, feat_ind, prop);
+
+    new_feat->set_value();
+
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+AddParamTopLevNode::AddParamTopLevNode()
+{}
+
+AddParamTopLevNode::AddParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    AddParamNode(feat_1, feat_2, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+AddParamTopLevNode::AddParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, std::vector<double>& prop) :
+    AddParamNode(feat_1, feat_2, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+AddParamTopLevNode::AddParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound) :
+    AddParamNode(feat_1, feat_2, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void AddParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+
+    if(_selected)
+        allowed_op_funcs::add(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::add(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void AddParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::add(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _feats[1]->test_value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void AddParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[1] = 0.0;
+    ub[1] = 0.0;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterize_top_lev_add.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterize_top_lev_add.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..2516ba165e5996a8f3e68ed051625d5b308e24db
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterize_top_lev_add.hpp
@@ -0,0 +1,131 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterize_top_levadd.hpp
+ *  @brief Class describing the parameterized addition operator
+ *
+ *  This class represents the parameterized unary operator -> A + alpha * B + a
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_ADD_NODE
+#define PARAM_TOP_LEV_ADD_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterized_add.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_param_add_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class AddParamTopLevNode: public AddParamNode
+{
+    using AddParamNode::set_value;
+    using AddParamNode::set_test_value;
+    using AddParamNode::value_ptr;
+    using AddParamNode::test_value_ptr;
+    using AddParamNode::domain;
+    using AddParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<AddParamNode>(*this);
+    }
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    AddParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_2 shared_ptr of the feature to operate on (B)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    AddParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_2 shared_ptr of the feature to operate on (B)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    AddParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    AddParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: add_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: add_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: add_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: add_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "[" + _feats[0]->expr() + " + (" + std::to_string(_params[0]) + "*" + _feats[1]->expr() + " + " + std::to_string(_params[1]) + ")]";}
+
+    // DocString: add_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().add(_feats[1]->domain(), _params[0], _params[1]);}
+
+    // DocString: add_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateAddParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterized_add.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterized_add.cpp
index 9f79102625199f0aaa83e96c1d3e7e6913f4ae77..a7161dbf58cd12f900a1eb976fb2aa7be1d0360e 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterized_add.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterized_add.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterized_add.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(AddParamNode)
+
 void generateAddParamNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterized_add.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterized_add.hpp
index 4cf303b7c031ec19f604013f864cc3e7b4b26ead..f5b0d7b133a2d3e2d86bbbc76e4efd81c8dfc876 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterized_add.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterized_add.hpp
@@ -19,13 +19,6 @@
  */
 class AddParamNode: public AddNode
 {
-    using AddNode::set_value;
-    using AddNode::set_test_value;
-    using AddNode::value_ptr;
-    using AddNode::test_value_ptr;
-    using AddNode::domain;
-    using AddNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -39,8 +32,17 @@ class AddParamNode: public AddNode
         ar & boost::serialization::base_object<AddNode>(*this);
         ar & _params;
     }
+
 protected:
+    using AddNode::set_value;
+    using AddNode::set_test_value;
+    using AddNode::value_ptr;
+    using AddNode::test_value_ptr;
+    using AddNode::domain;
+    using AddNode::expr;
+
     std::vector<double> _params;
+
 public:
     /**
      * @brief Base Constructor
@@ -82,7 +84,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    AddParamNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound);
+    AddParamNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: add_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterize_top_lev_cube.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterize_top_lev_cube.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..95f865b81815d969c9f72cc0e202d540d7d81d6e
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterize_top_lev_cube.cpp
@@ -0,0 +1,63 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterize_top_lev_cube.hpp>
+
+void generateCbParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+    node_ptr new_feat = std::make_shared<CbParamTopLevNode>(feat, feat_ind, prop);
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+CbParamTopLevNode::CbParamTopLevNode()
+{}
+
+CbParamTopLevNode::CbParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    CbParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+
+    get_parameters(prop);
+    set_value();
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+CbParamTopLevNode::CbParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    CbParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+
+    get_parameters(prop);
+    set_value();
+}
+
+CbParamTopLevNode::CbParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    CbParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void CbParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::cb(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::cb(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void CbParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::cb(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void CbParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[0] = 1.0;
+    ub[0] = 1.0;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterize_top_lev_cube.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterize_top_lev_cube.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..2eb13937b732ecce2e3e37a9fdb98b47f68f588f
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterize_top_lev_cube.hpp
@@ -0,0 +1,131 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterize_top_levcube.hpp
+ *  @brief Class describing the parameterized cube operator
+ *
+ *  This class represents the parameterized unary operator -> (alpha * A + a)^3
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_CUBE_NODE
+#define PARAM_TOP_LEV_CUBE_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterized_cube.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class CbParamTopLevNode: public CbParamNode
+{
+    using CbParamNode::set_value;
+    using CbParamNode::set_test_value;
+    using CbParamNode::value_ptr;
+    using CbParamNode::test_value_ptr;
+    using CbParamNode::domain;
+    using CbParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<CbParamNode>(*this);
+    }
+
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    CbParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    CbParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    CbParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    CbParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: cb_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: cb_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: cb_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: cb_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "(" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + ")^3";}
+
+    // DocString: cb_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().pow(3.0, _params[0], _params[1]);}
+
+    // DocString: cb_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateCbParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterized_cube.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterized_cube.cpp
index e1dffd6d6f1e86503c0d6a8f59bd15bbf404cde5..5eb08d7d7b205f3e4b7a700d6298a555bc845ede 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterized_cube.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterized_cube.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterized_cube.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(CbParamNode)
+
 void generateCbParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterized_cube.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterized_cube.hpp
index e133a90cad518d009f4c4d13810fca45990f01dd..8b9cec6111c36ce8eb9842407fa5c4f194ac36c7 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterized_cube.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterized_cube.hpp
@@ -19,13 +19,6 @@
  */
 class CbParamNode: public CbNode
 {
-    using CbNode::set_value;
-    using CbNode::set_test_value;
-    using CbNode::value_ptr;
-    using CbNode::test_value_ptr;
-    using CbNode::domain;
-    using CbNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -41,6 +34,13 @@ class CbParamNode: public CbNode
     }
 
 protected:
+    using CbNode::set_value;
+    using CbNode::set_test_value;
+    using CbNode::value_ptr;
+    using CbNode::test_value_ptr;
+    using CbNode::domain;
+    using CbNode::expr;
+
     std::vector<double> _params; //!< The parameters vector
 
 public:
@@ -82,7 +82,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    CbParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    CbParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: cb_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterize_top_lev_cube_root.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterize_top_lev_cube_root.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ae37c16004aa143b4370e13702c2edd4ea151f6f
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterize_top_lev_cube_root.cpp
@@ -0,0 +1,65 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterize_top_lev_cube_root.hpp>
+
+void generateCbrtParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+    node_ptr new_feat = std::make_shared<CbrtParamTopLevNode>(feat, feat_ind, prop);
+
+    if(new_feat->parameters()[0] * feat->domain() + new_feat->parameters()[1] <= 0.0)
+        return;
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+CbrtParamTopLevNode::CbrtParamTopLevNode()
+{}
+
+CbrtParamTopLevNode::CbrtParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    CbrtParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+    if((_params[0] * _feats[0]->domain() + _params[1]) <= 0.0)
+        throw InvalidFeatureException();
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+CbrtParamTopLevNode::CbrtParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    CbrtParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+CbrtParamTopLevNode::CbrtParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    CbrtParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void CbrtParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::cbrt(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::cbrt(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void CbrtParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::cbrt(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void CbrtParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[0] = _sign_alpha;
+    ub[0] = _sign_alpha;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterize_top_lev_cube_root.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterize_top_lev_cube_root.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b9e74a19e229cf5f9d8a03d75a8aa87621593ec8
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterize_top_lev_cube_root.hpp
@@ -0,0 +1,130 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterize_top_levcube_root.hpp
+ *  @brief Class describing the parameterized cube root operator
+ *
+ *  This class represents the parameterized unary operator -> cbrt(alpha * A + a)
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_CBRT_NODE
+#define PARAM_TOP_LEV_CBRT_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterized_cube_root.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class CbrtParamTopLevNode: public CbrtParamNode
+{
+    using CbrtParamNode::set_value;
+    using CbrtParamNode::set_test_value;
+    using CbrtParamNode::value_ptr;
+    using CbrtParamNode::test_value_ptr;
+    using CbrtParamNode::domain;
+    using CbrtParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<CbrtParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    CbrtParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    CbrtParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    CbrtParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    CbrtParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50d);
+
+    // DocString: cbrt_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: cbrt_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: cbrt_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: cbrt_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "cbrt(" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + ")";}
+
+    // DocString: cbrt_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().pow(1.0 / 3.0, _params[0], _params[1]);}
+
+    // DocString: cbrt_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateCbrtParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterized_cube_root.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterized_cube_root.cpp
index 4e3fc8579301c272adfd04252919973d1f85bf3d..de18674e3b7f22bf4b20831cc79343341e880d5b 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterized_cube_root.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterized_cube_root.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterized_cube_root.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(CbrtParamNode)
+
 void generateCbrtParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterized_cube_root.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterized_cube_root.hpp
index c2bf5b7432afa955921e8a2a1715d384d2e7e7d7..f185ba86e5b5c7ef19ad662d0679d1ac1a555ef3 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterized_cube_root.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterized_cube_root.hpp
@@ -19,13 +19,6 @@
  */
 class CbrtParamNode: public CbrtNode
 {
-    using CbrtNode::set_value;
-    using CbrtNode::set_test_value;
-    using CbrtNode::value_ptr;
-    using CbrtNode::test_value_ptr;
-    using CbrtNode::domain;
-    using CbrtNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -42,6 +35,13 @@ class CbrtParamNode: public CbrtNode
     }
 
 protected:
+    using CbrtNode::set_value;
+    using CbrtNode::set_test_value;
+    using CbrtNode::value_ptr;
+    using CbrtNode::test_value_ptr;
+    using CbrtNode::domain;
+    using CbrtNode::expr;
+
     std::vector<double> _params; //!< The parameters vector
     double _sign_alpha; //!< 1 if alpha is positive, -1 if alpha is negative
 public:
@@ -83,7 +83,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    CbrtParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    CbrtParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: cbrt_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/cos.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/cos.hpp
index da9bb0f1cb0621c90e8fb7655e47e4cbc6b06fe5..9a9ae1d375311b212a2b3a5497c73476f224a6c3 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/cos.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/cos.hpp
@@ -170,7 +170,7 @@ public:
          * @param params parameter values for non-linear operations
          * @return the domain
          */
-        inline Domain domain(double* params) {return Domain(-1.0, 1.0);}
+        inline Domain domain(double* params){return Domain(-1.0, 1.0);}
 
         /**
          * @brief The expression of the feature
@@ -178,7 +178,7 @@ public:
          * @param params parameter values for non-linear operations
          * @return feature expression
          */
-        inline std::string expr(double* params) {return "cos(" + std::to_string(params[0]) + "*" + _feats[0]->expr( params + 2) + " + " + std::to_string(params[1]) + ")";}
+        inline std::string expr(double* params){return "cos(" + std::to_string(params[0]) + "*" + _feats[0]->expr( params + 2) + " + " + std::to_string(params[1]) + ")";}
 
         /**
          * @brief Set the bounds for the nl parameterization
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterize_top_lev_cos.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterize_top_lev_cos.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..186e0c325ce1195d124dcbd9cfdabcdfdf763855
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterize_top_lev_cos.cpp
@@ -0,0 +1,68 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterize_top_lev_cos.hpp>
+
+void generateCosParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+
+    if((feat->type() == NODE_TYPE::SIN) || (feat->type() == NODE_TYPE::COS))
+        return;
+
+    node_ptr new_feat = std::make_shared<CosParamTopLevNode>(feat, feat_ind, prop);
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+CosParamTopLevNode::CosParamTopLevNode()
+{}
+
+CosParamTopLevNode::CosParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    CosParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    if((feat->type() == NODE_TYPE::SIN) || (feat->type() == NODE_TYPE::COS))
+        throw InvalidFeatureException();
+
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+CosParamTopLevNode::CosParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    CosParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+CosParamTopLevNode::CosParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    CosParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void CosParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::cos(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::cos(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void CosParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::cos(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+
+void CosParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[1] = -1.0 * M_PI;
+    ub[1] = M_PI;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterize_top_lev_cos.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterize_top_lev_cos.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6805c38879708acaa758253ded198dbc1e2112a3
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterize_top_lev_cos.hpp
@@ -0,0 +1,131 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterize_top_levcos.hpp
+ *  @brief Class describing the parameterized cos operator
+ *
+ *  This class represents the parameterized unary operator -> cos(alpha * A + a)
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_COS_NODE
+#define PARAM_TOP_LEV_COS_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterized_cos.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class CosParamTopLevNode: public CosParamNode
+{
+    using CosParamNode::set_value;
+    using CosParamNode::set_test_value;
+    using CosParamNode::value_ptr;
+    using CosParamNode::test_value_ptr;
+    using CosParamNode::domain;
+    using CosParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<CosParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    CosParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     * @param prop The property to fit to
+     */
+    CosParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    CosParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    CosParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: cos_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: cos_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: cos_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: cos_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "cos(" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + ")";}
+
+    // DocString: cos_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return Domain(-1.0, 1.0);}
+
+    // DocString: cos_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateCosParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterized_cos.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterized_cos.cpp
index 20127ad9a7dbfbcfdc75fb0e39c46a66a7801dcc..8d1c93f04fa8b3cc49b29fa8012e38fec834fbbb 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterized_cos.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterized_cos.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterized_cos.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(CosParamNode)
+
 void generateCosParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterized_cos.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterized_cos.hpp
index 0df8f40a497c37ca16634cb1e374687fa61a59b6..af7cf0e761410c8217aa6d2b7e8865ebca467303 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterized_cos.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterized_cos.hpp
@@ -19,13 +19,6 @@
  */
 class CosParamNode: public CosNode
 {
-    using CosNode::set_value;
-    using CosNode::set_test_value;
-    using CosNode::value_ptr;
-    using CosNode::test_value_ptr;
-    using CosNode::domain;
-    using CosNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -41,6 +34,13 @@ class CosParamNode: public CosNode
     }
 
 protected:
+    using CosNode::set_value;
+    using CosNode::set_test_value;
+    using CosNode::value_ptr;
+    using CosNode::test_value_ptr;
+    using CosNode::domain;
+    using CosNode::expr;
+
     std::vector<double> _params; //!< The parameters vector
 
 public:
@@ -83,7 +83,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    CosParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    CosParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: cos_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterize_top_lev_divide.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterize_top_lev_divide.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..673ff3b69a71be1023ac922b7f7ab43a49a5ef52
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterize_top_lev_divide.cpp
@@ -0,0 +1,73 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterize_top_lev_divide.hpp>
+
+void generateDivParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+    if((feat_1->type() == NODE_TYPE::INV) || (feat_2->type() == NODE_TYPE::INV) || (feat_2->type() == NODE_TYPE::DIV))
+        return;
+
+    node_ptr new_feat = std::make_shared<DivParamTopLevNode>(feat_1, feat_2, feat_ind, prop);
+
+    if((new_feat->parameters()[0] * feat_2->domain() + new_feat->parameters()[1]).contains(0.0))
+        return;
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+DivParamTopLevNode::DivParamTopLevNode()
+{}
+
+DivParamTopLevNode::DivParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    DivParamNode(feat_1, feat_2, feat_ind, l_bound, u_bound)
+{
+     if((feat_1->type() == NODE_TYPE::INV) || (feat_2->type() == NODE_TYPE::INV) || (feat_2->type() == NODE_TYPE::DIV))
+        throw InvalidFeatureException();
+
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if((_params[0] * _feats[1]->domain() + _params[1]).contains(0.0))
+        throw InvalidFeatureException();
+
+    set_value();
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+DivParamTopLevNode::DivParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, std::vector<double>& prop) :
+    DivParamNode(feat_1, feat_2, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+
+    get_parameters(prop);
+}
+
+DivParamTopLevNode::DivParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound) :
+    DivParamNode(feat_1, feat_2, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void DivParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+
+    if(_selected)
+        allowed_op_funcs::div(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+    allowed_op_funcs::div(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+void DivParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::div(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _feats[1]->test_value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void DivParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[0] = 1.0;
+    ub[0] = 1.0;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterize_top_lev_divide.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterize_top_lev_divide.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..960815812acaf9a5ac4ef4679f0e32a6fcc372aa
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterize_top_lev_divide.hpp
@@ -0,0 +1,131 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterize_top_levdivide.hpp
+ *  @brief Class describing the parameterized addition operator
+ *
+ *  This class represents the parameterized unary operator -> A / (alpha * B + a)
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_DIV_NODE
+#define PARAM_TOP_LEV_DIV_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterized_divide.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_param_add_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class DivParamTopLevNode: public DivParamNode
+{
+    using DivParamNode::set_value;
+    using DivParamNode::set_test_value;
+    using DivParamNode::value_ptr;
+    using DivParamNode::test_value_ptr;
+    using DivParamNode::domain;
+    using DivParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<DivParamNode>(*this);
+    }
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    DivParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_2 shared_ptr of the feature to operate on (B)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    DivParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_2 shared_ptr of the feature to operate on (B)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    DivParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    DivParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: div_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: div_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: div_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: div_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "[(" + _feats[0]->expr() + ") / (" + std::to_string(_params[0]) + "*" + _feats[1]->expr() + " + " + std::to_string(_params[1]) + ")]";}
+
+    // DocString: div_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().div(_feats[1]->domain(), _params[0], _params[1]);}
+
+    // DocString: div_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateDivParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterized_divide.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterized_divide.cpp
index a2e6bc0d9a72fda148706d631a204390117a7cf7..cbdc91142a258e641fdcc0536e29af90ec5698ba 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterized_divide.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterized_divide.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterized_divide.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(DivParamNode)
+
 void generateDivParamNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterized_divide.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterized_divide.hpp
index 66f871d827fcad34f030668a1fee99ada0966449..926165e4657eda28b22002bf3d4ce2168fdebc32 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterized_divide.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterized_divide.hpp
@@ -19,13 +19,6 @@
  */
 class DivParamNode: public DivNode
 {
-    using DivNode::set_value;
-    using DivNode::set_test_value;
-    using DivNode::value_ptr;
-    using DivNode::test_value_ptr;
-    using DivNode::domain;
-    using DivNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -39,8 +32,17 @@ class DivParamNode: public DivNode
         ar & boost::serialization::base_object<DivNode>(*this);
         ar & _params;
     }
+
 protected:
+    using DivNode::set_value;
+    using DivNode::set_test_value;
+    using DivNode::value_ptr;
+    using DivNode::test_value_ptr;
+    using DivNode::domain;
+    using DivNode::expr;
+
     std::vector<double> _params;
+
 public:
     /**
      * @brief Base Constructor
@@ -82,7 +84,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    DivParamNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound);
+    DivParamNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: div_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterize_top_lev_exponential.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterize_top_lev_exponential.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..db984723e75c684a56ab8d7677d51ca7b0f967fa
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterize_top_lev_exponential.cpp
@@ -0,0 +1,68 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterize_top_lev_exponential.hpp>
+
+void generateExpParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+
+    if((feat->type() == NODE_TYPE::NEG_EXP) || (feat->type() == NODE_TYPE::EXP) || (feat->type() == NODE_TYPE::ADD) || (feat->type() == NODE_TYPE::SUB) || (feat->type() == NODE_TYPE::LOG))
+        return;
+
+    node_ptr new_feat = std::make_shared<ExpParamTopLevNode>(feat, feat_ind, prop);
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+ExpParamTopLevNode::ExpParamTopLevNode()
+{}
+
+ExpParamTopLevNode::ExpParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    ExpParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    if((feat->type() == NODE_TYPE::NEG_EXP) || (feat->type() == NODE_TYPE::EXP) || (feat->type() == NODE_TYPE::ADD) || (feat->type() == NODE_TYPE::SUB) || (feat->type() == NODE_TYPE::LOG))
+        throw InvalidFeatureException();
+
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+ExpParamTopLevNode::ExpParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    ExpParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+ExpParamTopLevNode::ExpParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    ExpParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void ExpParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::exp(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::exp(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+void ExpParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::exp(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void ExpParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[0] = 0.0;
+
+    *(lb - from_parent) = 1.0;
+    *(ub - from_parent) = 1.0;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterize_top_lev_exponential.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterize_top_lev_exponential.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4bfc5ca8c7e66cef1350aab61aaa8a3f500a39b8
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterize_top_lev_exponential.hpp
@@ -0,0 +1,130 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterize_top_levexponetial.hpp
+ *  @brief Class describing the parameterized exp operator
+ *
+ *  This class represents the parameterized unary operator -> exp(alpha * A + a)
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_EXP_NODE
+#define PARAM_TOP_LEV_EXP_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterized_exponential.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class ExpParamTopLevNode: public ExpParamNode
+{
+    using ExpParamNode::set_value;
+    using ExpParamNode::set_test_value;
+    using ExpParamNode::value_ptr;
+    using ExpParamNode::test_value_ptr;
+    using ExpParamNode::domain;
+    using ExpParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<ExpParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    ExpParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    ExpParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    ExpParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    ExpParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: exp_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: exp_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: exp_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: exp_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "exp(" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + ")";}
+
+    // DocString: exp_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().exp(_params[0], _params[1]);}
+
+    // DocString: exp_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateExpParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterized_exponential.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterized_exponential.cpp
index cce7c76090f9fb8c5592e831d21cd9dc03b3fa77..7158781048b65bb06c5515589e4d8d4fa601c57c 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterized_exponential.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterized_exponential.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterized_exponential.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(ExpParamNode)
+
 void generateExpParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterized_exponential.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterized_exponential.hpp
index 9b444415e49cc2f9820f0b35302345f721f6ff3f..6f3556d5902faa5e4799cc358090c1b5ef9751d0 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterized_exponential.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterized_exponential.hpp
@@ -19,13 +19,6 @@
  */
 class ExpParamNode: public ExpNode
 {
-    using ExpNode::set_value;
-    using ExpNode::set_test_value;
-    using ExpNode::value_ptr;
-    using ExpNode::test_value_ptr;
-    using ExpNode::domain;
-    using ExpNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -41,6 +34,13 @@ class ExpParamNode: public ExpNode
     }
 
 protected:
+    using ExpNode::set_value;
+    using ExpNode::set_test_value;
+    using ExpNode::value_ptr;
+    using ExpNode::test_value_ptr;
+    using ExpNode::domain;
+    using ExpNode::expr;
+
     std::vector<double> _params; //!< The parameters vector
 
 public:
@@ -82,7 +82,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    ExpParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    ExpParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: exp_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterize_top_lev_inverse.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterize_top_lev_inverse.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4e7f32c7eb0c226ae00083a186b80dabe67e28b1
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterize_top_lev_inverse.cpp
@@ -0,0 +1,73 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterize_top_lev_inverse.hpp>
+
+void generateInvParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+
+    if((feat->type() == NODE_TYPE::DIV) || (feat->type() == NODE_TYPE::INV))
+        return;
+
+    node_ptr new_feat = std::make_shared<InvParamTopLevNode>(feat, feat_ind, prop);
+
+    if(new_feat->parameters()[0] * feat->domain() + new_feat->parameters()[1] <= 0.0)
+        return;
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+InvParamTopLevNode::InvParamTopLevNode()
+{}
+
+InvParamTopLevNode::InvParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    InvParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    if((feat->type() == NODE_TYPE::DIV) || (feat->type() == NODE_TYPE::INV))
+        throw InvalidFeatureException();
+
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if((_params[0] * _feats[0]->domain() + _params[1]).contains(0.0))
+        throw InvalidFeatureException();
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+InvParamTopLevNode::InvParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    InvParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+InvParamTopLevNode::InvParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    InvParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void InvParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::inv(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::inv(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void InvParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::inv(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void InvParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[0] = 1.0;
+    ub[0] = 1.0;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterize_top_lev_inverse.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterize_top_lev_inverse.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..9916ad7fd0d2792d015643002fb6bf080c33e978
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterize_top_lev_inverse.hpp
@@ -0,0 +1,130 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterize_top_levinverse.hpp
+ *  @brief Class describing the parameterized inverse operator
+ *
+ *  This class represents the parameterized unary operator -> 1.0 / (alpha * A + a)
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_INV_NODE
+#define PARAM_TOP_LEV_INV_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterized_inverse.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class InvParamTopLevNode: public InvParamNode
+{
+    using InvParamNode::set_value;
+    using InvParamNode::set_test_value;
+    using InvParamNode::value_ptr;
+    using InvParamNode::test_value_ptr;
+    using InvParamNode::domain;
+    using InvParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<InvParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    InvParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    InvParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    InvParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    InvParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: inv_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: inv_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: inv_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: inv_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "1.0 / (" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + ")";}
+
+    // DocString: inv_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().inv(_params[0], _params[1]);}
+
+    // DocString: inv_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateInvParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterized_inverse.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterized_inverse.cpp
index 4e61fb6f3e4eb4b75f4d2f47eaa446d5df8c70fb..a9dc1db93c0517b73862036841a5f78ca6a16808 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterized_inverse.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterized_inverse.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterized_inverse.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(InvParamNode)
+
 void generateInvParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterized_inverse.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterized_inverse.hpp
index 2ee689306a79b64d9a2ae41222b45086929d7ff1..b0cb4375d4281c35a24d854ff7574e007bc8c5b1 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterized_inverse.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterized_inverse.hpp
@@ -19,13 +19,6 @@
  */
 class InvParamNode: public InvNode
 {
-    using InvNode::set_value;
-    using InvNode::set_test_value;
-    using InvNode::value_ptr;
-    using InvNode::test_value_ptr;
-    using InvNode::domain;
-    using InvNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -41,6 +34,13 @@ class InvParamNode: public InvNode
     }
 
 protected:
+    using InvNode::set_value;
+    using InvNode::set_test_value;
+    using InvNode::value_ptr;
+    using InvNode::test_value_ptr;
+    using InvNode::domain;
+    using InvNode::expr;
+
     std::vector<double> _params; //!< The parameters vector
 
 public:
@@ -82,7 +82,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    InvParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    InvParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: inv_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterize_top_lev_log.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterize_top_lev_log.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..95c620951e5d04e1b7438c469e55f2cead6e979e
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterize_top_lev_log.cpp
@@ -0,0 +1,73 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterize_top_lev_log.hpp>
+
+
+void generateLogParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+
+    if((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) || (feat->type() == NODE_TYPE::SQ) || (feat->type() == NODE_TYPE::CBRT) || (feat->type() == NODE_TYPE::SQRT))
+        return;
+
+    node_ptr new_feat = std::make_shared<LogParamTopLevNode>(feat, feat_ind, prop);
+    if(new_feat->parameters()[0] * feat->domain() + new_feat->parameters()[1] <= 0.0)
+        return;
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+LogParamTopLevNode::LogParamTopLevNode()
+{}
+
+LogParamTopLevNode::LogParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    LogParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    if((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) || (feat->type() == NODE_TYPE::SQ) || (feat->type() == NODE_TYPE::CBRT) || (feat->type() == NODE_TYPE::SQRT))
+        throw InvalidFeatureException();
+
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if((_params[0] * _feats[0]->domain() + _params[1]) <= 0.0)
+        throw InvalidFeatureException();
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+LogParamTopLevNode::LogParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    LogParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+LogParamTopLevNode::LogParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    LogParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void LogParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::log(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::log(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void LogParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::log(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void LogParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    *(lb - from_parent + 1) = 0.0;
+    *(ub - from_parent + 1) = 0.0;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterize_top_lev_log.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterize_top_lev_log.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..368671cdc148240a58418c0a71e619aea696970a
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterize_top_lev_log.hpp
@@ -0,0 +1,130 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterize_top_levlog.hpp
+ *  @brief Class describing the parameterized log operator
+ *
+ *  This class represents the parameterized unary operator -> log(alpha * A + a)
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_LOG_NODE
+#define PARAM_TOP_LEV_LOG_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterized_log.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class LogParamTopLevNode: public LogParamNode
+{
+    using LogParamNode::set_value;
+    using LogParamNode::set_test_value;
+    using LogParamNode::value_ptr;
+    using LogParamNode::test_value_ptr;
+    using LogParamNode::domain;
+    using LogParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<LogParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    LogParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    LogParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    LogParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    LogParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: log_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: log_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: log_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: log_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "log(" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + ")";}
+
+    // DocString: log_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().log(_params[0], _params[1]);}
+
+    // DocString: log_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateLogParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterized_log.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterized_log.cpp
index a2830d1b343d361b4bc1cc9e782fddc905c08109..7822ce70ac1d11207a6096fa80fe6ffe4a8c5cb1 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterized_log.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterized_log.cpp
@@ -1,5 +1,6 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterized_log.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(LogParamNode)
 
 void generateLogParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterized_log.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterized_log.hpp
index c44051ab5f4620529170d96d3da8a5483f1d6b6f..240095606c5f0fa0fe16e7bfbcb3b6080209fd11 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterized_log.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterized_log.hpp
@@ -19,14 +19,6 @@
  */
 class LogParamNode: public LogNode
 {
-    using LogNode::set_value;
-    using LogNode::set_test_value;
-    using LogNode::domain;
-    using LogNode::expr;
-    using LogNode::value_ptr;
-    using LogNode::test_value_ptr;
-
-
     friend class boost::serialization::access;
 
     /**
@@ -42,6 +34,13 @@ class LogParamNode: public LogNode
     }
 
 protected:
+    using LogNode::set_value;
+    using LogNode::set_test_value;
+    using LogNode::domain;
+    using LogNode::expr;
+    using LogNode::value_ptr;
+    using LogNode::test_value_ptr;
+
     std::vector<double> _params; //!< The parameters vector
 
 public:
@@ -83,7 +82,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    LogParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    LogParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: log_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterize_top_lev_multiply.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterize_top_lev_multiply.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fbd219c0ef4e954785eb8e3882247e64a018532d
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterize_top_lev_multiply.cpp
@@ -0,0 +1,60 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterize_top_lev_multiply.hpp>
+
+void generateMultParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+    node_ptr new_feat = std::make_shared<MultParamTopLevNode>(feat_1, feat_2, feat_ind, prop);
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+MultParamTopLevNode::MultParamTopLevNode()
+{}
+
+MultParamTopLevNode::MultParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop):
+    MultParamNode(feat_1, feat_2, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+MultParamTopLevNode::MultParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound):
+    MultParamNode(feat_1, feat_2, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+MultParamTopLevNode::MultParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, std::vector<double>& prop):
+    MultParamNode(feat_1, feat_2, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+void MultParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+
+    if(_selected)
+        allowed_op_funcs::mult(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+    allowed_op_funcs::mult(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void MultParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::mult(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _feats[1]->test_value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void MultParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[0] = 1.0;
+    ub[0] = 1.0;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterize_top_lev_multiply.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterize_top_lev_multiply.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..7e630725a27ebf76b1f9b02010c8c21c1713213b
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterize_top_lev_multiply.hpp
@@ -0,0 +1,130 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterize_top_levmultiply.hpp
+ *  @brief Class describing the parameterized addition operator
+ *
+ *  This class represents the parameterized unary operator -> A * (alpha * B + a)
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_MULT_NODE
+#define PARAM_TOP_LEV_MULT_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterized_multiply.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_param_add_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class MultParamTopLevNode: public MultParamNode
+{
+    using MultParamNode::set_value;
+    using MultParamNode::set_test_value;
+    using MultParamNode::value_ptr;
+    using MultParamNode::test_value_ptr;
+    using MultParamNode::domain;
+    using MultParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<MultParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    MultParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    MultParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    MultParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    MultParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: mult_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: mult_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: mult_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: mult_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "[(" + _feats[0]->expr() + ") * (" + std::to_string(_params[0]) + "*" + _feats[1]->expr() + " + " + std::to_string(_params[1]) + ")]";}
+
+    // DocString: mult_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().mult(_feats[1]->domain(), _params[0], _params[1]);}
+
+    // DocString: add_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateMultParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterized_multiply.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterized_multiply.cpp
index 0e61b8b9f2605fea003b271e2f08ba3fa7169b62..d86d18146f3798c3b56c305c102c61359c021a4a 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterized_multiply.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterized_multiply.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterized_multiply.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(MultParamNode)
+
 void generateMultParamNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterized_multiply.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterized_multiply.hpp
index f404b83998229476c0f7220df572055466026145..171bea8e63d07ede1a39b6b4a21d4719d4d458e2 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterized_multiply.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterized_multiply.hpp
@@ -19,13 +19,6 @@
  */
 class MultParamNode: public MultNode
 {
-    using MultNode::set_value;
-    using MultNode::set_test_value;
-    using MultNode::value_ptr;
-    using MultNode::test_value_ptr;
-    using MultNode::domain;
-    using MultNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -39,8 +32,17 @@ class MultParamNode: public MultNode
         ar & boost::serialization::base_object<MultNode>(*this);
         ar & _params;
     }
+
 protected:
+    using MultNode::set_value;
+    using MultNode::set_test_value;
+    using MultNode::value_ptr;
+    using MultNode::test_value_ptr;
+    using MultNode::domain;
+    using MultNode::expr;
+
     std::vector<double> _params;
+
 public:
     /**
      * @brief Base Constructor
@@ -80,7 +82,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    MultParamNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound);
+    MultParamNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: mult_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterize_top_lev_negative_exponential.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterize_top_lev_negative_exponential.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2f11c69c7bf82be132f588bdaf3b6a2113ef8eb4
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterize_top_lev_negative_exponential.cpp
@@ -0,0 +1,69 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterize_top_lev_negative_exponential.hpp>
+
+void generateNegExpParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+
+    if((feat->type() == NODE_TYPE::NEG_EXP) || (feat->type() == NODE_TYPE::EXP) || (feat->type() == NODE_TYPE::ADD) || (feat->type() == NODE_TYPE::SUB) || (feat->type() == NODE_TYPE::LOG))
+        return;
+
+    node_ptr new_feat = std::make_shared<NegExpParamTopLevNode>(feat, feat_ind, prop);
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+NegExpParamTopLevNode::NegExpParamTopLevNode()
+{}
+
+NegExpParamTopLevNode::NegExpParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    NegExpParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    if((feat->type() == NODE_TYPE::NEG_EXP) || (feat->type() == NODE_TYPE::EXP) || (feat->type() == NODE_TYPE::ADD) || (feat->type() == NODE_TYPE::SUB) || (feat->type() == NODE_TYPE::LOG))
+        throw InvalidFeatureException();
+
+    _params.resize(n_params(),  0.0);
+    get_parameters(prop);
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+NegExpParamTopLevNode::NegExpParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    NegExpParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(),  0.0);
+    get_parameters(prop);
+}
+
+NegExpParamTopLevNode::NegExpParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    NegExpParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(),  0.0);
+}
+
+void NegExpParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::neg_exp(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::neg_exp(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void NegExpParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::neg_exp(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void NegExpParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[0] = 0.0;
+
+    *(lb - from_parent) = 1.0;
+    *(ub - from_parent) = 1.0;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterize_top_lev_negative_exponential.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterize_top_lev_negative_exponential.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c33ecb0650ffd522ed1634158be91e824f28bf9a
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterize_top_lev_negative_exponential.hpp
@@ -0,0 +1,130 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterize_top_levnegative_exponetial.hpp
+ *  @brief Class describing the parameterized neg_exp operator
+ *
+ *  This class represents the parameterized unary operator -> exp(-alpha * A + a)
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_NEG_EXP_NODE
+#define PARAM_TOP_LEV_NEG_EXP_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterized_negative_exponential.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class NegExpParamTopLevNode: public NegExpParamNode
+{
+    using NegExpParamNode::set_value;
+    using NegExpParamNode::set_test_value;
+    using NegExpParamNode::value_ptr;
+    using NegExpParamNode::test_value_ptr;
+    using NegExpParamNode::domain;
+    using NegExpParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<NegExpParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    NegExpParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    NegExpParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    NegExpParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    NegExpParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: neg_exp_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: neg_exp_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: neg_exp_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: neg_exp_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "exp[-1.0*(" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + ")]";}
+
+    // DocString: neg_exp_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().exp(-1.0 * _params[0], _params[1]);}
+
+    // DocString: add_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateNegExpParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterized_negative_exponential.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterized_negative_exponential.cpp
index 71a0eb940191533c3300c83011719c00c6090cfd..f5251c061d951ebf17151993673f36de3db9e1cf 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterized_negative_exponential.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterized_negative_exponential.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterized_negative_exponential.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(NegExpParamNode)
+
 void generateNegExpParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterized_negative_exponential.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterized_negative_exponential.hpp
index 9f3c67dc0d3d6944df26580c199722cc5144889c..5f6c8e2a4b6d888b2b9aa21e83b9b5d95ca6b9f9 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterized_negative_exponential.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterized_negative_exponential.hpp
@@ -19,13 +19,6 @@
  */
 class NegExpParamNode: public NegExpNode
 {
-    using NegExpNode::set_value;
-    using NegExpNode::set_test_value;
-    using NegExpNode::value_ptr;
-    using NegExpNode::test_value_ptr;
-    using NegExpNode::domain;
-    using NegExpNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -41,6 +34,13 @@ class NegExpParamNode: public NegExpNode
     }
 
 protected:
+    using NegExpNode::set_value;
+    using NegExpNode::set_test_value;
+    using NegExpNode::value_ptr;
+    using NegExpNode::test_value_ptr;
+    using NegExpNode::domain;
+    using NegExpNode::expr;
+
     std::vector<double> _params; //!< The parameters vector
 
 public:
@@ -82,7 +82,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    NegExpParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    NegExpParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: neg_exp_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterize_top_lev_sin.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterize_top_lev_sin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aa48bf560845872442a2c386f54fe0a19b11f873
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterize_top_lev_sin.cpp
@@ -0,0 +1,67 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterize_top_lev_sin.hpp>
+
+void generateSinParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+
+    if((feat->type() == NODE_TYPE::SIN) || (feat->type() == NODE_TYPE::COS))
+        return;
+
+    node_ptr new_feat = std::make_shared<SinParamTopLevNode>(feat, feat_ind, prop);
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+SinParamTopLevNode::SinParamTopLevNode()
+{}
+
+SinParamTopLevNode::SinParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    SinParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    if((feat->type() == NODE_TYPE::SIN) || (feat->type() == NODE_TYPE::COS))
+        throw InvalidFeatureException();
+
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+SinParamTopLevNode::SinParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    SinParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+SinParamTopLevNode::SinParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    SinParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void SinParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::sin(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::sin(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void SinParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::sin(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void SinParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[1] = -1.0 * M_PI;
+    ub[1] = M_PI;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterize_top_lev_sin.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterize_top_lev_sin.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4989ec8c84a20537ce1eb45290d3245485d72f10
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterize_top_lev_sin.hpp
@@ -0,0 +1,130 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterize_top_levsin.hpp
+ *  @brief Class describing the parameterized sin operator
+ *
+ *  This class represents the parameterized unary operator -> sin(alpha * A + a)
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_SIN_NODE
+#define PARAM_TOP_LEV_SIN_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class SinParamTopLevNode: public SinParamNode
+{
+    using SinParamNode::set_value;
+    using SinParamNode::set_test_value;
+    using SinParamNode::value_ptr;
+    using SinParamNode::test_value_ptr;
+    using SinParamNode::domain;
+    using SinParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<SinParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    SinParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    SinParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    SinParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    SinParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: sin_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: sin_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: sin_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: sin_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "sin(" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + ")";}
+
+    // DocString: sin_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return Domain(-1.0, 1.0);}
+
+    // DocString: add_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateSinParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.cpp
index 00df12593d6f6ed4be36cc4c74dbfd9d7d82870a..b0a006ec8bfd15e0994b4e139ebb725661dc6c26 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(SinParamNode)
+
 void generateSinParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.hpp
index a08f04e6453f56200ad6676822805eb5412c3781..1824afe51d6c0915afa6561fa21d08d9462a1585 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.hpp
@@ -19,13 +19,6 @@
  */
 class SinParamNode: public SinNode
 {
-    using SinNode::set_value;
-    using SinNode::set_test_value;
-    using SinNode::value_ptr;
-    using SinNode::test_value_ptr;
-    using SinNode::domain;
-    using SinNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -41,6 +34,13 @@ class SinParamNode: public SinNode
     }
 
 protected:
+    using SinNode::set_value;
+    using SinNode::set_test_value;
+    using SinNode::value_ptr;
+    using SinNode::test_value_ptr;
+    using SinNode::domain;
+    using SinNode::expr;
+
     std::vector<double> _params; //!< The parameters vector
 
 public:
@@ -82,7 +82,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    SinParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    SinParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: sin_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterize_top_lev_sixth_power.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterize_top_lev_sixth_power.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..56f3fff8a99e465dcd81a891d1c380086f2349ab
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterize_top_lev_sixth_power.cpp
@@ -0,0 +1,60 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterize_top_lev_sixth_power.hpp>
+
+void generateSixPowParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+    node_ptr new_feat = std::make_shared<SixPowParamTopLevNode>(feat, feat_ind, prop);
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+SixPowParamTopLevNode::SixPowParamTopLevNode()
+{}
+
+SixPowParamTopLevNode::SixPowParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    SixPowParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+SixPowParamTopLevNode::SixPowParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    SixPowParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+SixPowParamTopLevNode::SixPowParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    SixPowParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void SixPowParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::sixth_pow(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::sixth_pow(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void SixPowParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::sixth_pow(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void SixPowParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[0] = 1.0;
+    ub[0] = 1.0;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterize_top_lev_sixth_power.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterize_top_lev_sixth_power.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b49b8ffabd460e6bf838c839136a0f7b054eb17c
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterize_top_lev_sixth_power.hpp
@@ -0,0 +1,131 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterize_top_levsixth_pow.hpp
+ *  @brief Class describing the parameterized sixth power operator
+ *
+ *  This class represents the parameterized unary operator -> (alpha * A + a)^6
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_SIX_POW_NODE
+#define PARAM_TOP_LEV_SIX_POW_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterized_sixth_power.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class SixPowParamTopLevNode: public SixPowParamNode
+{
+    using SixPowParamNode::set_value;
+    using SixPowParamNode::set_test_value;
+    using SixPowParamNode::value_ptr;
+    using SixPowParamNode::test_value_ptr;
+    using SixPowParamNode::domain;
+    using SixPowParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<SixPowParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    SixPowParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     * @param prop The property to fit to
+     */
+    SixPowParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    SixPowParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    SixPowParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: six_pow_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: six_pow_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: six_pow_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: six_pow_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "(" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + ")^6";}
+
+    // DocString: six_pow_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().pow(6.0, _params[0], _params[1]);}
+
+    // DocString: add_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateSixPowParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterized_sixth_power.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterized_sixth_power.cpp
index d317ebab8391bb67d22694f4c7f8be7dae5d93a8..e650e8cf9a83db79d53e6a8905778e4db09407ab 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterized_sixth_power.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterized_sixth_power.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterized_sixth_power.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(SixPowParamNode)
+
 void generateSixPowParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterized_sixth_power.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterized_sixth_power.hpp
index 903c68bcc05b869efab54a86556ac9daeead749d..0ff6829da1242d3c51da22a5560bf43469d6cc66 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterized_sixth_power.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterized_sixth_power.hpp
@@ -19,13 +19,6 @@
  */
 class SixPowParamNode: public SixPowNode
 {
-    using SixPowNode::set_value;
-    using SixPowNode::set_test_value;
-    using SixPowNode::value_ptr;
-    using SixPowNode::test_value_ptr;
-    using SixPowNode::domain;
-    using SixPowNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -41,6 +34,13 @@ class SixPowParamNode: public SixPowNode
     }
 
 protected:
+    using SixPowNode::set_value;
+    using SixPowNode::set_test_value;
+    using SixPowNode::value_ptr;
+    using SixPowNode::test_value_ptr;
+    using SixPowNode::domain;
+    using SixPowNode::expr;
+
     std::vector<double> _params; //!< The parameters vector
 
 public:
@@ -83,7 +83,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    SixPowParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    SixPowParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: six_pow_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterize_top_lev_square.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterize_top_lev_square.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1aab76018ad2e5ada2eecb6269271b029eeb2fb5
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterize_top_lev_square.cpp
@@ -0,0 +1,60 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterize_top_lev_square.hpp>
+
+void generateSqParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+    node_ptr new_feat = std::make_shared<SqParamTopLevNode>(feat, feat_ind, prop);
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+SqParamTopLevNode::SqParamTopLevNode()
+{}
+
+SqParamTopLevNode::SqParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    SqParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+SqParamTopLevNode::SqParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    SqParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+SqParamTopLevNode::SqParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    SqParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void SqParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::sq(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::sq(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void SqParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::sq(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void SqParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[0] = 1.0;
+    ub[0] = 1.0;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterize_top_lev_square.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterize_top_lev_square.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5c2a9c094e498307cfaad78f379733b134e98b7a
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterize_top_lev_square.hpp
@@ -0,0 +1,130 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterize_top_levsquare.hpp
+ *  @brief Class describing the parameterized square operator
+ *
+ *  This class represents the parameterized unary operator -> (alpha * A + a)^2
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_SQ_NODE
+#define PARAM_TOP_LEV_SQ_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterized_square.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class SqParamTopLevNode: public SqParamNode
+{
+    using SqParamNode::set_value;
+    using SqParamNode::set_test_value;
+    using SqParamNode::value_ptr;
+    using SqParamNode::test_value_ptr;
+    using SqParamNode::domain;
+    using SqParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<SqParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    SqParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    SqParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    SqParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    SqParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: sq_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: sq_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: sq_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: sq_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "sqrt(" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + ")";}
+
+    // DocString: sq_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().pow(1.0 / 2.0, _params[0], _params[1]);}
+
+    // DocString: add_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateSqParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterized_square.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterized_square.cpp
index be9f569abb7465754e2ebe9761f48c8636fea77a..6982914a23ce00eb4e3739212ecf82ca22b286c8 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterized_square.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterized_square.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterized_square.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(SqParamNode)
+
 void generateSqParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterized_square.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterized_square.hpp
index f7e69bc09d015dc30f72227a4bd09b6778186a4c..d3eeb416645d8ca5d4207eaa73dab5c62aa0afe0 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterized_square.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterized_square.hpp
@@ -19,13 +19,6 @@
  */
 class SqParamNode: public SqNode
 {
-    using SqNode::set_value;
-    using SqNode::set_test_value;
-    using SqNode::value_ptr;
-    using SqNode::test_value_ptr;
-    using SqNode::domain;
-    using SqNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -41,6 +34,13 @@ class SqParamNode: public SqNode
     }
 
 protected:
+    using SqNode::set_value;
+    using SqNode::set_test_value;
+    using SqNode::value_ptr;
+    using SqNode::test_value_ptr;
+    using SqNode::domain;
+    using SqNode::expr;
+
     std::vector<double> _params; //!< The parameters vector
 
 public:
@@ -82,7 +82,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    SqParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    SqParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: sq_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterize_top_lev_square_root.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterize_top_lev_square_root.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fc4fe6599d50006fd229196efbb61234e9124af7
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterize_top_lev_square_root.cpp
@@ -0,0 +1,66 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterize_top_lev_square_root.hpp>
+
+void generateSqrtParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+    node_ptr new_feat = std::make_shared<SqrtParamTopLevNode>(feat, feat_ind, prop);
+
+    if(new_feat->parameters()[0] * feat->domain() + new_feat->parameters()[1] <= 0.0)
+        return;
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+SqrtParamTopLevNode::SqrtParamTopLevNode()
+{}
+
+SqrtParamTopLevNode::SqrtParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    SqrtParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if((_params[0] * _feats[0]->domain() + _params[1]) <= 0.0)
+        throw InvalidFeatureException();
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+SqrtParamTopLevNode::SqrtParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop) :
+    SqrtParamNode(feat, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+SqrtParamTopLevNode::SqrtParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound) :
+    SqrtParamNode(feat, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void SqrtParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if(_selected)
+        allowed_op_funcs::sqrt(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+
+    allowed_op_funcs::sqrt(_n_samp, _feats[0]->value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void SqrtParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::sqrt(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void SqrtParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[0] = _sign_alpha;
+    ub[0] = _sign_alpha;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterize_top_lev_square_root.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterize_top_lev_square_root.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..40158ff01b9c896ffc6aeb9520e3e71196f3ff0f
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterize_top_lev_square_root.hpp
@@ -0,0 +1,130 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterize_top_levsquare_root.hpp
+ *  @brief Class describing the parameterized square root operator
+ *
+ *  This class represents the parameterized unary operator -> sqrt(alpha * A + a)
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_SQRT_NODE
+#define PARAM_TOP_LEV_SQRT_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterized_square_root.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_abs_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class SqrtParamTopLevNode: public SqrtParamNode
+{
+    using SqrtParamNode::set_value;
+    using SqrtParamNode::set_test_value;
+    using SqrtParamNode::value_ptr;
+    using SqrtParamNode::test_value_ptr;
+    using SqrtParamNode::domain;
+    using SqrtParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<SqrtParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    SqrtParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    SqrtParamTopLevNode(node_ptr feat, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    SqrtParamTopLevNode(node_ptr feat, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    SqrtParamTopLevNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: sqrt_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: sqrt_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: sqrt_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: sqrt_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "sqrt(" + std::to_string(_params[0]) + "*" + _feats[0]->expr() + " + " + std::to_string(_params[1]) + ")";}
+
+    // DocString: sqrt_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().pow(1.0 / 2.0, _params[0], _params[1]);}
+
+    // DocString: add_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateSqrtParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterized_square_root.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterized_square_root.cpp
index 589e599b159f169b19990cc93ef7a4b81d4dcd1d..2edeb2da2dcc1f4da9442b00e73ac2956b2e6037 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterized_square_root.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterized_square_root.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterized_square_root.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(SqrtParamNode)
+
 void generateSqrtParamNode(std::vector<node_ptr>& feat_list, node_ptr feat, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterized_square_root.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterized_square_root.hpp
index acfcf9db82a647763c2ea3b9a696b729da57049c..d8ee9f35535b264c3d7d8dbfc43f2860a20459fc 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterized_square_root.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterized_square_root.hpp
@@ -19,13 +19,6 @@
  */
 class SqrtParamNode: public SqrtNode
 {
-    using SqrtNode::set_value;
-    using SqrtNode::set_test_value;
-    using SqrtNode::value_ptr;
-    using SqrtNode::test_value_ptr;
-    using SqrtNode::domain;
-    using SqrtNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -42,6 +35,13 @@ class SqrtParamNode: public SqrtNode
     }
 
 protected:
+    using SqrtNode::set_value;
+    using SqrtNode::set_test_value;
+    using SqrtNode::value_ptr;
+    using SqrtNode::test_value_ptr;
+    using SqrtNode::domain;
+    using SqrtNode::expr;
+
     std::vector<double> _params; //!< The parameters vector
     double _sign_alpha; //!< 1 if alpha is positive, -1 if alpha is negative
 
@@ -84,7 +84,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    SqrtParamNode(node_ptr feat, int feat_ind, double l_bound, double u_bound);
+    SqrtParamNode(node_ptr feat, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: sqrt_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterize_top_lev_subtract.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterize_top_lev_subtract.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..da611609fd51ec8af2e0ba86e4f76f104fb59dac
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterize_top_lev_subtract.cpp
@@ -0,0 +1,60 @@
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterize_top_lev_subtract.hpp>
+
+void generateSubParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
+{
+    ++feat_ind;
+    node_ptr new_feat = std::make_shared<SubParamTopLevNode>(feat_1, feat_2, feat_ind, prop);
+
+    new_feat->set_value();
+    if(new_feat->is_nan() || new_feat->is_const() || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) > u_bound) || (util_funcs::max_abs_val<double>(new_feat->value_ptr(), new_feat->n_samp()) < l_bound))
+        return;
+
+    feat_list.push_back(new_feat);
+}
+
+SubParamTopLevNode::SubParamTopLevNode()
+{}
+
+SubParamTopLevNode::SubParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop) :
+    SubParamNode(feat_1, feat_2, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+
+    if(is_nan() || is_const() || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) > u_bound) || (util_funcs::max_abs_val<double>(value_ptr(), _n_samp) < l_bound))
+        throw InvalidFeatureException();
+}
+
+SubParamTopLevNode::SubParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, std::vector<double>& prop) :
+    SubParamNode(feat_1, feat_2, feat_ind)
+{
+    _params.resize(n_params(), 0.0);
+    get_parameters(prop);
+}
+
+SubParamTopLevNode::SubParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound) :
+    SubParamNode(feat_1, feat_2, feat_ind, l_bound, u_bound)
+{
+    _params.resize(n_params(), 0.0);
+}
+
+void SubParamTopLevNode::set_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+
+    if(_selected)
+        allowed_op_funcs::sub(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_d_matrix_ptr(_d_mat_ind));
+    allowed_op_funcs::sub(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void SubParamTopLevNode::set_test_value(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    allowed_op_funcs::sub(_n_test_samp, _feats[0]->test_value_ptr(offset + 2), _feats[1]->test_value_ptr(offset + 1), _params[0], _params[1], node_value_arrs::get_test_value_ptr(_arr_ind, _feat_ind, offset, false));
+}
+
+void SubParamTopLevNode::set_bounds(double* lb, double* ub, int from_parent)
+{
+    lb[1] = 0.0;
+    ub[1] = 0.0;
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterize_top_lev_subtract.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterize_top_lev_subtract.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5fac02dc2413910d336513f4433226bc49ea7f8e
--- /dev/null
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterize_top_lev_subtract.hpp
@@ -0,0 +1,132 @@
+/** @file feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterize_top_levsubtract.hpp
+ *  @brief Class describing the parameterized addition operator
+ *
+ *  This class represents the parameterized unary operator -> A - (alpha * B + a)
+ *
+ *  @author Thomas A. R. Purcell (tpurcell)
+ *  @bug No known bugs.
+ */
+#ifndef PARAM_TOP_LEV_SUB_NODE
+#define PARAM_TOP_LEV_SUB_NODE
+
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterized_subtract.hpp>
+#include <nl_opt/NLOptWrapper.hpp>
+
+// DocString: cls_param_add_node
+/**
+ * @brief ParamNode for the absolute value operator
+ *
+ */
+class SubParamTopLevNode: public SubParamNode
+{
+    using SubParamNode::set_value;
+    using SubParamNode::set_test_value;
+    using SubParamNode::value_ptr;
+    using SubParamNode::test_value_ptr;
+    using SubParamNode::domain;
+    using SubParamNode::expr;
+
+    friend class boost::serialization::access;
+
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<SubParamNode>(*this);
+    }
+
+public:
+    /**
+     * @brief Base Constructor
+     * @details This is only used for serialization
+     */
+    SubParamTopLevNode();
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_2 shared_ptr of the feature to operate on (B)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param prop The property to fit to
+     */
+    SubParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_2 shared_ptr of the feature to operate on (B)
+     * @param feat_ind Index of the new feature
+     * @param prop The property to fit to
+     */
+    SubParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, std::vector<double>& prop);
+
+    /**
+     * @brief Constructor
+     * @details Constructs the ParamNode from node pointer of the feature to operate on
+     *
+     * @param feat_1 shared_ptr of the feature to operate on (A)
+     * @param feat_ind Index of the new feature
+     * @param l_bound Minimum absolute value allowed for the feature.
+     * @param u_bound Maximum absolute value allowed for the feature.
+     * @param param_list The list of parameters to optimize using non-linear least squares
+     */
+    SubParamTopLevNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
+
+    // DocString: sub_param_top_lev_node_n_params
+    /**
+     * @brief returns the number of theoretical parameters for this feature
+     * @return the number of theoretical parameters
+     */
+    inline int n_params(int n_cur = 0){return 2;}
+
+    // DocString: sub_param_top_lev_node_set_value
+    /**
+     * @brief Set the values of the training data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_value(int offset = -1);
+
+    // DocString: sub_param_top_lev_node_set_test_value
+    /**
+     * @brief Set the values of the test data for the feature inside of the value storage arrays
+     *
+     * @param offset(int) Key to determine which part of the temporary storage array to look into
+     */
+    void set_test_value(int offset = -1);
+
+    // DocString: sub_param_top_lev_node_expr
+    /**
+     * @brief Get the expression for the overall feature (From root node down)
+     */
+    inline std::string expr(){return "[(" + _feats[0]->expr() + ") - (" + std::to_string(_params[0]) + "*" + _feats[1]->expr() + " + " + std::to_string(_params[1]) + ")]";}
+
+    // DocString: sub_param_top_lev_node_domain
+    /**
+     * @brief The domain for the feature (min/max values)
+     */
+    inline Domain domain(){return _feats[0]->domain().sub(_feats[1]->domain(), _params[0], _params[1]);}
+
+    // DocString: add_param_top_lev_node_set_bounds
+    /**
+     * @brief Set the bounds for the nl parameterization
+     *
+     * @param lb pointer to the lower bounds data
+     * @param ub pointer to the upper bounds data
+     */
+    void set_bounds(double* lb, double* ub, int from_parent=2);
+};
+
+void generateSubParamTopLevNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop);
+
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterized_subtract.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterized_subtract.cpp
index cb5b48243678a59fc343c9377b37dbc63cfdbf5d..cb2235800d48b50109076c2218dbcc84c75e2029 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterized_subtract.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterized_subtract.cpp
@@ -1,5 +1,7 @@
 #include <feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterized_subtract.hpp>
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(SubParamNode)
+
 void generateSubParamNode(std::vector<node_ptr>& feat_list, node_ptr feat_1, node_ptr feat_2, int& feat_ind, double l_bound, double u_bound, std::vector<double>& prop)
 {
     ++feat_ind;
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterized_subtract.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterized_subtract.hpp
index 2a0a3aec30ccad3ceffa9e5583902d2fe9c760cd..611bdb04ddf8c6e2c616bd3e623c278b3c5ee654 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterized_subtract.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterized_subtract.hpp
@@ -19,13 +19,6 @@
  */
 class SubParamNode: public SubNode
 {
-    using SubNode::set_value;
-    using SubNode::set_test_value;
-    using SubNode::value_ptr;
-    using SubNode::test_value_ptr;
-    using SubNode::domain;
-    using SubNode::expr;
-
     friend class boost::serialization::access;
 
     /**
@@ -39,8 +32,17 @@ class SubParamNode: public SubNode
         ar & boost::serialization::base_object<SubNode>(*this);
         ar & _params;
     }
+
 protected:
+    using SubNode::set_value;
+    using SubNode::set_test_value;
+    using SubNode::value_ptr;
+    using SubNode::test_value_ptr;
+    using SubNode::domain;
+    using SubNode::expr;
+
     std::vector<double> _params;
+
 public:
     /**
      * @brief Base Constructor
@@ -82,7 +84,7 @@ public:
      * @param u_bound Maximum absolute value allowed for the feature.
      * @param param_list The list of parameters to optimize using non-linear least squares
      */
-    SubParamNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound, double u_bound);
+    SubParamNode(node_ptr feat_1, node_ptr feat_2, int feat_ind, double l_bound=1e-50, double u_bound=1e50);
 
     // DocString: sub_param_node_set_value
     /**
diff --git a/src/feature_creation/node/operator_nodes/allowed_ops.hpp b/src/feature_creation/node/operator_nodes/allowed_ops.hpp
index dfd9d17f0527bbba2a57243a7f034d9fdfb16307..07cc1fed8197895de68f96168d15746d75c64a83 100644
--- a/src/feature_creation/node/operator_nodes/allowed_ops.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_ops.hpp
@@ -7,41 +7,23 @@
 #ifndef ALLOWED_OP_NODES
 #define ALLOWED_OP_NODES
 
-#include <feature_creation/node/Node.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/add/add.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sub/subtract.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs/absolute_value.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/absolute_difference.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/mult/multiply.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/div/divide.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/inv/inverse.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/exp/exponential.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/negative_exponential.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/log/log.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sq/square.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cb/cube.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/sixth_power.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/square_root.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/cube_root.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sin/sin.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cos/cos.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterized_add.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterized_subtract.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterized_absolute_value.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterized_absolute_difference.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterized_multiply.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterized_divide.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterized_inverse.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterized_exponential.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterized_negative_exponential.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterized_log.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterized_square.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterized_cube.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterized_sixth_power.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterized_square_root.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterized_cube_root.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.hpp>
-#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterized_cos.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/add/parameterize_top_lev_add.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sub/parameterize_top_lev_subtract.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs/parameterize_top_lev_absolute_value.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/parameterize_top_lev_absolute_difference.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/mult/parameterize_top_lev_multiply.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/div/parameterize_top_lev_divide.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/inv/parameterize_top_lev_inverse.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/exp/parameterize_top_lev_exponential.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/parameterize_top_lev_negative_exponential.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/log/parameterize_top_lev_log.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sq/parameterize_top_lev_square.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cb/parameterize_top_lev_cube.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/parameterize_top_lev_sixth_power.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/parameterize_top_lev_square_root.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/parameterize_top_lev_cube_root.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterize_top_lev_sin.hpp>
+#include <feature_creation/node/operator_nodes/allowed_operator_nodes/cos/parameterize_top_lev_cos.hpp>
 #include <map>
 #include <iostream>
 
@@ -69,4 +51,4 @@ namespace allowed_op_maps
 };
 
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_parameter_ops.cpp b/src/feature_creation/node/operator_nodes/allowed_parameter_ops.cpp
index 17fea3f1a1cf2be10cdb7ad1a1fb6dd1ff3f7c5c..6d089f0b6acc7a146e570a373d653969578ff4da 100644
--- a/src/feature_creation/node/operator_nodes/allowed_parameter_ops.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_parameter_ops.cpp
@@ -5,22 +5,46 @@ std::map<std::string, bin_param_op_node_gen> allowed_op_maps::binary_param_opera
 
 void allowed_op_maps::set_param_node_maps()
 {
-    allowed_op_maps::binary_param_operator_map["add"] = generateAddParamNode;
-    allowed_op_maps::binary_param_operator_map["sub"] = generateSubParamNode;
-    allowed_op_maps::binary_param_operator_map["abs_diff"] = generateAbsDiffParamNode;
-    allowed_op_maps::binary_param_operator_map["mult"] = generateMultParamNode;
-    allowed_op_maps::binary_param_operator_map["div"] = generateDivParamNode;
+    if(nlopt_wrapper::_param_internal)
+    {
+        allowed_op_maps::binary_param_operator_map["add"] = generateAddParamNode;
+        allowed_op_maps::binary_param_operator_map["sub"] = generateSubParamNode;
+        allowed_op_maps::binary_param_operator_map["abs_diff"] = generateAbsDiffParamNode;
+        allowed_op_maps::binary_param_operator_map["mult"] = generateMultParamNode;
+        allowed_op_maps::binary_param_operator_map["div"] = generateDivParamNode;
 
-    allowed_op_maps::unary_param_operator_map["exp"] = generateExpParamNode;
-    allowed_op_maps::unary_param_operator_map["neg_exp"] = generateNegExpParamNode;
-    allowed_op_maps::unary_param_operator_map["inv"] = generateInvParamNode;
-    allowed_op_maps::unary_param_operator_map["sq"] = generateSqParamNode;
-    allowed_op_maps::unary_param_operator_map["cb"] = generateCbParamNode;
-    allowed_op_maps::unary_param_operator_map["six_pow"] = generateSixPowParamNode;
-    allowed_op_maps::unary_param_operator_map["sqrt"] = generateSqrtParamNode;
-    allowed_op_maps::unary_param_operator_map["cbrt"] = generateCbrtParamNode;
-    allowed_op_maps::unary_param_operator_map["log"] = generateLogParamNode;
-    allowed_op_maps::unary_param_operator_map["abs"] = generateAbsParamNode;
-    allowed_op_maps::unary_param_operator_map["sin"] = generateSinParamNode;
-    allowed_op_maps::unary_param_operator_map["cos"] = generateCosParamNode;
+        allowed_op_maps::unary_param_operator_map["exp"] = generateExpParamNode;
+        allowed_op_maps::unary_param_operator_map["neg_exp"] = generateNegExpParamNode;
+        allowed_op_maps::unary_param_operator_map["inv"] = generateInvParamNode;
+        allowed_op_maps::unary_param_operator_map["sq"] = generateSqParamNode;
+        allowed_op_maps::unary_param_operator_map["cb"] = generateCbParamNode;
+        allowed_op_maps::unary_param_operator_map["six_pow"] = generateSixPowParamNode;
+        allowed_op_maps::unary_param_operator_map["sqrt"] = generateSqrtParamNode;
+        allowed_op_maps::unary_param_operator_map["cbrt"] = generateCbrtParamNode;
+        allowed_op_maps::unary_param_operator_map["log"] = generateLogParamNode;
+        allowed_op_maps::unary_param_operator_map["abs"] = generateAbsParamNode;
+        allowed_op_maps::unary_param_operator_map["sin"] = generateSinParamNode;
+        allowed_op_maps::unary_param_operator_map["cos"] = generateCosParamNode;
+    }
+    else
+    {
+        allowed_op_maps::binary_param_operator_map["add"] = generateAddParamTopLevNode;
+        allowed_op_maps::binary_param_operator_map["sub"] = generateSubParamTopLevNode;
+        allowed_op_maps::binary_param_operator_map["abs_diff"] = generateAbsDiffParamTopLevNode;
+        allowed_op_maps::binary_param_operator_map["mult"] = generateMultParamTopLevNode;
+        allowed_op_maps::binary_param_operator_map["div"] = generateDivParamTopLevNode;
+
+        allowed_op_maps::unary_param_operator_map["exp"] = generateExpParamTopLevNode;
+        allowed_op_maps::unary_param_operator_map["neg_exp"] = generateNegExpParamTopLevNode;
+        allowed_op_maps::unary_param_operator_map["inv"] = generateInvParamTopLevNode;
+        allowed_op_maps::unary_param_operator_map["sq"] = generateSqParamTopLevNode;
+        allowed_op_maps::unary_param_operator_map["cb"] = generateCbParamTopLevNode;
+        allowed_op_maps::unary_param_operator_map["six_pow"] = generateSixPowParamTopLevNode;
+        allowed_op_maps::unary_param_operator_map["sqrt"] = generateSqrtParamTopLevNode;
+        allowed_op_maps::unary_param_operator_map["cbrt"] = generateCbrtParamTopLevNode;
+        allowed_op_maps::unary_param_operator_map["log"] = generateLogParamTopLevNode;
+        allowed_op_maps::unary_param_operator_map["abs"] = generateAbsParamTopLevNode;
+        allowed_op_maps::unary_param_operator_map["sin"] = generateSinParamTopLevNode;
+        allowed_op_maps::unary_param_operator_map["cos"] = generateCosParamTopLevNode;
+    }
 }
diff --git a/src/inputs/InputParser.cpp b/src/inputs/InputParser.cpp
index fe95fd4d9b069f5c70fd20256f424fe599380318..da318dafaee47a706eed098a0dfbfe5f606685ed 100644
--- a/src/inputs/InputParser.cpp
+++ b/src/inputs/InputParser.cpp
@@ -20,7 +20,8 @@ InputParser::InputParser(pt::ptree IP, std::string fn, std::shared_ptr<MPI_Inter
     _n_samp(0),
     _n_residuals(IP.get<int>("n_residual", 1)),
     _n_models_store(IP.get<int>("n_models_store", _n_residuals)),
-    _fix_intercept(IP.get<bool>("fix_intercept", false))
+    _fix_intercept(IP.get<bool>("fix_intercept", false)),
+    _param_internal(IP.get<bool>("param_internal", true))
 {
     std::ifstream data_stream;
     std::string line;
@@ -306,7 +307,7 @@ void InputParser::generate_feature_space(std::shared_ptr<MPI_Interface> comm, st
     }
 
     if(_calc_type.compare("log_regression_fit_c") == 0)
-        nlopt_wrapper::setup_data(_task_sizes_train, _n_dim, _max_rung);
+        nlopt_wrapper::setup_data(_task_sizes_train, _n_dim, _max_rung, _param_internal);
 
     _feat_space = std::make_shared<FeatureSpace>(comm, phi_0, _opset, _param_opset, _prop_train, _task_sizes_train, _calc_type, _max_rung, _n_sis_select, _max_store_rung, _n_rung_generate, _cross_cor_max, _l_bound, _u_bound);
 }
diff --git a/src/inputs/InputParser.hpp b/src/inputs/InputParser.hpp
index e71265accbde0e068f207e0781902b5c43e95a22..b31e44d57975816d73de73e206b833eabff06f41 100644
--- a/src/inputs/InputParser.hpp
+++ b/src/inputs/InputParser.hpp
@@ -69,6 +69,7 @@ public:
     int _n_models_store; //!< Number of models to store
 
     bool _fix_intercept; //!< If true force intercept to be 0.0
+    bool _param_internal; //!< If true parameterize features fully (not just top level)
     /**
      * @brief Constructor
      *
diff --git a/src/nl_opt/NLOptWrapper.cpp b/src/nl_opt/NLOptWrapper.cpp
index 169325483cfd31a947df0f601a50d0744d258232..99fc9a59238001a21170a7dae534a0f028ef4b6a 100644
--- a/src/nl_opt/NLOptWrapper.cpp
+++ b/src/nl_opt/NLOptWrapper.cpp
@@ -11,12 +11,15 @@ std::vector<double> nlopt_wrapper::_work;
 std::vector<double> nlopt_wrapper::_a_copy;
 std::vector<double> nlopt_wrapper::_prop_copy;
 
+bool nlopt_wrapper::_param_internal;
+
 nlopt::algorithm nlopt_wrapper::_local_opt_alg = nlopt::LD_VAR2;
 double nlopt_wrapper::_cauchy_scaling = 0.5 * 0.5;
 int nlopt_wrapper::_n_samp = 0;
 
-void nlopt_wrapper::setup_data(std::vector<int> task_sizes, int max_dim, int n_rung)
+void nlopt_wrapper::setup_data(std::vector<int> task_sizes, int max_dim, int n_rung, bool param_internal)
 {
+    _param_internal = param_internal;
     _task_sizes = task_sizes;
     _zeros.resize(50, 0.0);
     _n_samp = std::accumulate(task_sizes.begin(), task_sizes.end(), 0.0);
@@ -36,24 +39,24 @@ void nlopt_wrapper::setup_data(std::vector<int> task_sizes, int max_dim, int n_r
     }
 }
 
-void nlopt_wrapper::set_objective(std::string calc_type, double* prop, std::vector<int> sizes, int n_rung)
+void nlopt_wrapper::set_objective(std::string calc_type, double* prop, std::vector<int> sizes, int n_rung, bool param_internal)
 {
     if(calc_type.compare("classification") == 0)
     {
         convex_hull::initialize_projection(sizes, prop);
         _objective = objective_class;
         _local_opt_alg = nlopt::LN_SBPLX;
-        setup_data(sizes, 1, 0);
+        setup_data(sizes, 1, 0, param_internal);
     }
     else if(calc_type.compare("regression") == 0)
     {
         _objective = objective_reg;
-        setup_data(sizes, 1, n_rung);
+        setup_data(sizes, 1, n_rung, param_internal);
     }
     else if(calc_type.compare("log_regression") == 0)
     {
         _objective = objective_log_reg;
-        setup_data(sizes, 1, n_rung);
+        setup_data(sizes, 1, n_rung, param_internal);
     }
     else if(calc_type.compare("log_regression_fit_c") == 0)
     {
@@ -70,8 +73,8 @@ double nlopt_wrapper::optimize_feature_params(feat_data data, bool use_simplex)
 {
     double minf = 0.0;
 
-    std::vector<double> params(data._feat->parameters().size() + 2 * _task_sizes.size(), 1.0);
-    std::vector<double> params_final(data._feat->parameters().size(), 1.0);
+    std::vector<double> params((_param_internal ? data._feat->parameters().size() : 2) + 2 * _task_sizes.size(), 1.0);
+    std::vector<double> params_final((_param_internal ? data._feat->parameters().size() : 2), 1.0);
 
     dcopy_(params.size() / 2, _zeros.data(), 1, &params[1], 2);
     dcopy_(params_final.size() / 2, _zeros.data(), 1, &params_final[1], 2);
diff --git a/src/nl_opt/NLOptWrapper.hpp b/src/nl_opt/NLOptWrapper.hpp
index 3fc792e2aed330cc1ee8248b58ba7ed73d8f2887..a5880a7cb772ece88580e9d1460f3baa1451e223 100644
--- a/src/nl_opt/NLOptWrapper.hpp
+++ b/src/nl_opt/NLOptWrapper.hpp
@@ -27,6 +27,8 @@ namespace nlopt_wrapper
     extern int _n_samp; //!< total number of samples
     extern nlopt::algorithm _local_opt_alg; //!< Algorithm used for local optimization
 
+    extern bool _param_internal; //!< parameterize features to all depths of the tree
+
     #pragma omp threadprivate(_log_trans, _work, _a_copy, _residuals, _feature_gradient,_prop_copy)
 
     typedef struct
@@ -250,7 +252,7 @@ namespace nlopt_wrapper
      * @param max_dim Maximum dimension of the features
      * @param n_rung maximum rung of a feature
      */
-    void setup_data(std::vector<int> task_sizes, int max_dim, int n_rung);
+    void setup_data(std::vector<int> task_sizes, int max_dim, int n_rung, bool param_internal=true);
 
     /**
      * @brief Set up the projection operator for the objective function
@@ -260,7 +262,7 @@ namespace nlopt_wrapper
      * @param sizes number of samples per task
      * @param n_rung maximum rung of a feature
      */
-    void set_objective(std::string calc_type, double* prop, std::vector<int> sizes, int n_rung);
+    void set_objective(std::string calc_type, double* prop, std::vector<int> sizes, int n_rung, bool param_internal=true);
 
     #ifdef PY_BINDINGS
         /**
@@ -270,7 +272,7 @@ namespace nlopt_wrapper
          * @param max_dim Maximum dimension of the features
          * @param n_rung maximum rung of a feature
          */
-        inline void setup_data(py::list task_sizes, int max_dim, int n_rung){setup_data(python_conv_utils::from_list<int>(task_sizes), max_dim, n_rung);}
+        inline void setup_data(py::list task_sizes, int max_dim, int n_rung, bool param_internal=true){setup_data(python_conv_utils::from_list<int>(task_sizes), max_dim, n_rung, param_internal);}
 
         /**
          * @brief Set up the projection operator for the objective function
@@ -279,7 +281,7 @@ namespace nlopt_wrapper
          * @param max_dim Maximum dimension of the features
          * @param n_rung maximum rung of a feature
          */
-        inline void setup_data(np::ndarray task_sizes, int max_dim, int n_rung){setup_data(python_conv_utils::from_ndarray<int>(task_sizes), max_dim, n_rung);}
+        inline void setup_data(np::ndarray task_sizes, int max_dim, int n_rung, bool param_internal=true){setup_data(python_conv_utils::from_ndarray<int>(task_sizes), max_dim, n_rung, param_internal);}
 
         /**
          * @brief Set up the projection operator for the objective function
@@ -289,10 +291,10 @@ namespace nlopt_wrapper
          * @param N number of samples per task
          * @param n_rung maximum rung of a feature
          */
-        inline void set_objective(std::string calc_type, py::list prop, py::list sizes, int n_rung)
+        inline void set_objective(std::string calc_type, py::list prop, py::list sizes, int n_rung, bool param_internal=true)
         {
             std::vector<double> prop_vec = python_conv_utils::from_list<double>(prop);
-            return set_objective(calc_type, prop_vec.data(), python_conv_utils::from_list<int>(sizes), n_rung);
+            return set_objective(calc_type, prop_vec.data(), python_conv_utils::from_list<int>(sizes), n_rung, param_internal);
         }
 
         /**
@@ -303,10 +305,10 @@ namespace nlopt_wrapper
          * @param N number of samples per task
          * @param n_rung maximum rung of a feature
          */
-        inline void set_objective(std::string calc_type, np::ndarray prop, py::list sizes, int n_rung)
+        inline void set_objective(std::string calc_type, np::ndarray prop, py::list sizes, int n_rung, bool param_internal=true)
         {
             std::vector<double> prop_vec = python_conv_utils::from_ndarray<double>(prop);
-            return set_objective(calc_type, prop_vec.data(), python_conv_utils::from_list<int>(sizes), n_rung);
+            return set_objective(calc_type, prop_vec.data(), python_conv_utils::from_list<int>(sizes), n_rung, param_internal);
         }
 
         /**
@@ -317,10 +319,10 @@ namespace nlopt_wrapper
          * @param N number of samples per task
          * @param n_rung maximum rung of a feature
          */
-        inline void set_objective(std::string calc_type, np::ndarray prop, np::ndarray sizes, int n_rung)
+        inline void set_objective(std::string calc_type, np::ndarray prop, np::ndarray sizes, int n_rung, bool param_internal=true)
         {
             std::vector<double> prop_vec = python_conv_utils::from_ndarray<double>(prop);
-            return set_objective(calc_type, prop_vec.data(), python_conv_utils::from_ndarray<int>(sizes), n_rung);
+            return set_objective(calc_type, prop_vec.data(), python_conv_utils::from_ndarray<int>(sizes), n_rung, param_internal);
         }
     #endif
 }
diff --git a/src/python/bindings_docstring_keyed.cpp b/src/python/bindings_docstring_keyed.cpp
index 22248de5addbd5c6042ade78c5427bd7184a8b21..0b554fd442530d358acaf134be92932a92d5d25e 100644
--- a/src/python/bindings_docstring_keyed.cpp
+++ b/src/python/bindings_docstring_keyed.cpp
@@ -61,16 +61,16 @@ void sisso::register_all()
     def("initialize_values_arr", &node_value_arrs::initialize_values_arr);
     def("initialize_d_matrix_arr", &node_value_arrs::initialize_d_matrix_arr);
 
-    void (*set_objective_list_list)(std::string, py::list, py::list, int) = &nlopt_wrapper::set_objective;
-    void (*set_objective_arr_list)(std::string, np::ndarray, py::list, int) = &nlopt_wrapper::set_objective;
-    void (*set_objective_arr_arr)(std::string, np::ndarray, np::ndarray, int) = &nlopt_wrapper::set_objective;
+    void (*set_objective_list_list)(std::string, py::list, py::list, int, bool) = &nlopt_wrapper::set_objective;
+    void (*set_objective_arr_list)(std::string, np::ndarray, py::list, int, bool) = &nlopt_wrapper::set_objective;
+    void (*set_objective_arr_arr)(std::string, np::ndarray, np::ndarray, int, bool) = &nlopt_wrapper::set_objective;
 
     def("set_objective", set_objective_list_list);
     def("set_objective", set_objective_arr_list);
     def("set_objective", set_objective_arr_arr);
 
-    void(*setup_data_list)(py::list, int, int) = &nlopt_wrapper::setup_data;
-    void(*setup_data_arr)(np::ndarray, int, int) = &nlopt_wrapper::setup_data;
+    void(*setup_data_list)(py::list, int, int, bool) = &nlopt_wrapper::setup_data;
+    void(*setup_data_arr)(np::ndarray, int, int, bool) = &nlopt_wrapper::setup_data;
     def("setup_data", setup_data_list);
     def("setup_data", setup_data_arr);
 }
@@ -80,8 +80,8 @@ void sisso::feature_creation::registerFeatureSpace()
     void (FeatureSpace::*sis_list)(list) = &FeatureSpace::sis;
     void (FeatureSpace::*sis_ndarray)(np::ndarray) = &FeatureSpace::sis;
 
-    class_<FeatureSpace>("FeatureSpace", init<list, list, list, np::ndarray, list, optional<std::string, int, int, int, int, double, double, double>>())
-        .def(init<list, list, list, list, list, optional<std::string, int, int, int, int, double, double, double>>())
+    class_<FeatureSpace>("FeatureSpace", init<list, list, list, np::ndarray, list, optional<std::string, int, int, int, int, double, double, double, bool>>())
+        .def(init<list, list, list, list, list, optional<std::string, int, int, int, int, double, double, double, bool>>())
         .def(init<std::string, list, list, optional<std::string, int, double>>())
         .def("sis", sis_list, "@DocString_feat_space_sis_list@")
         .def("sis", sis_ndarray, "@DocString_feat_space_sis_arr@")
diff --git a/src/python/feature_creation/FeatureSpace.cpp b/src/python/feature_creation/FeatureSpace.cpp
index 3d107fe33764586bc5ac1af56fc83471f38589f2..5857678e7fb2dbe7137268f6250c926951cd48a2 100644
--- a/src/python/feature_creation/FeatureSpace.cpp
+++ b/src/python/feature_creation/FeatureSpace.cpp
@@ -13,7 +13,8 @@ FeatureSpace::FeatureSpace(
     int n_rung_generate,
     double cross_corr_max,
     double min_abs_feat_val,
-    double max_abs_feat_val
+    double max_abs_feat_val,
+    bool param_internal
 ):
     _phi(python_conv_utils::shared_ptr_vec_from_list<Node, FeatureNode>(phi_0)),
     _phi_0(_phi),
@@ -34,7 +35,8 @@ FeatureSpace::FeatureSpace(
     _n_feat(py::len(phi_0)),
     _n_rung_store(max_store_rung),
     _n_rung_generate(n_rung_generate),
-    _n_samp(_phi[0]->n_samp())
+    _n_samp(_phi[0]->n_samp()),
+    _param_internal(param_internal)
 {
     initialize_fs(project_type);
 }
@@ -52,7 +54,8 @@ FeatureSpace::FeatureSpace(
     int n_rung_generate,
     double cross_corr_max,
     double min_abs_feat_val,
-    double max_abs_feat_val
+    double max_abs_feat_val,
+    bool param_internal
 ):
     _phi(python_conv_utils::shared_ptr_vec_from_list<Node, FeatureNode>(phi_0)),
     _phi_0(_phi),
@@ -73,7 +76,8 @@ FeatureSpace::FeatureSpace(
     _n_feat(py::len(phi_0)),
     _n_rung_store(max_store_rung),
     _n_rung_generate(n_rung_generate),
-    _n_samp(_phi[0]->n_samp())
+    _n_samp(_phi[0]->n_samp()),
+    _param_internal(param_internal)
 {
     initialize_fs(project_type);
 }
@@ -99,7 +103,8 @@ FeatureSpace::FeatureSpace(
     _n_feat(py::len(phi_0)),
     _n_rung_store(0),
     _n_rung_generate(0),
-    _n_samp(_phi_0[0]->n_samp())
+    _n_samp(_phi_0[0]->n_samp()),
+    _param_internal(true)
 {
     std::cout << "project: " << _phi_0.size() << std::endl;
     if(project_type.compare("regression") == 0)