diff --git a/src/feature_creation/feature_space/FeatureSpace.cpp b/src/feature_creation/feature_space/FeatureSpace.cpp
index 98d1b362ad6be13ee1266922edd645a558d846e8..66dee6c8602e8344573ffb225e7b9a5a1ac97b4f 100644
--- a/src/feature_creation/feature_space/FeatureSpace.cpp
+++ b/src/feature_creation/feature_space/FeatureSpace.cpp
@@ -812,6 +812,31 @@ void FeatureSpace::project_generated(const double* prop, const int size, std::ve
 
 void FeatureSpace::sis(const std::vector<double>& prop)
 {
+    // Reparameterize for the residuals
+#ifdef PARAMETERIZE
+    if(_phi_selected.size() > 0)
+    {
+        // Make a hard copy of the previously selected features
+        for(int ff = _phi_selected.size() - _n_sis_select; ff < _phi_selected.size(); ++ff)
+        {
+            _phi_selected[ff] = _phi_selected[ff]->hard_copy();
+        }
+
+        // Reparameterize based on residuals
+        #pragma omp parallel
+        {
+            std::shared_ptr<NLOptimizer> optimizer = nlopt_wrapper::get_optimizer(_project_type, _task_sizes, prop, _max_phi, _max_param_depth);
+            #pragma omp for schedule(dynamic)
+            for(int ff = _start_gen[1]; ff < _phi.size(); ++ff)
+            {
+                if(_phi[ff]->n_params() > 0)
+                {
+                    _phi[ff]->get_parameters(optimizer);
+                }
+            }
+        }
+    }
+#endif
     // Create output directories if needed
     boost::filesystem::path p(_feature_space_file.c_str());
     boost::filesystem::create_directories(p.remove_filename());
diff --git a/src/feature_creation/node/FeatureNode.hpp b/src/feature_creation/node/FeatureNode.hpp
index 85d06b1640eec24e5f0a4ca4dc4f865e2a61ff2b..aa0c9d76cb7a6b216c1292efacedb9524ef1287e 100644
--- a/src/feature_creation/node/FeatureNode.hpp
+++ b/src/feature_creation/node/FeatureNode.hpp
@@ -134,6 +134,12 @@ public:
      */
     ~FeatureNode();
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual inline node_ptr hard_copy()const {return std::make_shared<FeatureNode>(*this);}
+
     /**
      * @brief Get the list of feature expressions
      * @return vector storing the expressions for all primary features that show up in feature in the order they appear in the postfix notation
@@ -366,6 +372,15 @@ public:
      */
     inline void set_parameters(const double* params){};
 
+    //DocString: feat_node_get_params
+    /**
+     * @brief Solve the non-linear optimization to set the parameters
+     * @details Fits the data points from _feats->value_ptr and prop to get the parameters for the feature
+     *
+     * @param optimizer The optimizer used to get the paremeters
+     */
+    void get_parameters(std::shared_ptr<NLOptimizer> optimizer){};
+
     /**
      * @brief returns the number of parameters for this feature
      *
diff --git a/src/feature_creation/node/ModelNode.hpp b/src/feature_creation/node/ModelNode.hpp
index 0c19dbe13815e4f8c34043691046740f5a7dd59a..4f6cbbbcdc5c63ce4508b35329fe31ee2fed7cfe 100644
--- a/src/feature_creation/node/ModelNode.hpp
+++ b/src/feature_creation/node/ModelNode.hpp
@@ -134,6 +134,12 @@ public:
      */
     ~ModelNode();
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    inline node_ptr hard_copy()const {return std::make_shared<ModelNode>(*this);}
+
     /**
      * @brief Generate the list of functions used to evaluate the value of this feature for a new data point from the postfix expression
      */
diff --git a/src/feature_creation/node/Node.hpp b/src/feature_creation/node/Node.hpp
index cbcd40dd4eecf874a322819fb9bafd2e121a7bb1..2ed4be8bff8a68839b265e6db93a0e0af3e53c7c 100644
--- a/src/feature_creation/node/Node.hpp
+++ b/src/feature_creation/node/Node.hpp
@@ -30,6 +30,9 @@ namespace py = boost::python;
 namespace np = boost::python::numpy;
 #endif
 
+// Forward Declaration of NLOptimizer
+class NLOptimizer;
+
 // DocString: cls_node
 /**
  * @brief Base class for a Node
@@ -113,6 +116,12 @@ public:
      */
     virtual ~Node();
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual std::shared_ptr<Node> hard_copy()const = 0;
+
     /**
      * @brief Get the list of feature expressions
      * @return vector storing the expressions for all primary features that show up in feature in the order they appear in the postfix notation
@@ -379,6 +388,15 @@ public:
      */
     virtual void set_parameters(const double* params) = 0;
 
+    //DocString: node_get_params
+    /**
+     * @brief Solve the non-linear optimization to set the parameters
+     * @details Fits the data points from _feats->value_ptr and prop to get the parameters for the feature
+     *
+     * @param optimizer The optimizer used to get the paremeters
+     */
+    virtual void get_parameters(std::shared_ptr<NLOptimizer> optimizer) = 0;
+
     /**
      * @brief returns the number of parameters for this feature
      *
diff --git a/src/feature_creation/node/operator_nodes/OperatorNode.hpp b/src/feature_creation/node/operator_nodes/OperatorNode.hpp
index 38e23fc22ef2f40eab9c61414ba510eb541d360d..db98514907c265f7c14d5c6b7a62573061b02cda 100644
--- a/src/feature_creation/node/operator_nodes/OperatorNode.hpp
+++ b/src/feature_creation/node/operator_nodes/OperatorNode.hpp
@@ -112,6 +112,12 @@ public:
     ~OperatorNode()
     {}
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const = 0;
+
     /**
      * @brief Get the list of feature expressions
      * @return vector storing the expressions for all primary features that show up in feature in the order they appear in the postfix notation
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/absolute_value.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/absolute_value.cpp
index a152c40e4cc94fc101fbec0bd7f6d7535b9ca7f2..48cc89925bd3d7e0ba2def533b9aa32fad505019 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/absolute_value.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/absolute_value.cpp
@@ -87,6 +87,14 @@ AbsNode::AbsNode(const node_ptr feat, const unsigned long int feat_ind, const do
     }
 }
 
+node_ptr AbsNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<AbsNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void AbsNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/absolute_value.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/absolute_value.hpp
index da033d878020647b7027f7f30cb26e0687cfd84c..f37662c94531af35442392ad45b91dd07bae3a23 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/absolute_value.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs/absolute_value.hpp
@@ -58,6 +58,12 @@ public:
      */
     AbsNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: abs_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 dd374d966b5305d2600c5e568c723455ddf4665c..2c166a95a0906c9e3881d6166de98f8fad62b389 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
@@ -72,6 +72,15 @@ AbsParamNode::AbsParamNode(const node_ptr feat, const unsigned long int feat_ind
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr AbsParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<AbsParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void AbsParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     // Change the sign of alpha as a control on linear dependency without forcing one sign or another
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 6cbe19331c2c3b4d63a9926968781c24c20e0dd3..3be3d22fc857b56832c9de730c9c95ece149e98e 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
@@ -90,6 +90,12 @@ public:
      */
     AbsParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: abs_param_node_set_value
     /**
      * @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_diff/absolute_difference.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/absolute_difference.cpp
index 4afc56de0fff5669e6f5faea6b73177050acecd5..b92ed4902a51786505d9b8d525fddadcaf2a8147 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/absolute_difference.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/absolute_difference.cpp
@@ -124,6 +124,14 @@ AbsDiffNode::AbsDiffNode(const node_ptr feat_1, const node_ptr feat_2, const uns
     }
 }
 
+node_ptr AbsDiffNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<AbsDiffNode>(_feats[0]->hard_copy(), _feats[1]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void AbsDiffNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/absolute_difference.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/absolute_difference.hpp
index 5cdf23e0ad9e033bc9f20f76b1101669931aaf7a..6e17c5ad02b8a488c5e5d28734d646072d89ce84 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/absolute_difference.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/abs_diff/absolute_difference.hpp
@@ -63,6 +63,13 @@ public:
      */
     AbsDiffNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
+
     // DocString: abs_diff_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 f16c83ea592765de85b0c106d6ff39d2e9483343..970bdddb3b3cf2bf37f0fde7af308641c6b72bb2 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
@@ -116,6 +116,15 @@ AbsDiffParamNode::AbsDiffParamNode(const node_ptr feat_1, const node_ptr feat_2,
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr AbsDiffParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<AbsDiffParamNode>(_feats[0]->hard_copy(), _feats[1]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void AbsDiffParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 4d1becc6a7fb9ad7aab3c6f9bee14cd3d86a0826..a1830dcbb9826609b6533d548b23024ae72dff54 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
@@ -92,6 +92,12 @@ public:
      */
     AbsDiffParamNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: abs_diff_param_node_set_value
     /**
      * @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/add/add.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/add.cpp
index f6fd65cecc41d270f7e4158528f74581e6248039..6d832484697bcab4f8c12caef124bfca0d63c5f2 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/add.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/add.cpp
@@ -118,6 +118,14 @@ AddNode::AddNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned lo
     }
 }
 
+node_ptr AddNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<AddNode>(_feats[0]->hard_copy(), _feats[1]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void AddNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     _feats[0]->update_add_sub_leaves(add_sub_leaves, pl_mn, expected_abs_tot);
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/add.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/add.hpp
index e13dc19dc38c2a1ffa34c11aab7ff4f7a1bffdb4..a532154dc56c51ca3d122e787a790ef9e513b1c5 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/add.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add/add.hpp
@@ -60,6 +60,12 @@ public:
      */
     AddNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: add_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 ff048f83e0ec3959f71e80aaaa8ed7b792828229..f33046b9ebf3b591b8d3f78ae06c0cb814823e05 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
@@ -79,6 +79,15 @@ AddParamNode::AddParamNode(const node_ptr feat_1, const node_ptr feat_2, const u
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr AddParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<AddParamNode>(_feats[0]->hard_copy(), _feats[1]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void AddParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 46125a7ce116140a3f41f034de6574a36aa8641d..6071fedb8c517e02c88a14970e2759730e808ff1 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
@@ -93,6 +93,12 @@ public:
      */
     AddParamNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: add_param_node_set_value
     /**
      * @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/cb/cube.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/cube.cpp
index bc5b5ffe19a933d30d642b7aca05f90c17a3186d..394c6e0c7bea2fb3a9b4cafdc32af346098cc6cc 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/cube.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/cube.cpp
@@ -82,6 +82,14 @@ CbNode::CbNode(const node_ptr feat, const unsigned long int feat_ind, const doub
 
 }
 
+node_ptr CbNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<CbNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void CbNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/cube.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/cube.hpp
index 59d1ca5893c340c1654f30efd9b86a54a745aa6d..8412c6c247b29e4536ed47cb732fbab42c3a429e 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/cube.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cb/cube.hpp
@@ -58,6 +58,12 @@ public:
      */
     CbNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: cb_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 7405f7a4a6ae17c234ef280c5871a05efea6a1ac..2aeb18d079e54793f6156ec5b69d39f2444b5969 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
@@ -122,6 +122,15 @@ void CbParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
     }
 }
 
+node_ptr CbParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<CbParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void CbNode::set_value(const double* params, int offset, const bool for_comp, const int depth) const
 {
     bool is_root = (offset == -1);
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 245ac8fc1203b816aed7d769d1440102f9c78418..c7470e673d8a684b69dc7c37e8077327e1feb8e3 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
@@ -90,6 +90,12 @@ public:
      */
     CbParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: cb_param_node_set_value
     /**
      * @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/cbrt/cube_root.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/cube_root.cpp
index f2f8bf96e05e62b16671b9634d080a26d52571e1..420dc6c8fcd05998ff2cc657d5680abcf9d4fcdb 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/cube_root.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/cube_root.cpp
@@ -87,6 +87,14 @@ CbrtNode::CbrtNode(const node_ptr feat, const unsigned long int feat_ind, const
     }
 }
 
+node_ptr CbrtNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<CbrtNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void CbrtNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/cube_root.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/cube_root.hpp
index fdbb58111ab884147e98b7e31b4c399abcdd8672..94abff84eb9b34c15bc6859fe5f3f4efe0bc4fcf 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/cube_root.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cbrt/cube_root.hpp
@@ -58,6 +58,12 @@ public:
      */
     CbrtNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: cbrt_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 8004b651d940ca801cc4a67c1d3163506b693a64..e4762873228db8002c252ed934f5434efde298d0 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
@@ -100,6 +100,15 @@ CbrtParamNode::CbrtParamNode(const node_ptr feat, const unsigned long int feat_i
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr CbrtParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<CbrtParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void CbrtParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 9b1ef4e75bc259ec857ea48ff2084420b8f6b10c..f2c47e1d69c6cbf19dbeb931015334e1f7166f03 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
@@ -89,6 +89,12 @@ public:
      */
     CbrtParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: cbrt_param_node_set_value
     /**
      * @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/cos/cos.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/cos.cpp
index d68a5ed5ca935cd236f76f84ba809935a51fba64..a7a9d70e8b1ec81c3bbfe5d8f66ca7db60a6622e 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/cos.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos/cos.cpp
@@ -72,6 +72,14 @@ CosNode::CosNode(const node_ptr feat, const unsigned long int feat_ind, const do
     }
 }
 
+node_ptr CosNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<CosNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void CosNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
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 981707b5e3b43d1d5b9248a433f61e40f7894ab3..a159789b2dbd4c33bb933da3d9a4383b095470eb 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
@@ -58,6 +58,12 @@ public:
      */
     CosNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: cos_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 1e021e0e277bfaaae4b8210759394bb7f762d4bb..57b4d8ae1c1d6c62c5332fe956521cf16a7229f3 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
@@ -99,6 +99,15 @@ CosParamNode::CosParamNode(const node_ptr feat, const unsigned long int feat_ind
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr CosParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<CosParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void CosParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 c1faab75b2f0c6be5aea6f994c34120760cf75a9..1b4375772e8be2b5b26c8fc931e87e665e0769bd 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
@@ -90,6 +90,12 @@ public:
      */
     CosParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: cos_param_node_set_value
     /**
      * @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/div/divide.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/divide.cpp
index 75b9e0c332d4e7a9227d850d4b3506c4f1282cd2..5fd36ead02300c6683fb7b3e8732435294a846c5 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/divide.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/divide.cpp
@@ -128,6 +128,14 @@ DivNode::DivNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned lo
 
 }
 
+node_ptr DivNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<DivNode>(_feats[0]->hard_copy(), _feats[1]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void DivNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/divide.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/divide.hpp
index 3451ef8c76c13e59affb05f6e64f2c11dfee261c..ca40eb123a6ff5bbd759a9e9680900ae27bd3c54 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/divide.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/div/divide.hpp
@@ -60,6 +60,12 @@ public:
      */
     DivNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: div_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 5cbf5402e41e3e6bdbca03292dc782cd21c54582..2d6d45feda000b7ef42133f094441bf40e87e744 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
@@ -106,6 +106,15 @@ DivParamNode::DivParamNode(const node_ptr feat_1, const node_ptr feat_2, const u
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr DivParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<DivParamNode>(_feats[0]->hard_copy(), _feats[1]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void DivParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 66d8f8f74a19cd91d60b4f23ec59648a06ffe09e..b958eef938633a6b5773de2ca9cb80964ae86fe5 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
@@ -93,6 +93,12 @@ public:
      */
     DivParamNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: div_param_node_set_value
     /**
      * @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/exp/exponential.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/exponential.cpp
index 4eb2a0a233faa8fecf49ab2af8280de462fbce21..7a071ebc526f6883e51170ee21d67f80439b710e 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/exponential.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/exponential.cpp
@@ -84,6 +84,14 @@ ExpNode::ExpNode(const node_ptr feat, const unsigned long int feat_ind, const do
     set_test_value();
 }
 
+node_ptr ExpNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<ExpNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void ExpNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/exponential.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/exponential.hpp
index 8e24fa3debe07dcd4a2db8deda87005402b1bc78..e71f990674498be02086b1d1b71a3c97be0ec880 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/exponential.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exp/exponential.hpp
@@ -58,6 +58,12 @@ public:
      */
     ExpNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: exp_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 406f9a1f4caab1842c5e22bb4e9ae979c47c1fe3..bda774478d705a775ba7f12353f6f774dc451fe4 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
@@ -111,6 +111,15 @@ ExpParamNode::ExpParamNode(const node_ptr feat, const unsigned long int feat_ind
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr ExpParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<ExpParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void ExpParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 985fed8828d2ab60349c4f345d96bbac6ccd4073..43c2845afe333dba766e019a9b269360a71b05c4 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
@@ -90,6 +90,12 @@ public:
      */
     ExpParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: exp_param_node_set_value
     /**
      * @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/inv/inverse.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/inverse.cpp
index 3e2d06aca301b8e8f13c6e8f61e82cd956bc3386..7d52017f8de46c529f54b41282fc8d6ab2bb9fab 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/inverse.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/inverse.cpp
@@ -77,6 +77,14 @@ InvNode::InvNode(const node_ptr feat, const unsigned long int feat_ind, const do
 
 }
 
+node_ptr InvNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<InvNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void InvNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/inverse.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/inverse.hpp
index 16de6ce793eda91fd8dcfd06881c8828a7fe4f7a..12d95a9af435ec0f1e6709cf2832fb4ba36ab3a6 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/inverse.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inv/inverse.hpp
@@ -54,6 +54,12 @@ public:
      */
     InvNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: inv_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 fc14efc3e708889f38e162adba61fb8eccb11175..9126df9a68256b76cc1fd02ebe38be0d4e0dfd08 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
@@ -107,6 +107,15 @@ InvParamNode::InvParamNode(const node_ptr feat, const unsigned long int feat_ind
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr InvParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<InvParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void InvParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 3b46926af8043852fd8b299fe9de5f7dea24f454..c43f018772a27c89e378055c9f7d391e66efb353 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
@@ -90,6 +90,12 @@ public:
      */
     InvParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: inv_param_node_set_value
     /**
      * @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/log/log.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/log.cpp
index 3ae3373285f4269cab041c0963ccb2bd1fd9b80c..f11e1c7e2e18d854a4a6990e33e48dc2d5c6401d 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/log.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/log.cpp
@@ -109,6 +109,14 @@ LogNode::LogNode(const node_ptr feat, const unsigned long int feat_ind, const do
     set_test_value();
 }
 
+node_ptr LogNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<LogNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void LogNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/log.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/log.hpp
index 5596bcff8763b06be1dd54f5e06c4ba99d43264b..503e524a4bcfa90b7651d94e751f22d808de6384 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/log.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log/log.hpp
@@ -58,6 +58,12 @@ public:
      */
     LogNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: log_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 55f10032679704be4fb1ef438f439c31045d0368..eed292ffb7fb0ddbbe18d3d2a2a026e07a85499e 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
@@ -135,6 +135,15 @@ LogParamNode::LogParamNode(const node_ptr feat, const unsigned long int feat_ind
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr LogParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<LogParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void LogParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 202dda03fee939f1d7bb6e1fedf8e6e4abfc5b28..1d139f899379171b22958474c430aa66b498ad41 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
@@ -90,6 +90,12 @@ public:
      */
     LogParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: log_param_node_set_value
     /**
      * @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/mult/multiply.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/multiply.cpp
index 7f4744d2894cfed6f1a744ee4a13ce6f81d3d9b2..a3433c364ddc242e52e20db0549691a4a4dc2c81 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/multiply.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/multiply.cpp
@@ -127,6 +127,14 @@ MultNode::MultNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned
     }
 }
 
+node_ptr MultNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<MultNode>(_feats[0]->hard_copy(), _feats[1]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void MultNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/multiply.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/multiply.hpp
index d6724144ce25b1c6d01cdacbc53488c169779809..6d146221f15e94c6ed663c0ed7cff68b1627f86d 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/multiply.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/mult/multiply.hpp
@@ -61,6 +61,12 @@ public:
      */
     MultNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: mult_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 b54761adf3e7c2264fb093587e9b20fa6a515b00..a3c838180c2433a82e56519fb3335766339e94dd 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
@@ -78,6 +78,15 @@ MultParamNode::MultParamNode(const node_ptr feat_1, const node_ptr feat_2, const
     get_parameters(optimizer);
 }
 
+node_ptr MultParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<MultParamNode>(_feats[0]->hard_copy(), _feats[1]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void MultParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 fb339e3faf4a8a2b2176c0b1699c658da6469877..0ab306c0259af265c7380fad31790336a18fbf2b 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
@@ -91,6 +91,12 @@ public:
      */
     MultParamNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: mult_param_node_set_value
     /**
      * @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/neg_exp/negative_exponential.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/negative_exponential.cpp
index 2c03958ffda875568156c16c049f22497ffe14b6..d704e9cacdcd4363b00c2593af262f184ce0abca 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/negative_exponential.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/negative_exponential.cpp
@@ -83,6 +83,14 @@ NegExpNode::NegExpNode(const node_ptr feat, const unsigned long int feat_ind, co
     }
 }
 
+node_ptr NegExpNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<NegExpNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void NegExpNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/negative_exponential.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/negative_exponential.hpp
index 87da93e768af7b523b56a0b1997ebb9b0b7a12fa..850ae2c66294b1ef4d2e84c1eeff052f36a27b7d 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/negative_exponential.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/neg_exp/negative_exponential.hpp
@@ -59,6 +59,12 @@ public:
      */
     NegExpNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: neg_exp_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 7fd8a2daee7963c94253dddef10c282c65a01473..039b3e90ab6ba7bcab30819918f28db4d2691937 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
@@ -111,6 +111,15 @@ NegExpParamNode::NegExpParamNode(const node_ptr feat, const unsigned long int fe
     _params.resize(n_params(),  0.0);
 }
 
+node_ptr NegExpParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<NegExpParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void NegExpParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 9d0ad8b32153ed5e532c85d66ee16a5a079343cf..5e40984db84dfd31b3a7a2c0c7bb341e0105f167 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
@@ -90,6 +90,12 @@ public:
      */
     NegExpParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: neg_exp_param_node_set_value
     /**
      * @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/sin/parameterized_sin.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/parameterized_sin.cpp
index 20da40a77a16d3f02edce3d764d82a78dd0ec690..0d480eaf2fdda30d59b8b32eec4764895cf0b3f2 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
@@ -99,6 +99,15 @@ SinParamNode::SinParamNode(const node_ptr feat, const unsigned long int feat_ind
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr SinParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<SinParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void SinParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 cb713756d0750641fef68ba4d8e8247c8e79ef3a..a57e8b0566099a0a3e940d3307abdf1a3b9c33ae 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
@@ -90,6 +90,12 @@ public:
      */
     SinParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: sin_param_node_set_value
     /**
      * @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/sin/sin.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/sin.cpp
index 2e6064c93c21a71a6ba4347e1c5a926df873e71d..8d99ebc5076024b7d5c1d6dedaa819757acf2782 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/sin.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/sin.cpp
@@ -61,6 +61,14 @@ SinNode::SinNode(const node_ptr feat, const unsigned long int feat_ind, const do
     }
 }
 
+node_ptr SinNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<SinNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void SinNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/sin.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/sin.hpp
index 9ce624bdbbaa4d00b0c9b5aec88f9b2e8038045d..0e641d281dd72ebf791af55f1583e5b9b8ba589b 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/sin.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin/sin.hpp
@@ -59,6 +59,12 @@ public:
      */
     SinNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: sin_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 7a47dd573e16ed74629ada7e05e93504fd42e263..54fa1ce3442356862f83fd57a8fb08a36d7fb683 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
@@ -114,6 +114,15 @@ SixPowParamNode::SixPowParamNode(const node_ptr feat, const unsigned long int fe
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr SixPowParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<SixPowParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void SixPowParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 262e17aee05beffcacc632d6cd52365b17e1be47..0798beada5a80b797e7d9a17a7380343770e5019 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
@@ -90,6 +90,12 @@ public:
      */
     SixPowParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: six_pow_param_node_set_value
     /**
      * @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/six_pow/sixth_power.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/sixth_power.cpp
index 2ebf1eacff26c33668c6a4cb4845b6fbb34b4482..b6f0999ec628e0873704039b467c94c9ec36c7cc 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/sixth_power.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/sixth_power.cpp
@@ -90,6 +90,14 @@ SixPowNode::SixPowNode(const node_ptr feat, const unsigned long int feat_ind, co
     }
 }
 
+node_ptr SixPowNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<SixPowNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void SixPowNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/sixth_power.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/sixth_power.hpp
index 1f55baf12c87cf3cf3614c1a60f842e206247771..1dbf6138daa5899a7098e5bc045e2faf8df1b425 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/sixth_power.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/six_pow/sixth_power.hpp
@@ -59,6 +59,12 @@ public:
      */
     SixPowNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: six_pow_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 3458c2dabeec8e7799b62a1317c1a6f3390506ee..a967cd9864d57ec34fca5b723447d0ee9940d57b 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
@@ -105,6 +105,15 @@ SqParamNode::SqParamNode(const node_ptr feat, const unsigned long int feat_ind,
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr SqParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<SqParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void SqParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 0f6cf20e3ade80b0192ab9aba0d7475d8a8e910d..282d5027414c2aea290ab66b8d3d0ba8b21f7754 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
@@ -90,6 +90,12 @@ public:
      */
     SqParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: sq_param_node_set_value
     /**
      * @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/sq/square.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/square.cpp
index 7cf62256dcb1d132ca19d4900a64f1e78b374e5b..a4f8a0453db9fe4a1490f129863af6a9c712e762 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/square.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/square.cpp
@@ -80,6 +80,14 @@ SqNode::SqNode(const node_ptr feat, const unsigned long int feat_ind, const doub
 
 }
 
+node_ptr SqNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<SqNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void SqNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/square.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/square.hpp
index e9ddf6bcac9e23023ecb2f9fb55eeb6dde3625fb..ffffc816bb0c7490cc19210e91565c107c6a6690 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/square.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sq/square.hpp
@@ -58,6 +58,12 @@ public:
      */
     SqNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: sq_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 7d1d548f37acaf79c72b9ee4f1ad7907198703dc..3b2098c71385714660644a2c7f42d32cee98fdf4 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
@@ -120,6 +120,15 @@ SqrtParamNode::SqrtParamNode(const node_ptr feat, const unsigned long int feat_i
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr SqrtParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<SqrtParamNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void SqrtParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     // Change the sign of alpha as a control on linear dependency without forcing one sign or another
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 f67b7fd823e66b1e7f67f73c4c2a37de3764e097..3b44b479633b7e696ba6f8bd06731b68b1e49069 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
@@ -92,6 +92,12 @@ public:
      */
     SqrtParamNode(const node_ptr feat, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: sqrt_param_node_set_value
     /**
      * @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/sqrt/square_root.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/square_root.cpp
index 04ecd4b241b7bf8da505dd1e7b74d508db278801..ddfbc9ee6eb42a8654d84dceea5ce19e84de8e21 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/square_root.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/square_root.cpp
@@ -89,6 +89,14 @@ SqrtNode::SqrtNode(const node_ptr feat, const unsigned long int feat_ind, const
 
 }
 
+node_ptr SqrtNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<SqrtNode>(_feats[0]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void SqrtNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     std::string key = expr();
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/square_root.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/square_root.hpp
index 3206b869216a3112f51df4a2a705d37157ee3dae..c061e5e6c70b66029bf756e6585036c2c382a967 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/square_root.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sqrt/square_root.hpp
@@ -59,6 +59,12 @@ public:
      */
     SqrtNode(const node_ptr feat, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: sqrt_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
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 af894157c879844da4bcebd81964ec741acd3102..acdc1f4dcb646242c3e135b24fb72e6846305636 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
@@ -79,6 +79,15 @@ SubParamNode::SubParamNode(const node_ptr feat_1, const node_ptr feat_2, const u
     _params.resize(n_params(), 0.0);
 }
 
+node_ptr SubParamNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<SubParamNode>(_feats[0]->hard_copy(), _feats[1]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    cp->set_parameters(_params.data());
+    return cp;
+}
+
 void SubParamNode::get_parameters(std::shared_ptr<NLOptimizer> optimizer)
 {
     double min_res = optimizer->optimize_feature_params(this);
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 f18c582156db4868264ea30fa92906b7df15e2ae..d3a8e481f368560eed0b0ca7f1e2e551f3a8f21f 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
@@ -93,6 +93,12 @@ public:
      */
     SubParamNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned long int feat_ind, double const l_bound=1e-50, const double u_bound=1e50);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    node_ptr hard_copy()const;
+
     // DocString: sub_param_node_set_value
     /**
      * @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/sub/subtract.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/subtract.cpp
index 8ee3d232c97a907112f42f16e2fec074028a475d..4fe5575343b1062402eea4a59623989eebc13b97 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/subtract.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/subtract.cpp
@@ -118,6 +118,14 @@ SubNode::SubNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned lo
     }
 }
 
+node_ptr SubNode::hard_copy()const
+{
+    node_ptr cp = std::make_shared<SubNode>(_feats[0]->hard_copy(), _feats[1]->hard_copy(), _feat_ind);
+    cp->set_selected(_selected);
+    cp->set_d_mat_ind(_d_mat_ind);
+    return cp;
+}
+
 void SubNode::update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const
 {
     _feats[0]->update_add_sub_leaves(add_sub_leaves, pl_mn, expected_abs_tot);
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/subtract.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/subtract.hpp
index 6bcf0a90e1c4c95a7c610c25221bff1cccee4ee9..308d1be2dac55f5996e2e003ffa1841746df65d9 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/subtract.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sub/subtract.hpp
@@ -62,6 +62,12 @@ public:
      */
     SubNode(const node_ptr feat_1, const node_ptr feat_2, const unsigned long int feat_ind, const double l_bound, const double u_bound);
 
+    /**
+     * @brief Makes a hard copy node (all items in _feats are a new shared_ptr)
+     * @return A shared_ptr of a copy of this node with all members hard copied
+     */
+    virtual node_ptr hard_copy()const;
+
     // DocString: sub_node_unit
     /**
      * @brief Get the unit of the feature (combine the units of _feats)
diff --git a/src/python/bindings_docstring_keyed.hpp b/src/python/bindings_docstring_keyed.hpp
index 9c6f4f7cc737a27fd36c5670e9d638d0934c9d9a..304ffd95d43e4dd55597ef32c898a016b36e91ea 100644
--- a/src/python/bindings_docstring_keyed.hpp
+++ b/src/python/bindings_docstring_keyed.hpp
@@ -59,6 +59,7 @@ namespace sisso
             struct NodeWrap :  Node, py::wrapper<Node>
             {
             public:
+                inline node_ptr hard_copy() const {return this->get_override("hard_copy")();}
                 inline std::string expr() const {return this->get_override("expr")();}
                 inline std::string expr(double*, int depth=1) const {return this->get_override("expr")();}
                 inline std::string get_latex_expr() const {return this->get_override("latex_expr")();}
@@ -87,6 +88,7 @@ namespace sisso
                 inline std::string get_postfix_term() const {return this->get_override("get_postfix_term")();}
                 inline void update_add_sub_leaves(std::map<std::string, int>& add_sub_leaves, const int pl_mn, int& expected_abs_tot) const {this->get_override("update_add_sub_leaves")();}
                 inline void update_div_mult_leaves(std::map<std::string, double>& div_mult_leaves, const double fact, double& expected_abs_tot) const {this->get_override("update_div_mult_leaves")();}
+                inline void get_parameters(std::shared_ptr<NLOptimizer> optimizer){this->get_override("get_parameters")();}
                 inline std::vector<double> parameters() const {return this->get_override("parameters")();}
                 inline void set_parameters(std::vector<double>, bool check_sz=true){this->get_override("set_parameters")();}
                 inline void set_parameters(const double*){this->get_override("set_parameters")();}
@@ -107,6 +109,7 @@ namespace sisso
             template<int N>
             struct OperatorNodeWrap : OperatorNode<N>, py::wrapper<OperatorNode<N>>
             {
+                inline node_ptr hard_copy() const {return this->get_override("hard_copy")();}
                 inline void set_value(int offset=-1, const bool for_comp=false) const {this->get_override("set_value")();}
                 inline void set_test_value(int offset=-1, const bool for_comp=false) const {this->get_override("set_test_value")();}
                 inline void set_value(const double* params, int offset=-1, bool for_comp=false, int depth=1) const {this->get_override("set_value")();}
@@ -138,6 +141,7 @@ namespace sisso
             struct NodeWrap :  Node, py::wrapper<Node>
             {
             public:
+                inline node_ptr hard_copy() const {return this->get_override("hard_copy")();}
                 inline std::string expr() const
                 {
                     return this->get_override("expr")();
@@ -246,6 +250,7 @@ namespace sisso
             template<int N>
             struct OperatorNodeWrap : OperatorNode<N>, py::wrapper<OperatorNode<N>>
             {
+                inline node_ptr hard_copy() const {return this->get_override("hard_copy")();}
                 inline void set_value(int offset=-1, const bool for_comp=false) const
                 {
                     this->get_override("set_value")();