From 196ff8a11172d1a9e97f68e842da35d3f6cfd590 Mon Sep 17 00:00:00 2001
From: Thomas Purcell <purcell@fhi-berlin.mpg.de>
Date: Tue, 2 Jun 2020 10:44:40 +0200
Subject: [PATCH] Node Refactor

Removed _value_ptr and _feat_value_ptrs from OperatorNode
Allow set_value() and get_value_ptr() to accept offest and work directly on offset
value_ptr only thing to call set_value
---
 src/feature_creation/node/FeatureNode.hpp     | 27 ++-----
 src/feature_creation/node/Node.hpp            | 27 ++-----
 .../node/operator_nodes/OperatorNode.cpp      | 23 ++++--
 .../node/operator_nodes/OperatorNode.hpp      | 46 ++++--------
 .../absolute_difference.cpp                   | 13 ----
 .../absolute_difference.hpp                   | 11 ++-
 .../allowed_operator_nodes/absolute_value.cpp |  8 ---
 .../allowed_operator_nodes/absolute_value.hpp | 11 ++-
 .../allowed_operator_nodes/add.cpp            | 13 ----
 .../allowed_operator_nodes/add.hpp            | 11 ++-
 .../allowed_operator_nodes/cos.cpp            |  8 ---
 .../allowed_operator_nodes/cos.hpp            | 11 ++-
 .../allowed_operator_nodes/cube.cpp           |  8 ---
 .../allowed_operator_nodes/cube.hpp           | 11 ++-
 .../allowed_operator_nodes/cube_root.cpp      |  8 ---
 .../allowed_operator_nodes/cube_root.hpp      | 11 ++-
 .../allowed_operator_nodes/divide.cpp         | 13 ----
 .../allowed_operator_nodes/divide.hpp         | 11 ++-
 .../allowed_operator_nodes/exponential.cpp    |  8 ---
 .../allowed_operator_nodes/exponential.hpp    | 11 ++-
 .../allowed_operator_nodes/inverse.cpp        |  8 ---
 .../allowed_operator_nodes/inverse.hpp        | 11 ++-
 .../allowed_operator_nodes/log.cpp            |  8 ---
 .../allowed_operator_nodes/log.hpp            | 11 ++-
 .../allowed_operator_nodes/multiply.cpp       | 13 ----
 .../allowed_operator_nodes/multiply.hpp       | 11 ++-
 .../negative_exponential.cpp                  |  8 ---
 .../negative_exponential.hpp                  | 11 ++-
 .../allowed_operator_nodes/sin.cpp            |  8 ---
 .../allowed_operator_nodes/sin.hpp            | 11 ++-
 .../allowed_operator_nodes/sixth_power.cpp    |  8 ---
 .../allowed_operator_nodes/sixth_power.hpp    | 11 ++-
 .../allowed_operator_nodes/square.cpp         |  8 ---
 .../allowed_operator_nodes/square.hpp         | 11 ++-
 .../allowed_operator_nodes/square_root.cpp    |  8 ---
 .../allowed_operator_nodes/square_root.hpp    | 11 ++-
 .../allowed_operator_nodes/subtract.cpp       | 16 +----
 .../allowed_operator_nodes/subtract.hpp       | 11 ++-
 .../node/operator_nodes/functions.hpp         | 70 +++++++++----------
 .../value_storage/nodes_value_containers.hpp  |  4 +-
 40 files changed, 250 insertions(+), 298 deletions(-)

diff --git a/src/feature_creation/node/FeatureNode.hpp b/src/feature_creation/node/FeatureNode.hpp
index 8d6db1ee..8537d572 100644
--- a/src/feature_creation/node/FeatureNode.hpp
+++ b/src/feature_creation/node/FeatureNode.hpp
@@ -10,9 +10,6 @@
 
 #include <feature_creation/node/Node.hpp>
 
-typedef std::function<double(double)> unary_op_func;
-typedef std::function<double(double, double)> binary_op_func;
-
 /**
  * @brief Node that describe the leaves of the operator graph (Initial features in Phi_0)
  */
@@ -60,22 +57,7 @@ public:
     /**
      * @brief Set the value for the feature
      */
-    inline void set_value(){return;}
-
-    /**
-     * @brief Access the rung of the feature (Depth of the chart)
-     */
-    inline int rung(){return 0;}
-
-    /**
-     * @brief Set up the feature value pointers
-     */
-    inline void set_feat_val_ptrs(){return;}
-
-    /**
-     * @brief Accessor function to the feature value pointers
-     */
-    inline std::vector<double*> feat_value_ptrs(){return std::vector<double*>(0);}
+    inline void set_value(int offset = -1){return;}
 
     /**
      * @brief Check if the feature contains NaN
@@ -99,7 +81,12 @@ public:
     /**
      * @brief Accessor function to the value of the feature
      */
-    inline double* value_ptr(){return node_value_arrs::get_value_ptr(_feat_ind);}
+    inline double* value_ptr(int offset = 0){return node_value_arrs::get_value_ptr(_feat_ind, offset);}
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung = 0){return cur_rung;}
 
     /**
      * @brief Serialization function to send over MPI
diff --git a/src/feature_creation/node/Node.hpp b/src/feature_creation/node/Node.hpp
index da370a64..35b2e941 100644
--- a/src/feature_creation/node/Node.hpp
+++ b/src/feature_creation/node/Node.hpp
@@ -14,9 +14,6 @@
 #include <boost/serialization/string.hpp>
 #include <boost/serialization/unique_ptr.hpp>
 
-typedef std::function<double(double)> unary_op_func;
-typedef std::function<double(double, double)> binary_op_func;
-
 /**
  * @brief Base class for a Node
  * @details Class used to describe a Node on the descriptor graph. Features are treated as an operation graph, these are the nodes on that graph.
@@ -73,27 +70,12 @@ public:
     /**
      * @brief Set the value for the feature
      */
-    virtual void set_value() = 0;
-
-    /**
-     * @brief Access the rung of the feature (Depth of the chart)
-     */
-    virtual int rung() = 0;
-
-    /**
-     * @brief Set up the feature value pointers
-     */
-    virtual void set_feat_val_ptrs() = 0;
-
-    /**
-     * @brief Accessor function to the feature value pointers
-     */
-    virtual std::vector<double*> feat_value_ptrs() = 0;
+    virtual void set_value(int offset = -1) = 0;
 
     /**
      * @brief Accessor function to the value of the feature
      */
-    virtual double* value_ptr() = 0;
+    virtual double* value_ptr(int offset = 0) = 0;
 
     /**
      * @brief Check if the feature contains NaN
@@ -110,6 +92,11 @@ public:
      */
     virtual NODE_TYPE type() = 0;
 
+    /**
+     * @brief return the rung of the feature
+     */
+    virtual int rung(int cur_rung = 0) = 0;
+
     /**
      * @brief Serialization function to send over MPI
      *
diff --git a/src/feature_creation/node/operator_nodes/OperatorNode.cpp b/src/feature_creation/node/operator_nodes/OperatorNode.cpp
index ff1808ca..0a9f7cb7 100644
--- a/src/feature_creation/node/operator_nodes/OperatorNode.cpp
+++ b/src/feature_creation/node/operator_nodes/OperatorNode.cpp
@@ -5,17 +5,28 @@ OperatorNode::OperatorNode()
 
 OperatorNode::OperatorNode(std::vector<node_ptr> feats, int rung, int feat_ind) :
     Node(feat_ind, feats[0]->n_samp()),
-    _rung_offset(rung),
     _feats(feats)
 {
-    set_feat_val_ptrs();
+    _feats.reserve(_feats.size());
 }
 
 OperatorNode::OperatorNode(const OperatorNode &o) :
     Node(o),
-    _rung_offset(o._rung_offset),
-    _feats(o._feats),
-    _feat_val_ptrs(o._feat_val_ptrs)
-{}
+    _feats(o._feats)
+{
+    _feats.reserve(_feats.size());
+}
+
+double* OperatorNode::value_ptr(int offset)
+{
+    offset = (offset == -1) ? rung() : offset;
+    if((rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feat_ind, offset) != _feat_ind))
+    {
+        set_value(offset);
+        node_value_arrs::temp_storage_reg(_feat_ind, offset) = _feat_ind;
+    }
+
+    return node_value_arrs::get_value_ptr(_feat_ind, offset);
+}
 
 BOOST_SERIALIZATION_ASSUME_ABSTRACT(OperatorNode)
diff --git a/src/feature_creation/node/operator_nodes/OperatorNode.hpp b/src/feature_creation/node/operator_nodes/OperatorNode.hpp
index 1a3825b4..6cd8f424 100644
--- a/src/feature_creation/node/operator_nodes/OperatorNode.hpp
+++ b/src/feature_creation/node/operator_nodes/OperatorNode.hpp
@@ -20,10 +20,7 @@ class OperatorNode: public Node
 {
     friend class boost::serialization::access;
 protected:
-    double* _value_ptr;
-    int _rung_offset;
     std::vector<node_ptr> _feats;
-    std::vector<double*> _feat_val_ptrs;
 
 public:
     /**
@@ -51,37 +48,24 @@ public:
 
     virtual Unit unit() = 0;
 
-    virtual void set_value() =0;
+    virtual void set_value(int offset = -1) = 0;
 
     template <typename Archive>
     void serialize(Archive& ar, const unsigned int version)
     {
         ar & boost::serialization::base_object<Node>(*this);
-        ar & _rung_offset;
         ar & _feats;
-        set_feat_val_ptrs();
     }
 
     /**
-     * @brief Accessor function to the feature value pointers
-     */
-    inline std::vector<double*> feat_value_ptrs(){return _feat_val_ptrs;}
-
-    /**
-     * @brief Access the rung of the feature (Depth of the chart)
+     * @brief Get the pointer to the feature's data
+     * @details If the feature is not already stored in memory, then calculate the feature and return the pointer to the data
+     *
+     * @param offset the integer value to offset the location in the temporary storage array
+     *
+     * @return pointer to the feature's value
      */
-    inline int rung(){return _rung_offset;}
-
-    /**
-     * @brief Accessor function to the value of the feature
-     */
-    inline double* value_ptr()
-    {
-        if((_rung_offset > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feat_ind) != _feat_ind))
-            set_value();
-
-        return node_value_arrs::get_value_ptr(_feat_ind);
-    }
+    double* value_ptr(int offset=-1);
 
     /**
      * @brief Check if the feature contains NaN
@@ -98,20 +82,14 @@ public:
     }
 
     /**
-     * @brief Returns the type of node this is
+     * @brief return the rung of the feature
      */
-    virtual NODE_TYPE type() = 0;
+    virtual int rung(int cur_rung = 0) = 0;
 
     /**
-     * @brief Set up the feature value pointers
+     * @brief Returns the type of node this is
      */
-    inline void set_feat_val_ptrs()
-    {
-        _value_ptr = node_value_arrs::get_value_ptr(_feat_ind, 0);
-        _feat_val_ptrs = std::vector<double*>(_feats.size());
-        for(int ff = 0; ff < _feats.size(); ++ff)
-            _feat_val_ptrs[ff] = node_value_arrs::get_value_ptr(_feats[ff]->feat_ind(), (_rung_offset + 2 - ff) % 3);
-    }
+    virtual NODE_TYPE type() = 0;
 };
 
 #endif
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_difference.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_difference.cpp
index c0590ee1..2453e9a4 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_difference.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_difference.cpp
@@ -32,16 +32,3 @@ AbsDiffNode::AbsDiffNode(node_ptr feat_1, node_ptr feat_2, int rung, int feat_in
     if(is_nan() || is_const())
         throw InvalidFeatureException();
  }
-
-void AbsDiffNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    if((_feats[1]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[1]->feat_ind(), 1) != _feats[1]->feat_ind()))
-    {
-        std::copy_n(_feats[1]->value_ptr(), _n_samp, _feat_val_ptrs[1]);
-        node_value_arrs::temp_storage_reg(_feats[1]->feat_ind(), 1) = _feats[1]->feat_ind();
-    }
-    allowed_op_funcs::abs_diff(_n_samp, _feat_val_ptrs, _value_ptr);
-}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_difference.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_difference.hpp
index 0d3ec143..4ce38e04 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_difference.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_difference.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "|" + _feats[0]->expr() + " - (" + _feats[1]->expr() + ")|";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::abs_diff(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung = 0){return std::max(_feats[0]->rung(cur_rung + 1), _feats[1]->rung(cur_rung + 1));}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_value.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_value.cpp
index 71f35c94..4426869a 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_value.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_value.cpp
@@ -20,11 +20,3 @@ AbsNode::AbsNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
 }
-
-void AbsNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::abs(_n_samp, _feat_val_ptrs, _value_ptr);
-}
\ No newline at end of file
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_value.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_value.hpp
index 20afc8c5..07523c4a 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_value.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/absolute_value.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "|" + _feats[0]->expr() + "|";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::abs(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add.cpp
index 1a75d051..a500268d 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add.cpp
@@ -24,16 +24,3 @@ AddNode::AddNode(node_ptr feat_1, node_ptr feat_2, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
  }
-
-void AddNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    if((_feats[1]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[1]->feat_ind(), 1) != _feats[1]->feat_ind()))
-    {
-        std::copy_n(_feats[1]->value_ptr(), _n_samp, _feat_val_ptrs[1]);
-        node_value_arrs::temp_storage_reg(_feats[1]->feat_ind(), 1) = _feats[1]->feat_ind();
-    }
-    allowed_op_funcs::add(_n_samp, _feat_val_ptrs, _value_ptr);
-}
\ No newline at end of file
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add.hpp
index faff638c..6e496d05 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/add.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "(" + _feats[0]->expr() + " + " + _feats[1]->expr() + ")";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::add(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung = 0){return std::max(_feats[0]->rung(cur_rung + 1), _feats[1]->rung(cur_rung + 1));}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos.cpp
index 07d40fb1..954d858b 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos.cpp
@@ -30,11 +30,3 @@ CosNode::CosNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
  }
-
-void CosNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::cos(_n_samp, _feat_val_ptrs, _value_ptr);
-}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos.hpp
index bd246c74..29fa3753 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cos.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "cos(" + _feats[0]->expr() + ")";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::cos(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube.cpp
index 72cd11c9..e5d652d3 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube.cpp
@@ -24,11 +24,3 @@ CbNode::CbNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
 }
-
-void CbNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::cb(_n_samp, _feat_val_ptrs, _value_ptr);
-}
\ No newline at end of file
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube.hpp
index 671d7312..3bad615d 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "(" + _feats[0]->expr() + ")^3";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::cb(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube_root.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube_root.cpp
index 18ab351a..21eb0e8b 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube_root.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube_root.cpp
@@ -24,11 +24,3 @@ CbrtNode::CbrtNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
 }
-
-void CbrtNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::cbrt(_n_samp, _feat_val_ptrs, _value_ptr);
-}
\ No newline at end of file
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube_root.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube_root.hpp
index 88f0e935..fa78ec94 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube_root.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/cube_root.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "cbrt(" + _feats[0]->expr() + ")";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::cbrt(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/divide.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/divide.cpp
index 2fcd1955..b116cc12 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/divide.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/divide.cpp
@@ -24,16 +24,3 @@ DivNode::DivNode(node_ptr feat_1, node_ptr feat_2, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
 }
-
-void DivNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    if((_feats[1]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[1]->feat_ind(), 1) != _feats[1]->feat_ind()))
-    {
-        std::copy_n(_feats[1]->value_ptr(), _n_samp, _feat_val_ptrs[1]);
-        node_value_arrs::temp_storage_reg(_feats[1]->feat_ind(), 1) = _feats[1]->feat_ind();
-    }
-    allowed_op_funcs::div(_n_samp, _feat_val_ptrs, _value_ptr);
-}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/divide.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/divide.hpp
index 08607cc8..755acd61 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/divide.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/divide.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "[(" + _feats[0]->expr() + ") / (" + _feats[1]->expr() + ")]";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::div(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung = 0){return std::max(_feats[0]->rung(cur_rung + 1), _feats[1]->rung(cur_rung + 1));}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exponential.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exponential.cpp
index ed2450d6..3a6f47ae 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exponential.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exponential.cpp
@@ -30,11 +30,3 @@ ExpNode::ExpNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
  }
-
-void ExpNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::exp(_n_samp, _feat_val_ptrs, _value_ptr);
-}
\ No newline at end of file
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exponential.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exponential.hpp
index 46eb66c4..605bd4f0 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exponential.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/exponential.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "exp(" + _feats[0]->expr() + ")";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::exp(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inverse.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inverse.cpp
index e33471a1..1cfe5f50 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inverse.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inverse.cpp
@@ -24,11 +24,3 @@ InvNode::InvNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
 }
-
-void InvNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::inv(_n_samp, _feat_val_ptrs, _value_ptr);
-}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inverse.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inverse.hpp
index 6bd02488..4f2c24b2 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inverse.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/inverse.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "1.0 / (" + _feats[0]->expr() + ")";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::inv(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log.cpp
index 2a3e77e2..6196fcd4 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log.cpp
@@ -30,11 +30,3 @@ LogNode::LogNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
  }
-
-void LogNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::log(_n_samp, _feat_val_ptrs, _value_ptr);
-}
\ No newline at end of file
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log.hpp
index db792788..8ba84f86 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/log.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "log(" + _feats[0]->expr() + ")";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::log(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/multiply.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/multiply.cpp
index 66729c80..7e3b23cd 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/multiply.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/multiply.cpp
@@ -19,16 +19,3 @@ MultNode::MultNode(node_ptr feat_1, node_ptr feat_2, int rung, int feat_ind):
         throw InvalidFeatureException();
 }
 
-void MultNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    if((_feats[1]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[1]->feat_ind(), 1) != _feats[1]->feat_ind()))
-    {
-        std::copy_n(_feats[1]->value_ptr(), _n_samp, _feat_val_ptrs[1]);
-        node_value_arrs::temp_storage_reg(_feats[1]->feat_ind(), 1) = _feats[1]->feat_ind();
-    }
-
-    allowed_op_funcs::mult(_n_samp, _feat_val_ptrs, _value_ptr);
-}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/multiply.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/multiply.hpp
index 9460ac6f..aa93bbd9 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/multiply.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/multiply.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "[(" + _feats[0]->expr() + ") * (" + _feats[1]->expr() + ")]";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::mult(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung = 0){return std::max(_feats[0]->rung(cur_rung + 1), _feats[1]->rung(cur_rung + 1));}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/negative_exponential.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/negative_exponential.cpp
index ac6ff996..6cb67bb1 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/negative_exponential.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/negative_exponential.cpp
@@ -32,11 +32,3 @@ NegExpNode::NegExpNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
  }
-
-void NegExpNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::neg_exp(_n_samp, _feat_val_ptrs, _value_ptr);
-}
\ No newline at end of file
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/negative_exponential.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/negative_exponential.hpp
index 129036fd..32e4d785 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/negative_exponential.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/negative_exponential.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "exp[-1.0*(" + _feats[0]->expr() + ")]";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::neg_exp(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    };
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin.cpp
index c9845a1e..ceba2dde 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin.cpp
@@ -30,11 +30,3 @@ SinNode::SinNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
  }
-
-void SinNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::sin(_n_samp, _feat_val_ptrs, _value_ptr);
-}
\ No newline at end of file
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin.hpp
index 306381cc..d871a87e 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sin.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "sin(" + _feats[0]->expr() + ")";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::sin(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sixth_power.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sixth_power.cpp
index e69e3195..3d1063d4 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sixth_power.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sixth_power.cpp
@@ -24,11 +24,3 @@ SixPowNode::SixPowNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
 }
-
-void SixPowNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::sixth_pow(_n_samp, _feat_val_ptrs, _value_ptr);
-}
\ No newline at end of file
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sixth_power.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sixth_power.hpp
index 85062f99..6c2535be 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sixth_power.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/sixth_power.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "(" + _feats[0]->expr() + ")^6";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::sixth_pow(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square.cpp
index 1fe69a5a..082f9e30 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square.cpp
@@ -24,11 +24,3 @@ SqNode::SqNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
 }
-
-void SqNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::sq(_n_samp, _feat_val_ptrs, _value_ptr);
-}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square.hpp
index 8ced5433..93ed269c 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "(" + _feats[0]->expr() + ")^2";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::sq(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square_root.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square_root.cpp
index 09673fd7..0bbcaa9a 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square_root.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square_root.cpp
@@ -24,11 +24,3 @@ SqrtNode::SqrtNode(node_ptr feat, int rung, int feat_ind):
     if(is_nan() || is_const())
         throw InvalidFeatureException();
 }
-
-void SqrtNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    allowed_op_funcs::sqrt(_n_samp, _feat_val_ptrs, _value_ptr);
-}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square_root.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square_root.hpp
index ab93e8e1..086328a4 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square_root.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/square_root.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "sqrt(" + _feats[0]->expr() + ")";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::sqrt(_n_samp, _feats[0]->value_ptr(offset + 2), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung=0){return _feats[0]->rung(cur_rung + 1);}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/subtract.cpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/subtract.cpp
index 4b7e6c7d..9c98078a 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/subtract.cpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/subtract.cpp
@@ -23,18 +23,4 @@ SubNode::SubNode(node_ptr feat_1, node_ptr feat_2, int rung, int feat_ind):
     set_value();
     if(is_nan() || is_const())
         throw InvalidFeatureException();
- }
-
-void SubNode::set_value()
-{
-    if((_feats[0]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[0]->feat_ind(), 2) != _feats[0]->feat_ind()))
-        _feats[0]->set_value();
-
-    if((_feats[1]->rung() > node_value_arrs::N_RUNGS_STORED) && (node_value_arrs::temp_storage_reg(_feats[1]->feat_ind(), 1) != _feats[1]->feat_ind()))
-    {
-        std::copy_n(_feats[1]->value_ptr(), _n_samp, _feat_val_ptrs[1]);
-        node_value_arrs::temp_storage_reg(_feats[1]->feat_ind(), 1) = _feats[1]->feat_ind();
-    }
-
-    allowed_op_funcs::sub(_n_samp, _feat_val_ptrs, _value_ptr);
-}
\ No newline at end of file
+}
diff --git a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/subtract.hpp b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/subtract.hpp
index 5be24fe0..daa24450 100644
--- a/src/feature_creation/node/operator_nodes/allowed_operator_nodes/subtract.hpp
+++ b/src/feature_creation/node/operator_nodes/allowed_operator_nodes/subtract.hpp
@@ -17,7 +17,16 @@ public:
 
     inline std::string expr(){return "[(" + _feats[0]->expr() + ") - (" + _feats[1]->expr() + ")]";}
 
-    void set_value();
+    inline void set_value(int offset = -1)
+    {
+        offset = (offset == -1) ? rung() : offset;
+        allowed_op_funcs::sub(_n_samp, _feats[0]->value_ptr(offset + 2), _feats[1]->value_ptr(offset + 1), node_value_arrs::get_value_ptr(_feat_ind, offset));
+    }
+
+    /**
+     * @brief return the rung of the feature
+     */
+    inline int rung(int cur_rung = 0){return std::max(_feats[0]->rung(cur_rung + 1), _feats[1]->rung(cur_rung + 1));}
 
     /**
      * @brief Returns the type of node this is
diff --git a/src/feature_creation/node/operator_nodes/functions.hpp b/src/feature_creation/node/operator_nodes/functions.hpp
index ba31571c..f14cd8eb 100644
--- a/src/feature_creation/node/operator_nodes/functions.hpp
+++ b/src/feature_creation/node/operator_nodes/functions.hpp
@@ -4,8 +4,6 @@
 #include <algorithm>
 #include <functional>
 
-typedef std::function<void(int, std::vector<double*>&, double*)> op_func;
-
 namespace allowed_op_funcs
 {
     /**
@@ -15,9 +13,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void add(int size, std::vector<double*>& inputs, double* out)
+    inline void add(int size, double* in_0, double* in_1, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, inputs[1], out, std::plus<double>());
+        std::transform(in_0, in_0 + size, in_1, out, std::plus<double>());
     }
 
     /**
@@ -27,9 +25,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void sub(int size, std::vector<double*>& inputs, double* out)
+    inline void sub(int size, double* in_0, double* in_1, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, inputs[1], out, std::minus<double>());
+        std::transform(in_0, in_0 + size, in_1, out, std::minus<double>());
     }
 
     /**
@@ -39,9 +37,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void abs_diff(int size, std::vector<double*>& inputs, double* out)
+    inline void abs_diff(int size, double* in_0, double* in_1, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, inputs[1], out, [](double in_0, double in_1){return std::abs(in_0 - in_1);});
+        std::transform(in_0, in_0 + size, in_1, out, [](double in_0, double in_1){return std::abs(in_0 - in_1);});
     }
 
     /**
@@ -51,9 +49,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void mult(int size, std::vector<double*>& inputs, double* out)
+    inline void mult(int size, double* in_0, double* in_1, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, inputs[1], out, std::multiplies<double>());
+        std::transform(in_0, in_0 + size, in_1, out, std::multiplies<double>());
     }
 
     /**
@@ -63,9 +61,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void div(int size, std::vector<double*>& inputs, double* out)
+    inline void div(int size, double* in_0, double* in_1, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, inputs[1], out, std::divides<double>());
+        std::transform(in_0, in_0 + size, in_1, out, std::divides<double>());
     }
 
     /**
@@ -75,9 +73,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void exp(int size, std::vector<double*>& inputs, double* out)
+    inline void exp(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return std::exp(in_0);});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return std::exp(in_0);});
     }
 
     /**
@@ -87,9 +85,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void neg_exp(int size, std::vector<double*>& inputs, double* out)
+    inline void neg_exp(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return std::exp(-1.0*in_0);});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return std::exp(-1.0*in_0);});
     }
 
     /**
@@ -99,9 +97,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void sq(int size, std::vector<double*>& inputs, double* out)
+    inline void sq(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return std::pow(in_0, 2.0);});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return std::pow(in_0, 2.0);});
     }
 
     /**
@@ -111,9 +109,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void cb(int size, std::vector<double*>& inputs, double* out)
+    inline void cb(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return std::pow(in_0, 3.0);});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return std::pow(in_0, 3.0);});
     }
 
     /**
@@ -123,9 +121,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void sixth_pow(int size, std::vector<double*>& inputs, double* out)
+    inline void sixth_pow(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return std::pow(in_0, 6.0);});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return std::pow(in_0, 6.0);});
     }
 
     /**
@@ -135,9 +133,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void cbrt(int size, std::vector<double*>& inputs, double* out)
+    inline void cbrt(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return std::pow(in_0, 1.0/3.0);});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return std::pow(in_0, 1.0/3.0);});
     }
 
     /**
@@ -147,9 +145,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void sqrt(int size, std::vector<double*>& inputs, double* out)
+    inline void sqrt(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return std::sqrt(in_0);});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return std::sqrt(in_0);});
     }
 
     /**
@@ -159,9 +157,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void inv(int size, std::vector<double*>& inputs, double* out)
+    inline void inv(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return 1.0 / in_0;});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return 1.0 / in_0;});
     }
 
     /**
@@ -171,9 +169,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void log(int size, std::vector<double*>& inputs, double* out)
+    inline void log(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return std::log(in_0);});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return std::log(in_0);});
     }
 
     /**
@@ -183,9 +181,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void sin(int size, std::vector<double*>& inputs, double* out)
+    inline void sin(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return std::sin(in_0);});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return std::sin(in_0);});
     }
 
     /**
@@ -195,9 +193,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void cos(int size, std::vector<double*>& inputs, double* out)
+    inline void cos(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return std::cos(in_0);});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return std::cos(in_0);});
     }
 
     /**
@@ -207,9 +205,9 @@ namespace allowed_op_funcs
      * @param inputs array of the pointers to the input arrays
      * @param out pointer to the output array
      */
-    inline void abs(int size, std::vector<double*>& inputs, double* out)
+    inline void abs(int size, double* in_0, double* out)
     {
-        std::transform(inputs[0], inputs[0] + size, out, [](double in_0){return std::abs(in_0);});
+        std::transform(in_0, in_0 + size, out, [](double in_0){return std::abs(in_0);});
     }
 };
 
diff --git a/src/feature_creation/node/value_storage/nodes_value_containers.hpp b/src/feature_creation/node/value_storage/nodes_value_containers.hpp
index daefbeba..a5a09682 100644
--- a/src/feature_creation/node/value_storage/nodes_value_containers.hpp
+++ b/src/feature_creation/node/value_storage/nodes_value_containers.hpp
@@ -56,7 +56,7 @@ namespace node_value_arrs
      *
      * @return The register element for a given feature index and offset
      */
-    inline int& temp_storage_reg(int ind, int offset = 0){return TEMP_STORAGE_REG[(ind % N_STORE_FEATURES) + offset * N_STORE_FEATURES];}
+    inline int& temp_storage_reg(int ind, int offset = 0){return TEMP_STORAGE_REG[(ind % N_STORE_FEATURES) + (offset % 3) * N_STORE_FEATURES];}
 
     /**
      * @brief Access element of the permanent storage array
@@ -89,7 +89,7 @@ namespace node_value_arrs
         if(ind < N_STORE_FEATURES)
             return  access_value_arr(ind);
         temp_storage_reg(ind, offset) = ind;
-        return access_temp_storage((ind % N_STORE_FEATURES) + offset * N_STORE_FEATURES);
+        return access_temp_storage((ind % N_STORE_FEATURES) + (offset % 3) * N_STORE_FEATURES);
     }
 }
 
-- 
GitLab