From dda6e01bc60fb088fe52c0867ad1ddc3e66b6a1d Mon Sep 17 00:00:00 2001
From: Thomas <purcell@fhi-berlin.mpg.de>
Date: Mon, 23 Aug 2021 09:45:46 +0200
Subject: [PATCH] Revert some changes from sissopp gitlab repo

Dockerfile and .gitlab-ci; remove bindings.*pp files
---
 .gitlab-ci.yml                             |  156 ++-
 docker/Dockerfile                          |   39 +-
 src/python/py_binding_cpp_def/bindings.cpp | 1374 --------------------
 src/python/py_binding_cpp_def/bindings.hpp |  599 ---------
 4 files changed, 160 insertions(+), 2008 deletions(-)
 delete mode 100644 src/python/py_binding_cpp_def/bindings.cpp
 delete mode 100644 src/python/py_binding_cpp_def/bindings.hpp

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4f32195c..8647aa9f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,4 +1,4 @@
-image: registry.gitlab.com/sissopp_developers/sissopp
+image: gitlab-registry.mpcdf.mpg.de/tpurcell/cpp_sisso
 
 stages:
   - build
@@ -6,16 +6,118 @@ stages:
   - bin_test
   - doc_builds
 
+build-intel:
+  stage: build
+  script:
+    - python -m venv cpp_sisso_env
+    - source cpp_sisso_env/bin/activate
+    - mkdir build_intel/
+    - cd build_intel/
+    - export I_MPI_ROOT=/home/runner/intel/oneapi/mpi/latest/
+    - export INTEL_COMP_ROOT=/home/runner/intel/oneapi/compiler/latest/linux/
+    - export MKLROOT=/home/runner/intel/oneapi/mkl/latest/
+    - export LD_LIBRARY_PATH=$I_MPI_ROOT/lib/:$I_MPI_ROOT/lib/release:$MKLROOT/lib/intel64:$INTEL_COMP_ROOT/lib/:$INTEL_COMP_ROOT/compiler/lib/intel64/:$LD_LIBRARY_PATH:$HOME/intel/oneapi/intelpython/latest/lib/:$HOME/intel/oneapi/intelpython/latest/lib/python3.7
+    - export PYTHONPATH=$HOME/intel/oneapi/intelpython/latest/lib/python3.7/site-packages/:cpp_sisso_env/lib/python3.7/site-packages/
+    - export PATH=$INTEL_COMP_ROOT/bin/:$INTEL_COMP_ROOT/bin/intel64:$I_MPI_ROOT/bin:$PATH
+    - cmake -DCMAKE_CXX_COMPILER=icpc -DCMAKE_C_COMPILE=icc -DCMAKE_CXX_FLAGS="-O3" -DBUILD_TESTS=ON -DBUILD_PARAMS=ON -DBUILD_PYTHON=ON ../
+    - make
+    - make install
+    - cd ../
+  artifacts:
+    when: always
+    paths:
+      - bin/sisso++
+      - lib/libsisso.so
+      - lib/boost/*
+      - lib/gtest/*
+      - lib/coin-or/*
+      - lib/nlopt/*
+      - lib/gtest/*
+      - lib/fmt/*
+      - tests/googletest/sisso_test
+      - cpp_sisso_env/*
+    expire_in: 1 days
+
+test-intel-py:
+  stage: unit_test
+  dependencies:
+    - build-intel
+  script:
+    - source cpp_sisso_env/bin/activate
+    - export I_MPI_ROOT=/home/runner/intel/oneapi/mpi/latest/
+    - export INTEL_COMP_ROOT=/home/runner/intel/oneapi/compiler/latest/linux/
+    - export MKLROOT=/home/runner/intel/oneapi/mkl/latest/
+    - export LD_LIBRARY_PATH=$I_MPI_ROOT/lib/:$I_MPI_ROOT/lib/release:$MKLROOT/lib/intel64:$INTEL_COMP_ROOT/lib/:$INTEL_COMP_ROOT/compiler/lib/intel64/:$LD_LIBRARY_PATH:$HOME/intel/oneapi/intelpython/latest/lib/:$HOME/intel/oneapi/intelpython/latest/lib/python3.7
+    - export PYTHONPATH=$HOME/intel/oneapi/intelpython/latest/lib/python3.7/site-packages/:cpp_sisso_env/lib/python3.7/site-packages/
+    - export PATH=$INTEL_COMP_ROOT/bin/:$INTEL_COMP_ROOT/bin/intel64:$I_MPI_ROOT/bin:$PATH
+    - export OMP_NUM_THREADS=2
+    - export OMP_PLACES=cores
+    - pytest tests/pytest
+
+test-intel-googletest:
+  stage: unit_test
+  dependencies:
+    - build-intel
+  script:
+    - source cpp_sisso_env/bin/activate
+    - export I_MPI_ROOT=/home/runner/intel/oneapi/mpi/latest/
+    - export INTEL_COMP_ROOT=/home/runner/intel/oneapi/compiler/latest/linux/
+    - export MKLROOT=/home/runner/intel/oneapi/mkl/latest/
+    - export LD_LIBRARY_PATH=$I_MPI_ROOT/lib/:$I_MPI_ROOT/lib/release:$MKLROOT/lib/intel64:$INTEL_COMP_ROOT/lib/:$INTEL_COMP_ROOT/compiler/lib/intel64/:$LD_LIBRARY_PATH:$HOME/intel/oneapi/intelpython/latest/lib/:$HOME/intel/oneapi/intelpython/latest/lib/python3.7
+    - export PYTHONPATH=$HOME/intel/oneapi/intelpython/latest/lib/python3.7/site-packages/:cpp_sisso_env/lib/python3.7/site-packages/
+    - export PATH=$INTEL_COMP_ROOT/bin/:$INTEL_COMP_ROOT/bin/intel64:$I_MPI_ROOT/bin:$PATH
+    - export OMP_NUM_THREADS=2
+    - export OMP_PLACES=cores
+    - cd tests/
+    - googletest/sisso_test
+
+test-intel-bin:
+  stage: bin_test
+  dependencies:
+    - build-intel
+  script:
+    - source cpp_sisso_env/bin/activate
+    - export I_MPI_ROOT=/home/runner/intel/oneapi/mpi/latest/
+    - export INTEL_COMP_ROOT=/home/runner/intel/oneapi/compiler/latest/linux/
+    - export MKLROOT=/home/runner/intel/oneapi/mkl/latest/
+    - export LD_LIBRARY_PATH=$I_MPI_ROOT/lib/:$I_MPI_ROOT/lib/release:$MKLROOT/lib/intel64:$INTEL_COMP_ROOT/lib/:$INTEL_COMP_ROOT/compiler/lib/intel64/:$LD_LIBRARY_PATH:$HOME/intel/oneapi/intelpython/latest/lib/:$HOME/intel/oneapi/intelpython/latest/lib/python3.7
+    - export PYTHONPATH=$HOME/intel/oneapi/intelpython/latest/lib/python3.7/site-packages/:cpp_sisso_env/lib/python3.7/site-packages/
+    - export PATH=$INTEL_COMP_ROOT/bin/:$INTEL_COMP_ROOT/bin/intel64:$I_MPI_ROOT/bin:$PATH
+    - export OMP_NUM_THREADS=1
+    - cd tests/exec_test/default/
+    - mpiexec -n 1 ../../../bin/sisso++
+    - python ../check_model.py
+    - cd ../classification/
+    - mpiexec -n 1 ../../../bin/sisso++
+    - python check_model.py
+    - cd ../gen_proj
+    - mpiexec -n 2 ../../../bin/sisso++
+    - python ../check_model.py
+    - cd ../log_reg
+    - mpiexec -n 2 ../../../bin/sisso++
+    - python check_model.py
+    - cd ../max_corr
+    - mpiexec -n 2 ../../../bin/sisso++
+    - python ../check_model.py
+    - cd ../param
+    - mpiexec -n 2 ../../../bin/sisso++
+    - python ../check_model.py
+    - cd ../reparam
+    - mpiexec -n 2 ../../../bin/sisso++
+    - cd ../../../
+
 build-gnu:
   stage: build
   script:
-    - /opt/anaconda/3/2021.05/bin/python -m venv sissopp_env
-    - source sissopp_env/bin/activate
-    - export LD_LIBRARY_PATH=/opt/anaconda/3/2021.05/lib/:/opt/anaconda/3/2021.05/lib/python3.8:$LD_LIBRARY_PATH
-    - export PYTHONPATH=/opt/anaconda/3/2021.05/lib/python3.8/site-packages/:sissopp_env/lib/python3.8/site-packages/
+    - conda info --envs
+    - python -m venv cpp_sisso_env
+    - source cpp_sisso_env/bin/activate
+    - export LD_LIBRARY_PATH=$HOME/intel/oneapi/intelpython/latest/lib/:$HOME/intel/oneapi/intelpython/latest/lib/python3.7:$LD_LIBRARY_PATH
+    - export PYTHONPATH=$HOME/intel/oneapi/intelpython/latest/lib/python3.7/site-packages/:cpp_sisso_env/lib/python3.7/site-packages/
     - mkdir build_gcc/
     - cd build_gcc/
-    - cmake -C ../cmake/toolchains/gnu_param_py.cmake -DBUILD_TESTS=ON ../
+    - cmake -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILE=gcc -DCMAKE_CXX_FLAGS="-O3" -DBUILD_TESTS=ON -DBUILD_PARAMS=ON -DBUILD_PYTHON=ON ../
+
     - make
     - make install
     - cd ../
@@ -23,33 +125,37 @@ build-gnu:
     when: always
     paths:
       - bin/sisso++
+      - lib/libsisso.so
       - lib/boost/*
       - lib/gtest/*
       - lib/coin-or/*
       - lib/nlopt/*
       - lib/gtest/*
       - lib/fmt/*
-      - lib/libsisso.so
-      - sissopp_env/*
       - tests/googletest/sisso_test
+      - cpp_sisso_env/*
 
 test-gnu-py:
   stage: unit_test
   dependencies:
     - build-gnu
   script:
-    - source sissopp_env/bin/activate
-    - export LD_LIBRARY_PATH=/opt/anaconda/3/2021.05/lib/:/opt/anaconda/3/2021.05/lib/python3.8:$LD_LIBRARY_PATH
-    - export PYTHONPATH=/opt/anaconda/3/2021.05/lib/python3.8/site-packages/:sissopp_env/lib/python3.8/site-packages/
-    - /opt/anaconda/3/2021.05/bin/pytest tests/pytest
+    - source cpp_sisso_env/bin/activate
+    - export LD_LIBRARY_PATH=$HOME/intel/oneapi/intelpython/latest/lib/:$HOME/intel/oneapi/intelpython/latest/lib/python3.7:$LD_LIBRARY_PATH
+    - export PYTHONPATH=$HOME/intel/oneapi/intelpython/latest/lib/python3.7/site-packages/:cpp_sisso_env/lib/python3.7/site-packages/
+    - export OMP_NUM_THREADS=2
+    - export OMP_PLACES=cores
+    - pytest tests/pytest
 
 test-gnu-googletest:
   stage: unit_test
   dependencies:
     - build-gnu
   script:
-    - source sissopp_env/bin/activate
-    - cd tests/  
+    - source cpp_sisso_env/bin/activate
+    - export OMP_NUM_THREADS=2
+    - export OMP_PLACES=cores
+    - cd tests/
     - googletest/sisso_test
 
 test-gnu-bin:
@@ -57,30 +163,36 @@ test-gnu-bin:
   dependencies:
     - build-gnu
   script:
-    - source sissopp_env/bin/activate
-    - export LD_LIBRARY_PATH=/opt/anaconda/3/2021.05/lib/:/opt/anaconda/3/2021.05/lib/python3.8:`pwd`/lib/:$LD_LIBRARY_PATH
-    - export PYTHONPATH=/opt/anaconda/3/2021.05/lib/python3.8/site-packages/:sissopp_env/lib/python3.8/site-packages/
-    - ls lib
+    - source cpp_sisso_env/bin/activate
+    - export LD_LIBRARY_PATH=$HOME/intel/oneapi/intelpython/latest/lib/:$HOME/intel/oneapi/intelpython/latest/lib/python3.7:$LD_LIBRARY_PATH
+    - export PYTHONPATH=$HOME/intel/oneapi/intelpython/latest/lib/python3.7/site-packages/:cpp_sisso_env/lib/python3.7/site-packages/
+    - export OMP_NUM_THREADS=1
     - cd tests/exec_test/default/
     - mpiexec -n 1 ../../../bin/sisso++
     - python ../check_model.py
     - cd ../classification/
     - mpiexec -n 1 ../../../bin/sisso++
     - python check_model.py
-    - cd ../gen_proj/
+    - cd ../gen_proj
     - mpiexec -n 1 ../../../bin/sisso++
     - python ../check_model.py
-    - cd ../log_reg/
+    - cd ../log_reg
     - mpiexec -n 1 ../../../bin/sisso++
     - python check_model.py
-    - cd ../max_corr/
+    - cd ../max_corr
     - mpiexec -n 1 ../../../bin/sisso++
     - python ../check_model.py
+    - cd ../param
+    - mpiexec -n 1 ../../../bin/sisso++
+    - python ../check_model.py
+    - cd ../reparam
+    - mpiexec -n 1 ../../../bin/sisso++
+    - cd ../../../
 
 pages:
   stage: doc_builds
   script:
-    - source sissopp_env/bin/activate
+    - source cpp_sisso_env/bin/activate
     - cd docs/
     - make html
     - mv _build/html/ ../public
diff --git a/docker/Dockerfile b/docker/Dockerfile
index f1337ea9..02e9d93d 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -17,15 +17,22 @@ RUN apt-get update &&\
     apt-get install -y doxygen &&\
     apt-get clean
 
-ARG dst=/opt/anaconda/3/2021.05
-
-RUN wget https://repo.anaconda.com/archive/Anaconda3-2021.05-Linux-x86_64.sh
-RUN mv Anaconda3-2021.05-Linux-x86_64.sh /tmp/anaconda.sh
-RUN bash /tmp/anaconda.sh -b -f -p ${dst} &&\
-    rm -f /tmp/anaconda.sh
-
-RUN ${dst}/bin/conda install -y  -c conda-forge numpy scipy pandas pytest seaborn tornado
-RUN ${dst}/bin/pip install sphinx sphinx-rtd-theme breathe sphinx-sitemap myst_parser
+RUN apt-get install -y gpg-agent wget software-properties-common &&\
+    wget https://repositories.intel.com/graphics/intel-graphics.key &&\
+    apt-key add intel-graphics.key &&\
+    apt-add-repository 'deb [arch=amd64] https://repositories.intel.com/graphics/ubuntu focal main'
+RUN apt-get update -y &&\
+    apt-get install -y intel-opencl-icd intel-level-zero-gpu level-zero intel-media-va-driver-non-free libmfx1 libcilkrts5
+RUN apt-get install -y \
+    libigc-dev \
+    libigdfcl-dev \
+    libigfxcmrt-dev \
+    level-zero-dev
+ARG oneapi_src=oneapi.sh
+ADD ${oneapi_src} /tmp/oneapi.sh
+
+ARG hpc_oneapi_src=hpc_oneapi.sh
+ADD ${hpc_oneapi_src} /tmp/hpc_oneapi.sh
 
 # Setup the user
 RUN useradd -d /home/runner -ms /bin/bash runner
@@ -33,13 +40,19 @@ RUN useradd -d /home/runner -ms /bin/bash runner
 USER runner
 WORKDIR /home/runner
 
+RUN sh /tmp/oneapi.sh -s -a  --silent --eula accept --components intel.oneapi.lin.python3:intel.oneapi.lin.tbb.devel:intel.oneapi.lin.dpcpp-cpp-compiler:intel.oneapi.lin.dpl:intel.oneapi.lin.mkl.devel:intel.oneapi.lin.dpcpp-ct
+RUN sh /tmp/hpc_oneapi.sh -s -a  --silent --eula accept --components intel.oneapi.lin.mpi.devel:intel.oneapi.lin.dpcpp-cpp-compiler-pro:intel.oneapi.lin.ifort-compiler
+
 ENV CONDA_DEFAULT_ENV='base'
-ENV CONDA_EXE='/opt/anaconda/3/2021.05/bin/conda'
-ENV CONDA_PREFIX='/opt/anaconda/3/2021.05'
+ENV CONDA_EXE='/home/runner/intel/oneapi/intelpython/latest/bin/conda'
+ENV CONDA_PREFIX='/home/runner/intel/oneapi/intelpython/latest'
 ENV CONDA_PROMPT_MODIFIER='(base) '
-ENV CONDA_PYTHON_EXE='/opt/anaconda/3/2021.05/bin/python'
+ENV CONDA_PYTHON_EXE='/home/runner/intel/oneapi/intelpython/latest/bin/python'
 ENV CONDA_SHLVL='1'
-ENV PATH="/opt/anaconda/3/2021.05/bin:/opt/anaconda/3/2021.05/condabin:$PATH"
+ENV CPATH='/home/runner/intel/oneapi/dpl/latest/linux/include:/home/runner/intel/oneapi/dev-utilities/latest/include:/home/runner/intel/oneapi/mpi/latest//include:/home/runner/intel/oneapi/mkl/latest/include:/home/runner/intel/oneapi/ccl/latest/include/cpu_gpu_dpcpp:/home/runner/intel/oneapi/compiler/latest/linux/include:/home/runner/intel/oneapi/ipp/latest/include:/home/runner/intel/oneapi/vpl/latest/include:/home/runner/intel/oneapi/dal/latest/include:/home/runner/intel/oneapi/dnnl/latest/cpu_dpcpp_gpu_dpcpp/lib:/home/runner/intel/oneapi/ippcp/latest/include:/home/runner/intel/oneapi/tbb/latest/env/../include'
+ENV PATH="/home/runner/intel/oneapi/intelpython/latest/bin:/home/runner/intel/oneapi/intelpython/latest/condabin:$PATH"
 ENV _CE_CONDA=''
 ENV _CE_M=''
 
+RUN /home/runner/intel/oneapi/intelpython/latest/bin/conda install -y numpy scipy pandas pytest seaborn tornado
+RUN /home/runner/intel/oneapi/intelpython/latest/bin/pip install sphinx sphinx-rtd-theme breathe sphinx-sitemap myst_parser
diff --git a/src/python/py_binding_cpp_def/bindings.cpp b/src/python/py_binding_cpp_def/bindings.cpp
deleted file mode 100644
index b4809d3a..00000000
--- a/src/python/py_binding_cpp_def/bindings.cpp
+++ /dev/null
@@ -1,1374 +0,0 @@
-// Copyright 2021 Thomas A. R. Purcell
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/** @file python/py_bindings_cpp_def/bindings.cpp
- *  @brief Implements the functions used to convert C++ classes into python classes
- *
- *  @author Thomas A. R. Purcell (tpurcell90)
- *  @bug No known bugs.
- */
-
-#include "python/py_binding_cpp_def/bindings.hpp"
-
-using namespace boost::python;
-
-void sisso::register_all()
-{
-    sisso::registerInputs();
-    sisso::descriptor_identifier::registerModel();
-    sisso::descriptor_identifier::registerModelRegressor();
-    sisso::descriptor_identifier::registerModelLogRegressor();
-    sisso::descriptor_identifier::registerModelClassifier();
-    sisso::descriptor_identifier::registerSISSOSolver();
-    sisso::descriptor_identifier::registerSISSORegressor();
-    sisso::descriptor_identifier::registerSISSOLogRegressor();
-    sisso::descriptor_identifier::registerSISSOClassifier();
-    sisso::feature_creation::registerFeatureSpace();
-    sisso::feature_creation::registerUnit();
-    sisso::feature_creation::node::registerNode();
-    sisso::feature_creation::node::registerFeatureNode();
-    sisso::feature_creation::node::registerModelNode();
-    sisso::feature_creation::node::registerOperatorNode<1>();
-    sisso::feature_creation::node::registerOperatorNode<2>();
-    sisso::feature_creation::node::registerAddNode();
-    sisso::feature_creation::node::registerSubNode();
-    sisso::feature_creation::node::registerDivNode();
-    sisso::feature_creation::node::registerMultNode();
-    sisso::feature_creation::node::registerAbsDiffNode();
-    sisso::feature_creation::node::registerAbsNode();
-    sisso::feature_creation::node::registerInvNode();
-    sisso::feature_creation::node::registerLogNode();
-    sisso::feature_creation::node::registerExpNode();
-    sisso::feature_creation::node::registerNegExpNode();
-    sisso::feature_creation::node::registerSinNode();
-    sisso::feature_creation::node::registerCosNode();
-    sisso::feature_creation::node::registerCbNode();
-    sisso::feature_creation::node::registerCbrtNode();
-    sisso::feature_creation::node::registerSqNode();
-    sisso::feature_creation::node::registerSqrtNode();
-    sisso::feature_creation::node::registerSixPowNode();
-
-    def(
-        "phi_selected_from_file",
-        &str2node::phi_selected_from_file_py,
-        (arg("filename"), arg("phi_0")),
-        "Convert a feature_space/selected_features.txt into a phi_selected\nRead in the file to get the postfix expressions and regenerate the selected features using phi_0\n\nArgs:\n    filename: The name of the feature_space/selected_features.txt file\n    phi_0: The initial feature space\n\nReturns:\n     The selected feature set from the file as a python file"
-    );
-
-    void (*init_val_ar_list)(py::list, py::list, int, int, bool) = &node_value_arrs::initialize_values_arr;
-    void (*init_val_ar_arr)(np::ndarray, np::ndarray, int, int, bool) = &node_value_arrs::initialize_values_arr;
-
-    void (*init_val_ar_list_no_params)(py::list, py::list, int, int) = &node_value_arrs::initialize_values_arr;
-    void (*init_val_ar_arr_no_params)(np::ndarray, np::ndarray, int, int) = &node_value_arrs::initialize_values_arr;
-
-    def(
-        "initialize_values_arr",
-        init_val_ar_list,
-        (arg("task_sz_train"), arg("task_sz_test"), arg("n_primary_feat"), arg("max_rung"), arg("use_params")),
-        "Initialize the node value arrays\nUsing the size of the initial feature space constructor the storage arrays\n\nArgs:\n    task_sz_train: (list): The number of training samples per task\n    task_sz_test: (list): The number of test sample per task\n    n_primary_feat: (int): The number of primary features\n    max_rung: (int): The maximum rung for all features\n    use_params: (bool): If true also initialize parameterized storage"
-    );
-    def(
-        "initialize_values_arr",
-        init_val_ar_arr,
-        (arg("task_sz_train"), arg("task_sz_test"), arg("n_primary_feat"), arg("max_rung"), arg("use_params")),
-        "Initialize the node value arrays\nUsing the size of the initial feature space constructor the storage arrays\n\nArgs:\n    task_sz_train: (np.ndarray): The number of training samples per task\n    task_sz_test: (np.ndarray): The number of test sample per task\n    n_primary_feat: (int): The number of primary features\n    max_rung: (int): The maximum rung for all features\n    use_params: (bool): If true also initialize parameterized storage"
-    );
-
-    def(
-        "initialize_values_arr",
-        init_val_ar_list_no_params,
-        (arg("task_sz_train"), arg("task_sz_test"), arg("n_primary_feat"), arg("max_rung")),
-        "Initialize the node value arrays\nUsing the size of the initial feature space constructor the storage arrays\n\nArgs:\n    task_sz_train (list): The number of training samples per task\n    task_sz_test (list): The number of test sample per task\n    n_primary_feat (int): The number of primary features\n    max_rung (int): The maximum rung for all features"
-    );
-
-    def(
-        "initialize_values_arr",
-        init_val_ar_arr_no_params,
-        (arg("task_sz_train"), arg("task_sz_test"), arg("n_primary_feat"), arg("max_rung")),
-        "Initialize the node value arrays\nUsing the size of the initial feature space constructor the storage arrays\n\nArgs:\n    task_sz_train (np.ndarray): The number of training samples per task\n    task_sz_test (np.ndarray): The number of test sample per task\n    n_primary_feat (int): The number of primary features\n    max_rung (int): The maximum rung for all features"
-    );
-
-    def(
-        "initialize_d_matrix_arr",
-        &node_value_arrs::initialize_d_matrix_arr,
-        "Initialize the descriptor matrix"
-    );
-
-    def(
-        "finalize_values_arr",
-        &node_value_arrs::finialize_values_arr,
-        "Resize all storage arrays to be empty"
-    );
-
-    def(
-        "matlabify",
-        &str_utils::matlabify,
-        (arg("str")),
-        "Convert a string into a matlab valid name\n\nArgs:\n    str: String to convert to a valid matlab name\n\nReturns:\n     The matlab safe version of the string"
-    );
-
-    #ifdef PARAMETERIZE
-        sisso::feature_creation::node::registerAddParamNode();
-        sisso::feature_creation::node::registerSubParamNode();
-        sisso::feature_creation::node::registerDivParamNode();
-        sisso::feature_creation::node::registerMultParamNode();
-        sisso::feature_creation::node::registerAbsDiffParamNode();
-        sisso::feature_creation::node::registerAbsParamNode();
-        sisso::feature_creation::node::registerInvParamNode();
-        sisso::feature_creation::node::registerLogParamNode();
-        sisso::feature_creation::node::registerExpParamNode();
-        sisso::feature_creation::node::registerNegExpParamNode();
-        sisso::feature_creation::node::registerSinParamNode();
-        sisso::feature_creation::node::registerCosParamNode();
-        sisso::feature_creation::node::registerCbParamNode();
-        sisso::feature_creation::node::registerCbrtParamNode();
-        sisso::feature_creation::node::registerSqParamNode();
-        sisso::feature_creation::node::registerSqrtParamNode();
-        sisso::feature_creation::node::registerSixPowParamNode();
-
-        sisso::feature_creation::nloptimizer::registerNLOptimizer();
-        sisso::feature_creation::nloptimizer::registerNLOptimizerClassification();
-        sisso::feature_creation::nloptimizer::registerNLOptimizerRegression();
-        sisso::feature_creation::nloptimizer::registerNLOptimizerLogRegression();
-
-        NLOptimizerRegression(*get_reg_optimizer_list_list)(py::list, py::list, int, int, double, bool) = &nlopt_wrapper::get_reg_optimizer;
-        NLOptimizerRegression(*get_reg_optimizer_list_arr)(py::list, np::ndarray, int, int, double, bool) = &nlopt_wrapper::get_reg_optimizer;
-        NLOptimizerRegression(*get_reg_optimizer_arr_list)(np::ndarray, py::list, int, int, double, bool) = &nlopt_wrapper::get_reg_optimizer;
-        NLOptimizerRegression(*get_reg_optimizer_arr_arr)(np::ndarray, np::ndarray, int, int, double, bool) = &nlopt_wrapper::get_reg_optimizer;
-
-        NLOptimizerLogRegression(*get_log_reg_optimizer_list_list)(py::list, py::list, int, int, double, bool) = &nlopt_wrapper::get_log_reg_optimizer;
-        NLOptimizerLogRegression(*get_log_reg_optimizer_list_arr)(py::list, np::ndarray, int, int, double, bool) = &nlopt_wrapper::get_log_reg_optimizer;
-        NLOptimizerLogRegression(*get_log_reg_optimizer_arr_list)(np::ndarray, py::list, int, int, double, bool) = &nlopt_wrapper::get_log_reg_optimizer;
-        NLOptimizerLogRegression(*get_log_reg_optimizer_arr_arr)(np::ndarray, np::ndarray, int, int, double, bool) = &nlopt_wrapper::get_log_reg_optimizer;
-
-        NLOptimizerClassification(*get_class_optimizer_list_list)(py::list, py::list, int, int, bool) = &nlopt_wrapper::get_class_optimizer;
-        NLOptimizerClassification(*get_class_optimizer_list_arr)(py::list, np::ndarray, int, int, bool) = &nlopt_wrapper::get_class_optimizer;
-        NLOptimizerClassification(*get_class_optimizer_arr_list)(np::ndarray, py::list, int, int, bool) = &nlopt_wrapper::get_class_optimizer;
-        NLOptimizerClassification(*get_class_optimizer_arr_arr)(np::ndarray, np::ndarray, int, int, bool) = &nlopt_wrapper::get_class_optimizer;
-
-        def("initialize_param_storage", &node_value_arrs::initialize_param_storage);
-
-        def("get_reg_optimizer", get_reg_optimizer_list_list, "@DocString_nlopt_wrapper_get_reg_optimizer_list_list");
-        def("get_reg_optimizer", get_reg_optimizer_list_arr, "@DocString_nlopt_wrapper_get_reg_optimizer_list_arr");
-        def("get_reg_optimizer", get_reg_optimizer_arr_list, "@DocString_nlopt_wrapper_get_reg_optimizer_arr_list");
-        def("get_reg_optimizer", get_reg_optimizer_arr_arr, "@DocString_nlopt_wrapper_get_reg_optimizer_arr_arr");
-
-        def("get_log_reg_optimizer", get_log_reg_optimizer_list_list, "@DocString_nlopt_wrapper_get_log_reg_optimizer_list_list");
-        def("get_log_reg_optimizer", get_log_reg_optimizer_list_arr, "@DocString_nlopt_wrapper_get_log_reg_optimizer_list_arr");
-        def("get_log_reg_optimizer", get_log_reg_optimizer_arr_list, "@DocString_nlopt_wrapper_get_log_reg_optimizer_arr_list");
-        def("get_log_reg_optimizer", get_log_reg_optimizer_arr_arr, "@DocString_nlopt_wrapper_get_log_reg_optimizer_arr_arr");
-
-        def("get_class_optimizer", get_class_optimizer_list_list, "@DocString_nlopt_wrapper_get_class_optimizer_list_list");
-        def("get_class_optimizer", get_class_optimizer_list_arr, "@DocString_nlopt_wrapper_get_class_optimizer_list_arr");
-        def("get_class_optimizer", get_class_optimizer_arr_list, "@DocString_nlopt_wrapper_get_class_optimizer_arr_list");
-        def("get_class_optimizer", get_class_optimizer_arr_arr, "@DocString_nlopt_wrapper_get_class_optimizer_arr_arr");
-    #endif
-}
-
-void sisso::registerInputs()
-{
-    class_<InputParser>(
-        "Inputs",
-        "A class that parses the input files and constructs the FeatureSpace",
-        init<>(arg("self"), "")
-    )
-        .def(init<std::string>((arg("self"), arg("filename")), ""))
-        .def(init<InputParser>((arg("self"), arg("o")), "Copy Constructor\n\nArgs:\n    o: InputParser to be copied"))
-        .def("clear_data", &InputParser::clear_data, (arg("self")), "Clear the data of the features/training data for CV calculations")
-        .add_property("sample_ids_train", &InputParser::sample_ids_train_py, &InputParser::set_sample_ids_train_py, "")
-        .add_property("sample_ids_test", &InputParser::sample_ids_test_py, &InputParser::set_sample_ids_test_py, "")
-        .add_property("task_names", &InputParser::task_names_py, &InputParser::set_task_names_py, "")
-        .add_property("allowed_param_ops", &InputParser::allowed_param_ops_py, &InputParser::set_allowed_param_ops_py, "")
-        .add_property("allowed_ops", &InputParser::allowed_ops_py, &InputParser::set_allowed_ops_py, "")
-        .add_property("prop_train", &InputParser::prop_train_arr, &InputParser::set_prop_train_arr, "")
-        .add_property("prop_test", &InputParser::prop_test_arr, &InputParser::set_prop_test_arr, "")
-        .add_property("leave_out_inds", &InputParser::leave_out_inds_py, &InputParser::set_leave_out_inds_py, "")
-        .add_property("task_sizes_train", &InputParser::task_sizes_train_py, &InputParser::set_task_sizes_train_py, "")
-        .add_property("task_sizes_test", &InputParser::task_sizes_test_py, &InputParser::set_task_sizes_test_py, "")
-        .add_property("phi_0", &InputParser::phi_0_py, &InputParser::set_phi_0_py, "")
-        .add_property("prop_unit", &InputParser::prop_unit, &InputParser::set_prop_unit, "")
-        .add_property("filename", &InputParser::filename, &InputParser::set_filename, "")
-        .add_property("data_file", &InputParser::data_file, &InputParser::set_data_file, "")
-        .add_property("prop_key", &InputParser::prop_key, &InputParser::set_prop_key, "")
-        .add_property("prop_label", &InputParser::prop_label, &InputParser::set_prop_label, "")
-        .add_property("task_key", &InputParser::task_key, &InputParser::set_task_key, "")
-        .add_property("calc_type", &InputParser::calc_type, &InputParser::set_calc_type, "")
-        .add_property("cross_cor_max", &InputParser::cross_cor_max, &InputParser::set_cross_cor_max, "")
-        .add_property("l_bound", &InputParser::l_bound, &InputParser::set_l_bound, "")
-        .add_property("u_bound", &InputParser::u_bound, &InputParser::set_u_bound, "")
-        .add_property("n_dim", &InputParser::n_dim, &InputParser::set_n_dim, "")
-        .add_property("max_rung", &InputParser::max_rung, &InputParser::set_max_rung, "")
-        .add_property("n_rung_store", &InputParser::n_rung_store, &InputParser::set_n_rung_store, "")
-        .add_property("n_rung_generate", &InputParser::n_rung_generate, &InputParser::set_n_rung_generate, "")
-        .add_property("n_sis_select", &InputParser::n_sis_select, &InputParser::set_n_sis_select, "")
-        .add_property("n_samp", &InputParser::n_samp, "")
-        .add_property("n_samp_train", &InputParser::n_samp_train, "")
-        .add_property("n_samp_test", &InputParser::n_samp_test, "")
-        .add_property("n_residual", &InputParser::n_residual, &InputParser::set_n_residual, "")
-        .add_property("n_models_store", &InputParser::n_models_store, &InputParser::set_n_models_store, "")
-        .add_property("max_param_depth", &InputParser::max_param_depth, &InputParser::set_max_param_depth, "")
-        .add_property("nlopt_seed", &InputParser::nlopt_seed, &InputParser::set_nlopt_seed, "")
-        .add_property("fix_intercept", &InputParser::fix_intercept, &InputParser::set_fix_intercept, "")
-        .add_property("global_param_opt", &InputParser::global_param_opt, &InputParser::set_global_param_opt, "")
-        .add_property("reparam_residual", &InputParser::reparam_residual, &InputParser::set_reparam_residual, "")
-    ;
-}
-
-void sisso::feature_creation::registerFeatureSpace()
-{
-    void (FeatureSpace::*sis_list)(list) = &FeatureSpace::sis;
-    void (FeatureSpace::*sis_ndarray)(np::ndarray) = &FeatureSpace::sis;
-
-    class_<FeatureSpace>(
-        "FeatureSpace",
-        "Feature Space for SISSO calculations. It stores and performs all actions on the feature space for SISSO.",
-        init<InputParser>(
-            (
-                arg("self"),
-                arg("inputs")
-            ),
-            "Construct a FeatureSpace using an InputParser object\n\nArgs:\n    inputs: InputParser object used to build the FeatureSpace"
-        )
-    )
-        .def(
-            init<std::string, list, list, list, optional<std::string, int, double>>(
-                (
-                    arg("self"),
-                    arg("feature_file"),
-                    arg("phi_0"),
-                    arg("prop"),
-                    arg("task_sizes"),
-                    arg("project_type")="regression",
-                    arg("n_sis_select")=1,
-                    arg("cross_corr_max")=1.0
-                ),
-                "FeatureSpace constructor that uses a file containing postfix feature expressions to describe all features in Phi, and a primary feature setn <python/feature_creation/FeatureSpace.cpp>)\n\nArgs:\n    feature_file (str): The file containing the postfix expressions of all features in the FeatureSpace\n    phi_0 (list): The set of primary features\n    prop (list): List containing the property vector (training data only)\n    task_sizes_train (list): The number of samples in the training data per task\n    project_type (str): The type of loss function/projection operator to use\n    n_sis_select (int): The number of features to select during each SIS step\n    cross_corr_max (double): The maximum allowed cross-correlation value between selected features"
-            )
-        )
-        .def(
-            init<std::string, list, np::ndarray, list, optional<std::string, int, double>>(
-                (
-                    arg("self"),
-                    arg("feature_file"),
-                    arg("phi_0"),
-                    arg("prop"),
-                    arg("task_sizes"),
-                    arg("project_type")="regression",
-                    arg("n_sis_select")=1,
-                    arg("cross_corr_max")=1.0
-                ),
-                "FeatureSpace constructor that uses a file containing postfix feature expressions to describe all features in Phi, and a primary feature setn <python/feature_creation/FeatureSpace.cpp>)\n\nArgs:\n    feature_file (str): The file containing the postfix expressions of all features in the FeatureSpace\n    phi_0 (list): The set of primary features\n    prop (np.ndarray): List containing the property vector (training data only)\n    task_sizes_train (list): The number of samples in the training data per task\n    project_type (str): The type of loss function/projection operator to use\n    n_sis_select (int): The number of features to select during each SIS step\n    cross_corr_max (double): The maximum allowed cross-correlation value between selected features"
-            )
-        )
-        .def("sis", sis_list, (arg("self"), arg("prop")), "Perform Sure-Independence Screening over the FeatureSpace. The features are ranked using a projection operator constructed using _project_type and the Property vector\n\nArgs:\n    prop (list): List containing the property vector (training data only)")
-        .def("sis", sis_ndarray, (arg("self"), arg("prop")), "Perform Sure-Independence Screening over the FeatureSpace. The features are ranked using a projection operator constructed using _project_type and the Property vector\n\nArgs:\n    prop (np.ndarray): Array containing the property vector (training data only)")
-        .def("feat_in_phi", &FeatureSpace::feat_in_phi, (arg("self"), arg("ind")), "Is a feature in this process' _phi?\n\nArgs:\n    ind (int): The index of the feature\n\nReturns:\n     True if feature is in this rank's _phi")
-        .def("remove_feature", &FeatureSpace::remove_feature, (arg("self"), arg("ind")), "Remove a feature from phi\n\nArgs:\n    ind (int): index of feature to remove")
-        .def("get_feature", &FeatureSpace::get_feature, (arg("self"), arg("ind")), "Access the feature in _phi with an index ind\n\nArgs:\n    ind (int): The index of the feature to get\n\nReturns:\n     A ModelNode of the feature at index ind")
-        .add_property("phi_selected", &FeatureSpace::phi_selected_py, "A list containing all of the selected features")
-        .add_property("phi0", &FeatureSpace::phi0_py, "A list containing all features generated (Not including those created on the Fly during SIS)")
-        .add_property("phi", &FeatureSpace::phi_py, "A list containing all of the Primary features")
-        .add_property("scores", &FeatureSpace::scores_py, "An array of all stored projection scores from SIS")
-        .add_property("task_sizes_train", &FeatureSpace::task_sizes_train_py, "")
-        .add_property("allowed_ops", &FeatureSpace::allowed_ops_py, "The list of allowed operators")
-        .add_property("start_rung", &FeatureSpace::start_rung_py, "A list containing the index of the first feature of each rung in the feature space.")
-        .add_property("feature_space_file", &FeatureSpace::feature_space_file, "Filename of the file to output the computer readable representation of the selected features to")
-        .add_property("l_bound", &FeatureSpace::l_bound, "The mlower bound for the maximum absolute value of the features")
-        .add_property("u_bound", &FeatureSpace::u_bound, "The upper bound for the maximum absolute value of the features")
-        .add_property("max_rung", &FeatureSpace::max_rung, "The maximum rung for the feature creation")
-        .add_property("n_sis_select", &FeatureSpace::n_sis_select, "The number of features to select during each SIS iteration")
-        .add_property("n_samp_train", &FeatureSpace::n_samp_train, "")
-        .add_property("n_feat", &FeatureSpace::n_feat, "The total number of features in the feature space")
-        .add_property("n_rung_store", &FeatureSpace::n_rung_store, "The number of rungs to calculate and store the value of the features for all samples")
-        .add_property("n_rung_generate", &FeatureSpace::n_rung_generate, "Either 0 or 1, and is the number of rungs to generate on the fly during SIS")
-    ;
-}
-
-void sisso::feature_creation::registerUnit()
-{
-    class_<Unit>("Unit", "Class to define the units of the features\nFunction to serialize the data for MPI communication", init<>((arg("self")), "Base Constructor\nCreates a unit with no entries"))
-        .def(init<std::map<std::string, double>>((arg("self"), arg("dct")), "Constructor of the unit with the dictionary representation\n\nArgs:\n    dct: dictionary representation of the dictionary"))
-        .def(init<std::string>((arg("self"), arg("unit_str")), "Construct the unit based on a string representation of the unit\nTake a string representation of a unit, and build the Unit\n\nArgs:\n    unit_str: The string to build the unit"))
-        .def(init<Unit&>((arg("self"), arg("o")), "Copy Constructor\n\nArgs:\n    o: Unit to copy"))
-        .def("__str__", &Unit::toString, (arg("self")), "Convert the unit into a string")
-        .def("__repr__", &Unit::toString, (arg("self")), "Convert the unit into a string")
-        .def("inverse", &Unit::inverse, (arg("self")), "Inverse operator for units\n\nReturns:\n     The inverse of this unit")
-        .def(self * self)
-        .def(self / self)
-        .def(self *= self)
-        .def(self /= self)
-        .def(self == self)
-        .def(self != self)
-        .def("__pow__", &Unit::operator^, (arg("self"), arg("pow")), "Exponentiation operator for units\n\nArgs:\n    power: power to exponentiate the unit\n\nReturns:\n     The unit raised to the power")
-        .add_property("latex_str", &Unit::toLatexString, "Convert the unit into a latexified string")
-    ;
-}
-
-#ifdef PARAMETERIZE
-    void sisso::feature_creation::nloptimizer::registerNLOptimizer()
-    {
-        class_<sisso::feature_creation::nloptimizer::NLOptimizerWrap, boost::noncopyable>("NLOptimizer", "A wrapper to the NLopt library files", no_init)
-            .def("optimize_feature_params", &NLOptimizer::optimize_feature_params, (arg("self"), arg("feat")), "uses nlopt to optimize the parameters of a feature\n\nArgs:\n    feat: Pointer to the node to optimize")
-        ;
-    }
-    void sisso::feature_creation::nloptimizer::registerNLOptimizerClassification()
-    {
-        class_<NLOptimizerClassification, bases<NLOptimizer>>("NLOptimizerClassification", "The optimizer used for classification problems\nConstructor\n\nArgs:\n    task_sizes: Number of training samples per task\n    prop: The value of the property to evaluate the loss function against for the training set\n    n_rung: Maximum rung of the features\n    max_param_depth: The maximum depth in the binary expression tree to set non-linear optimization\n    reset_max_param_depth: If true reset the maximum parameter depth\n    local_opt_alg: Algorithm used for local optimization", no_init);
-    }
-    void sisso::feature_creation::nloptimizer::registerNLOptimizerRegression()
-    {
-        class_<NLOptimizerRegression, bases<NLOptimizer>>("NLOptimizerRegression", "The optimizer used for regression problems", no_init);
-    }
-    void sisso::feature_creation::nloptimizer::registerNLOptimizerLogRegression()
-    {
-        class_<NLOptimizerLogRegression, bases<NLOptimizer>>("NLOptimizerLogRegression", "The optimizer used for log regression problems", no_init);
-    }
-
-    void sisso::feature_creation::node::registerNode()
-    {
-        void (Node::*reindex_1)(unsigned long int) = &Node::reindex;
-        void (Node::*reindex_2)(unsigned long int, unsigned long int) = &Node::reindex;
-
-        class_<sisso::feature_creation::node::NodeWrap, boost::noncopyable>("Node", "Base class for a Node.\nThe class is used to describe a Node on a binary expression tree. Features defined as the root of the binary expression tree.", no_init)
-            .add_property("n_samp", &Node::n_samp, "The number of samples in the training set")
-            .add_property("n_samp_test", &Node::n_samp_test, "The number of samples in the test set")
-            .add_property("feat_ind", &Node::feat_ind, "The unique index ID for the feature")
-            .add_property("arr_ind", &Node::arr_ind, "The index that is used to access the data stored in the central data storage")
-            .add_property("selected", &Node::selected, &Node::set_selected, "True if the feature is selected")
-            .add_property("d_mat_ind", &Node::d_mat_ind, &Node::set_d_mat_ind, "The index used to access the data stored in the description matrix")
-            .add_property("value", &Node::value_py, "An array containing the values of the training set samples for the feature")
-            .add_property("test_value", &Node::test_value_py, "An array containing the values of the test set samples for the feature")
-            .add_property("primary_feat_decomp", &Node::primary_feature_decomp_py, "The decomposition of the primary features and how often they appear in the feature")
-            .add_property("postfix_expr", &Node::postfix_expr, "A computer readable representation of the feature. Primary features represented by their index in phi_0, node types are represented by abbreviations, and the order is the same as the postfix representation of the expression")
-            .add_property("latex_expr", &Node::latex_expr, "The valid LaTeX expression that represents the feature")
-            .add_property("parameters", &Node::parameters_py, "A list containing all scale and bias terms for this Node")
-            .def("reindex", reindex_1, (arg("self"), arg("feat_ind")), "Reset _feat_ind and _arr_ind to ind\n\nArgs:\n    ind (int): the new value of _feat_ind and _arr_ind")
-            .def("reindex", reindex_2, (arg("self"), arg("feat_ind"), arg("arr_ind")), "Reset _feat_ind and _arr_ind to feat_ind and arr_ind, respectively\n\nArgs:\n    feat_ind (int): the new value of _feat_ind\n    arr_ind (int): the new value of _arr_ind")
-            .def("unit", pure_virtual(&Node::unit), (arg("self")), "The unit of the feature (Derived recursively from the primary features and operators)")
-            .def("is_nan", pure_virtual(&Node::is_nan), (arg("self")), "Check if the feature has a NaN value in it\n\nReturns:\n     True if one of the values of the feature is a NaN")
-            .def("is_const", pure_virtual(&Node::is_const), (arg("self")), "Check if feature is constant for one of the tasks\n\nReturns:\n     True if the feature is constant for all samples in any task")
-            .def("rung", pure_virtual(&Node::rung), (arg("self"), arg("cur_rung")), "Return the rung of the feature (Height of the binary expression tree - 1)\n\nArgs:\n    cur_rung (int): A recursive helper counter for the rung")
-            .def("n_feats", pure_virtual(&Node::n_feats), (arg("self")), "The number of features used for an operator (Number of child node)\n\nReturns:\n     The number of features the operator is acting on (Number of child node)")
-            .def("feat", pure_virtual(&Node::feat), (arg("self"), arg("feat_ind")), "Return the ind^th feature stored by an operator node\n\nArgs:\n    ind (int): the index of the feats list to be accessed\n\nReturns:\n     The feature stored in _feats[ind]")
-            .def("n_leaves", pure_virtual(&Node::n_leaves), (arg("self"), arg("cur_n_leaves")), "The number of primary features (non-unique) this feature contains (The number of leaves of the Binary Expression Tree)\n\nArgs:\n    cur_n_leaves (int): A recurisve counting variable\n\nReturns:\n     The number of leaves of the Binary Expression Tree")
-            .def("x_in_expr_list", pure_virtual(&Node::get_x_in_expr_list), (arg("self")), "A vector storing the expressions for all primary features in the order they appear in the postfix expression")
-        ;
-    }
-#else
-    void sisso::feature_creation::node::registerNode()
-    {
-        void (Node::*reindex_1)(unsigned long int) = &Node::reindex;
-        void (Node::*reindex_2)(unsigned long int, unsigned long int) = &Node::reindex;
-        class_<sisso::feature_creation::node::NodeWrap, boost::noncopyable>("Node", "Base class for a Node.\nThe class is used to describe a Node on a binary expression tree. Features defined as the root of the binary expression tree.", no_init)
-            .add_property("n_samp", &Node::n_samp, "The number of samples in the training set")
-            .add_property("n_samp_test", &Node::n_samp_test, "The number of samples in the test set")
-            .add_property("feat_ind", &Node::feat_ind, "The unique index ID for the feature")
-            .add_property("arr_ind", &Node::arr_ind, "The index that is used to access the data stored in the central data storage")
-            .add_property("selected", &Node::selected, &Node::set_selected, "")
-            .add_property("d_mat_ind", &Node::d_mat_ind, &Node::set_d_mat_ind, "")
-            .add_property("value", &Node::value_py, "An array containing the values of the training set samples for the feature")
-            .add_property("test_value", &Node::test_value_py, "An array containing the values of the test set samples for the feature")
-            .add_property("primary_feat_decomp", &Node::primary_feature_decomp_py, "The decomposition of the primary features and how often they appear in the feature")
-            .add_property("postfix_expr", &Node::postfix_expr, "A computer readable representation of the feature. Primary features represented by their index in phi_0, node types are represented by abbreviations, and the order is the same as the postfix representation of the expression")
-            .add_property("latex_expr", &Node::latex_expr, "The valid LaTeX expression that represents the feature")
-            .def("reindex", reindex_1, (arg("self"), arg("feat_ind")), "Reset _feat_ind and _arr_ind to ind\n\nArgs:\n    ind (int): the new value of _feat_ind and _arr_ind")
-            .def("reindex", reindex_2, (arg("self"), arg("feat_ind"), arg("arr_ind")), "Reset _feat_ind and _arr_ind to feat_ind and arr_ind, respectively\n\nArgs:\n    feat_ind (int): the new value of _feat_ind\n    arr_ind (int): the new value of _arr_ind")
-            .def("unit", pure_virtual(&Node::unit), (arg("self")), "The unit of the feature (Derived recursively from the primary features and operators)")
-            .def("is_nan", pure_virtual(&Node::is_nan), (arg("self")), "Check if the feature has a NaN value in it\n\nReturns:\n     True if one of the values of the feature is a NaN")
-            .def("is_const", pure_virtual(&Node::is_const), (arg("self")), "Check if feature is constant for one of the tasks\n\nReturns:\n     True if the feature is constant for all samples in any task")
-            .def("rung", pure_virtual(&Node::rung), (arg("self"), arg("cur_rung")), "Return the rung of the feature (Height of the binary expression tree - 1)\n\nArgs:\n    cur_rung (int): A recursive helper counter for the rung")
-            .def("n_feats", pure_virtual(&Node::n_feats), (arg("self")), "The number of features used for an operator (Number of child node)\n\nReturns:\n     The number of features the operator is acting on (Number of child node)")
-            .def("feat", pure_virtual(&Node::feat), (arg("self"), arg("feat_ind")), "Return the ind^th feature stored by an operator node\n\nArgs:\n    ind (int): the index of the feats list to be accessed\n\nReturns:\n     The feature stored in _feats[ind]")
-            .def("n_leaves", pure_virtual(&Node::n_leaves), (arg("self"), arg("cur_n_leaves")), "The number of primary features (non-unique) this feature contains (The number of leaves of the Binary Expression Tree)\n\nArgs:\n    cur_n_leaves (int): A recurisve counting variable\n\nReturns:\n     The number of leaves of the Binary Expression Tree")
-            .def("x_in_expr_list", pure_virtual(&Node::get_x_in_expr_list), (arg("self")), "A vector storing the expressions for all primary features in the order they appear in the postfix expression")
-        ;
-    }
-#endif
-
-void sisso::feature_creation::node::registerFeatureNode()
-{
-    void (FeatureNode::*set_value_no_param)(int, bool) const = &FeatureNode::set_value;
-    void (FeatureNode::*set_test_value_no_param)(int, bool) const = &FeatureNode::set_test_value;
-    std::string (FeatureNode::*expr_no_param)() const = &FeatureNode::expr;
-
-    using namespace boost::python;
-    class_<FeatureNode, bases<Node>>(
-        "FeatureNode",
-        "Node that describe the leaves of the operator graph (Primary features in Phi_0)",
-        init<int, std::string, np::ndarray, np::ndarray, Unit>(
-            (arg("self"), arg("feat_ind"), arg("expr"), arg("value"), arg("test_value"), arg("unit")),
-            "Constructs a feature node using numpy arrays (cpp definition in python/feature_creation/FeatureNode.cpp)\n\nArgs:\n    feat_ind (int): The index of the feature\n    expr (str): Expression for the feature\n    value (np.ndarray): The value for this feature's training data\n    test_value (np.ndarray): The value for this feature's test data\n    unit (Unit): Unit of the feature"
-        )
-    )
-        .def(
-            init<int, std::string, py::list, py::list, Unit>(
-                (arg("self"), arg("feat_ind"), arg("expr"), arg("value"), arg("test_value"), arg("unit")),
-                "Constructs a feature node using Python lists (cpp definition in python/feature_creation/FeatureNode.cpp)\n\nArgs:\n    feat_ind (int): The index of the feature\n    expr (str): Expression for the feature\n    value (list): The value for this feature's training data\n    test_value (list): The value for this feature's test data\n    unit (Unit): Unit of the feature"
-            )
-        )
-        .def("is_nan", &FeatureNode::is_nan, (arg("self")), "Check if the feature has a NaN value in it\n\nReturns:\n     True if one of the values of the feature is a NaN")
-        .def("is_const", &FeatureNode::is_const, (arg("self")), "Check if feature is constant for one of the tasks\n\nReturns:\n     True if the feature is constant for all samples in any task")
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &FeatureNode::unit, "The unit of the primary feature")
-        .add_property("rung", &FeatureNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-        .add_property("n_leaves", &FeatureNode::n_leaves, "Get the number of primary features (non-unique) this feature contains (The number of leaves of the Binary Expression Tree)")
-        .add_property("x_in_expr_list", &FeatureNode::get_x_in_expr_list, "A vector storing the expressions for all primary features in the order they appear in the postfix expression")
-    ;
-}
-
-void sisso::feature_creation::node::registerModelNode()
-{
-    np::ndarray (ModelNode::*eval_many_dict)(py::dict) = &ModelNode::eval_many_py;
-    np::ndarray (ModelNode::*eval_many_ndarr)(np::ndarray) = &ModelNode::eval_many_py;
-
-    double (ModelNode::*eval_ndarr)(np::ndarray) = &ModelNode::eval_py;
-    double (ModelNode::*eval_list)(py::list) = &ModelNode::eval_py;
-    double (ModelNode::*eval_dict)(py::dict) = &ModelNode::eval_py;
-
-    using namespace boost::python;
-    class_<ModelNode, bases<FeatureNode>>(
-        "ModelNode",
-        "Nodes that are used to describe the features passed to a Model",
-        init<int, int, std::string, std::string, std::string, std::string, py::list, py::list, py::list, Unit>(
-            (arg("self"), arg("feat_ind"), arg("rung"), arg("expr"), arg("latex_expr"), arg("postfix_expr"), arg("matlab_fxn_expr"), arg("value"), arg("test_value"), arg("x_in_expr_list"), arg("unit")),
-            "Constructs a feature node\n\nArgs:\n    feat_ind:  (int)The index of the feature\n    rung (int): the rung of the feature\n    expr (str): Expression for the feature\n    latex_expr (str): Get the valid LaTeX expression that represents the feature for the feature\n    postfix_expr (str): A computer readable representation of the feature. Primary features represented by their index in phi_0, node types are represented by abbreviations, and the order is the same as the postfix representation of the expression\n    matlab_fxn_expr (str): The code to evaluate the feature in matlab\n    value (list): The value for this feature's training data\n    test_value (list): The value for this feature's test data\n    x_in_expr_list (list): vector storing the expressions for all primary features that show up in feature in the order they appear in the postfix notation\n    unit (Unit): Unit of the feature"
-        )
-    )
-        .def(
-            init<int, int, std::string, std::string, std::string, std::string, np::ndarray, np::ndarray, py::list, Unit>(
-                (arg("self"), arg("feat_ind"), arg("rung"), arg("expr"), arg("latex_expr"), arg("postfix_expr"), arg("matlab_fxn_expr"), arg("value"), arg("test_value"), arg("x_in_expr_list"), arg("unit")),
-                "Constructs a feature node\n\nArgs:\n    feat_ind:  (int)The index of the feature\n    rung (int): the rung of the feature\n    expr (str): Expression for the feature\n    latex_expr (str): Get the valid LaTeX expression that represents the feature for the feature\n    postfix_expr (str): A computer readable representation of the feature. Primary features represented by their index in phi_0, node types are represented by abbreviations, and the order is the same as the postfix representation of the expression\n    matlab_fxn_expr (str): The code to evaluate the feature in matlab\n    value (np.ndarray): The value for this feature's training data\n    test_value (np.ndarray): The value for this feature's test data\n    x_in_expr_list (np.ndarray): vector storing the expressions for all primary features that show up in feature in the order they appear in the postfix notation\n    unit (Unit): Unit of the feature"
-            )
-        )
-        .def(init<node_ptr>((arg("self"), arg("in_node")), "Copy constructor from general node_ptr\n\nArgs:\n    in_node (Node): Node to be copied"))
-        .def("is_nan", &ModelNode::is_nan, (arg("self")), "Check if the feature has a NaN value in it\n\nReturns:\n     True if one of the values of the feature is a NaN")
-        .def("is_const", &ModelNode::is_const, (arg("self")), "Check if feature is constant for one of the tasks\n\nReturns:\n     True if the feature is constant for all samples in any task")
-        .def("set_value", &ModelNode::set_value, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage arrays\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", &ModelNode::set_test_value, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("eval_many", eval_many_dict, (arg("self"), arg("x_in")), "Evaluate the model for a set of new points\n\nArgs:\n    x_in (dict): The set of data points to evaluate the model. Keys must be strings representing feature expressions and vectors must be the same length\n\nReturns:\n     The prediction of the model for a given data point")
-        .def("eval_many", eval_many_ndarr, (arg("self"), arg("x_in")), "Evaluate the model for a set of new points\n\nArgs:\n    x_in (np.ndarray): The set data for a set of new data points (size of n_feature x n_points, and order the same as appending the results of _feats[nn]->get_x_in_expr_list() for all feature)\n\nReturns:\n     The prediction of the model for a given data point")
-        .def("eval", eval_ndarr, (arg("self"), arg("x_in")), "Evaluate the model for a new point\n\nArgs:\n    x_in (np.ndarray): The data point to evaluate the model (order the same as appending the results of _feats[nn]->get_x_in_expr_list() for all feature)\n\nReturns:\n     The prediction of the model for a given data point")
-        .def("eval", eval_list, (arg("self"), arg("x_in")), "Evaluate the model for a new point\n\nArgs:\n    x_in (list): The data point to evaluate the model (order the same as appending the results of _feats[nn]->get_x_in_expr_list() for all feature)\n\nReturns:\n     The prediction of the model for a given data point")
-        .def("eval", eval_dict, (arg("self"), arg("x_in")), "Evaluate the model for a new point\n\nArgs:\n    x_in (dict): Dictionary describing the new point (\"feature expr\": value)\n\nReturns:\n     The prediction of the model for a given data point")
-        .add_property("rung", &ModelNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-        .add_property("n_leaves", &ModelNode::n_leaves, "The number of primary features (non-unique) this feature contains (The number of leaves of the Binary Expression Tree)\n\nArgs:\n    cur_n_leaves (int): A recurisve counting variable\n\nReturns:\n     The number of leaves of the Binary Expression Tree")
-        .add_property("x_in_expr_list", &ModelNode::x_in_expr_list_py, "A vector storing the expressions for all primary features in the order they appear in the postfix expression")
-    ;
-}
-
-void sisso::feature_creation::node::registerAddNode()
-{
-    void (AddNode::*set_value_no_param)(int, bool) const = &AddNode::set_value;
-    void (AddNode::*set_test_value_no_param)(int, bool) const = &AddNode::set_test_value;
-    std::string (AddNode::*expr_no_param)() const = &AddNode::expr;
-
-    class_<AddNode, bases<OperatorNode<2>>>(
-        "AddNode",
-        "Node for the addition operator",
-        init<node_ptr, node_ptr, int, double, double>(
-            (arg("self"), arg("feat_1"), arg("feat_2"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat_1 (Node): shared_ptr of the first feature to operate on (A)\n    feat_2 (Node): shared_ptr of the second feature to operate on (B)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the test value for the feature inside of the value storage arrays\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &AddNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &AddNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-
-    ;
-}
-
-void sisso::feature_creation::node::registerSubNode()
-{
-    void (SubNode::*set_value_no_param)(int, bool) const = &SubNode::set_value;
-    void (SubNode::*set_test_value_no_param)(int, bool) const = &SubNode::set_test_value;
-    std::string (SubNode::*expr_no_param)() const = &SubNode::expr;
-
-    class_<SubNode, bases<OperatorNode<2>>>(
-        "SubNode",
-        "Node for the subtraction operator",
-        init<node_ptr, node_ptr, int, double, double>(
-            (arg("self"), arg("feat_1"), arg("feat_2"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat_1 (Node): shared_ptr of the first feature to operate on (A)\n    feat_2 (Node): shared_ptr of the second feature to operate on (B)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &SubNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &SubNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerDivNode()
-{
-    void (DivNode::*set_value_no_param)(int, bool) const = &DivNode::set_value;
-    void (DivNode::*set_test_value_no_param)(int, bool) const = &DivNode::set_test_value;
-    std::string (DivNode::*expr_no_param)() const = &DivNode::expr;
-
-    class_<DivNode, bases<OperatorNode<2>>>(
-        "DivNode",
-        "Node for the division operator",
-        init<node_ptr, node_ptr, int, double, double>(
-            (arg("self"), arg("feat_1"), arg("feat_2"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor\nConstructs the Node from node pointer of the features to operate on\n\nArgs:\n    feat_1 (Node): shared_ptr of the first feature to operate on (A)\n    feat_1: shared_ptr of the second feature to operate on (B)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &DivNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &DivNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerMultNode()
-{
-    void (MultNode::*set_value_no_param)(int, bool) const = &MultNode::set_value;
-    void (MultNode::*set_test_value_no_param)(int, bool) const = &MultNode::set_test_value;
-    std::string (MultNode::*expr_no_param)() const = &MultNode::expr;
-
-    class_<MultNode, bases<OperatorNode<2>>>(
-        "MultNode",
-        "Node for the multiplication operator",
-        init<node_ptr, node_ptr, int, double, double>(
-            (arg("self"), arg("feat_1"), arg("feat_2"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat_1 (Node): shared_ptr of the first feature to operate on (A)\n    feat_2 (Node): shared_ptr of the second feature to operate on (B)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &MultNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &MultNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerAbsDiffNode()
-{
-    void (AbsDiffNode::*set_value_no_param)(int, bool) const = &AbsDiffNode::set_value;
-    void (AbsDiffNode::*set_test_value_no_param)(int, bool) const = &AbsDiffNode::set_test_value;
-    std::string (AbsDiffNode::*expr_no_param)() const = &AbsDiffNode::expr;
-
-    class_<AbsDiffNode, bases<OperatorNode<2>>>(
-        "AbsDiffNode",
-        "Node for the absolute difference operator",
-        init<node_ptr, node_ptr, int, double, double>(
-            (arg("self"), arg("feat_1"), arg("feat_2"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat_1 (Node): shared_ptr of the first feature to operate on (A)\n    feat_2 (Node): shared_ptr of the second feature to operate on (B)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &AbsDiffNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &AbsDiffNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerAbsNode()
-{
-    void (AbsNode::*set_value_no_param)(int, bool) const = &AbsNode::set_value;
-    void (AbsNode::*set_test_value_no_param)(int, bool) const = &AbsNode::set_test_value;
-    std::string (AbsNode::*expr_no_param)() const = &AbsNode::expr;
-
-    class_<AbsNode, bases<OperatorNode<1>>>(
-        "AbsNode",
-        "Node for the absolute value operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &AbsNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &AbsNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerInvNode()
-{
-    void (InvNode::*set_value_no_param)(int, bool) const = &InvNode::set_value;
-    void (InvNode::*set_test_value_no_param)(int, bool) const = &InvNode::set_test_value;
-    std::string (InvNode::*expr_no_param)() const = &InvNode::expr;
-
-    class_<InvNode, bases<OperatorNode<1>>>(
-        "InvNode",
-        "Node for the inverse operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor without checking feature values\nConstructs the Node from node pointer of the feature to operate on\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &InvNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &InvNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerLogNode()
-{
-    void (LogNode::*set_value_no_param)(int, bool) const = &LogNode::set_value;
-    void (LogNode::*set_test_value_no_param)(int, bool) const = &LogNode::set_test_value;
-    std::string (LogNode::*expr_no_param)() const = &LogNode::expr;
-
-    class_<LogNode, bases<OperatorNode<1>>>(
-        "LogNode",
-        "Node for the logarithm operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &LogNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &LogNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerExpNode()
-{
-    void (ExpNode::*set_value_no_param)(int, bool) const = &ExpNode::set_value;
-    void (ExpNode::*set_test_value_no_param)(int, bool) const = &ExpNode::set_test_value;
-    std::string (ExpNode::*expr_no_param)() const = &ExpNode::expr;
-
-    class_<ExpNode, bases<OperatorNode<1>>>(
-        "ExpNode",
-        "Node for the exponential operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &ExpNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &ExpNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerNegExpNode()
-{
-    void (NegExpNode::*set_value_no_param)(int, bool) const = &NegExpNode::set_value;
-    void (NegExpNode::*set_test_value_no_param)(int, bool) const = &NegExpNode::set_test_value;
-    std::string (NegExpNode::*expr_no_param)() const = &NegExpNode::expr;
-
-    class_<NegExpNode, bases<OperatorNode<1>>>(
-        "NegExpNode",
-        "Node for the negative exponential operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &NegExpNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &NegExpNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerSinNode()
-{
-    void (SinNode::*set_value_no_param)(int, bool) const = &SinNode::set_value;
-    void (SinNode::*set_test_value_no_param)(int, bool) const = &SinNode::set_test_value;
-    std::string (SinNode::*expr_no_param)() const = &SinNode::expr;
-
-    class_<SinNode, bases<OperatorNode<1>>>(
-        "SinNode",
-        "Node for the sine operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &SinNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &SinNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerCosNode()
-{
-    void (CosNode::*set_value_no_param)(int, bool) const = &CosNode::set_value;
-    void (CosNode::*set_test_value_no_param)(int, bool) const = &CosNode::set_test_value;
-    std::string (CosNode::*expr_no_param)() const = &CosNode::expr;
-
-    class_<CosNode, bases<OperatorNode<1>>>(
-        "CosNode",
-        "Node for the cosine operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &CosNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &CosNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerCbNode()
-{
-    void (CbNode::*set_value_no_param)(int, bool) const = &CbNode::set_value;
-    void (CbNode::*set_test_value_no_param)(int, bool) const = &CbNode::set_test_value;
-    std::string (CbNode::*expr_no_param)() const = &CbNode::expr;
-
-    class_<CbNode, bases<OperatorNode<1>>>(
-        "CbNode",
-        "Node for the cube operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &CbNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &CbNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerCbrtNode()
-{
-    void (CbrtNode::*set_value_no_param)(int, bool) const = &CbrtNode::set_value;
-    void (CbrtNode::*set_test_value_no_param)(int, bool) const = &CbrtNode::set_test_value;
-    std::string (CbrtNode::*expr_no_param)() const = &CbrtNode::expr;
-
-    class_<CbrtNode, bases<OperatorNode<1>>>(
-        "CbrtNode",
-        "Node for the cube root operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &CbrtNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &CbrtNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerSqNode()
-{
-    void (SqNode::*set_value_no_param)(int, bool) const = &SqNode::set_value;
-    void (SqNode::*set_test_value_no_param)(int, bool) const = &SqNode::set_test_value;
-    std::string (SqNode::*expr_no_param)() const = &SqNode::expr;
-
-    class_<SqNode, bases<OperatorNode<1>>>(
-        "SqNode",
-        "Node for the square operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &SqNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &SqNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerSqrtNode()
-{
-    void (SqrtNode::*set_value_no_param)(int, bool) const = &SqrtNode::set_value;
-    void (SqrtNode::*set_test_value_no_param)(int, bool) const = &SqrtNode::set_test_value;
-    std::string (SqrtNode::*expr_no_param)() const = &SqrtNode::expr;
-
-    class_<SqrtNode, bases<OperatorNode<1>>>(
-        "SqrtNode",
-        "Node for the square root operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &SqrtNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &SqrtNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-
-void sisso::feature_creation::node::registerSixPowNode()
-{
-    void (SixPowNode::*set_value_no_param)(int, bool) const = &SixPowNode::set_value;
-    void (SixPowNode::*set_test_value_no_param)(int, bool) const = &SixPowNode::set_test_value;
-    std::string (SixPowNode::*expr_no_param)() const = &SixPowNode::expr;
-
-    class_<SixPowNode, bases<OperatorNode<1>>>(
-        "SixPowNode",
-        "Node for the sixth power operator",
-        init<node_ptr, int, double, double>(
-            (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-            "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-        )
-    )
-        .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-        .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-        .add_property("unit", &SixPowNode::unit, "Get the unit of the feature (combine the units of _feats)")
-        .add_property("rung", &SixPowNode::rung, "return the rung of the feature (Height of the binary expression tree - 1)")
-    ;
-}
-#ifdef PARAMETERIZE
-    void sisso::feature_creation::node::registerAddParamNode()
-    {
-        void (AddParamNode::*set_value_no_param)(int, bool) const = &AddParamNode::set_value;
-        void (AddParamNode::*set_test_value_no_param)(int, bool) const = &AddParamNode::set_test_value;
-        std::string (AddParamNode::*expr_no_param)() const = &AddParamNode::expr;
-
-        class_<AddParamNode, bases<AddNode>>(
-            "AddParamNode",
-            "",
-            init<node_ptr, node_ptr, int, double, double>(
-                (arg("self"), arg("feat_1"), arg("feat_2"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &AddParamNode::unit, "")
-            // .add_property("rung", &AddParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerSubParamNode()
-    {
-        void (SubParamNode::*set_value_no_param)(int, bool) const = &SubParamNode::set_value;
-        void (SubParamNode::*set_test_value_no_param)(int, bool) const = &SubParamNode::set_test_value;
-        std::string (SubParamNode::*expr_no_param)() const = &SubParamNode::expr;
-
-        class_<SubParamNode, bases<SubNode>>(
-            "SubParamNode",
-            "Node for the parameterized subtraction operator",
-            init<node_ptr, node_ptr, int, double, double>(
-                (arg("self"), arg("feat_1"), arg("feat_2"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor\n\nArgs:\n    feat_1 (Node): shared_ptr of the feature to operate on (A)\n    feat_2 (Node): shared_ptr of the feature to operate on (B)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &SubParamNode::unit, "")
-            // .add_property("rung", &SubParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerDivParamNode()
-    {
-        void (DivParamNode::*set_value_no_param)(int, bool) const = &DivParamNode::set_value;
-        void (DivParamNode::*set_test_value_no_param)(int, bool) const = &DivParamNode::set_test_value;
-        std::string (DivParamNode::*expr_no_param)() const = &DivParamNode::expr;
-
-        class_<DivParamNode, bases<DivNode>>(
-            "DivParamNode",
-            "Node for the parameterized division operator",
-            init<node_ptr, node_ptr, int, double, double>(
-                (arg("self"), arg("feat_1"), arg("feat_2"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &DivParamNode::unit, "")
-            // .add_property("rung", &DivParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerMultParamNode()
-    {
-        void (MultParamNode::*set_value_no_param)(int, bool) const = &MultParamNode::set_value;
-        void (MultParamNode::*set_test_value_no_param)(int, bool) const = &MultParamNode::set_test_value;
-        std::string (MultParamNode::*expr_no_param)() const = &MultParamNode::expr;
-
-        class_<MultParamNode, bases<MultNode>>(
-            "MultParamNode",
-            "Node for the parameterized multiplication operator",
-            init<node_ptr, node_ptr, int, double, double>(
-                (arg("self"), arg("feat_1"), arg("feat_2"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &MultParamNode::unit, "")
-            // .add_property("rung", &MultParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerAbsDiffParamNode()
-    {
-        void (AbsDiffParamNode::*set_value_no_param)(int, bool) const = &AbsDiffParamNode::set_value;
-        void (AbsDiffParamNode::*set_test_value_no_param)(int, bool) const = &AbsDiffParamNode::set_test_value;
-        std::string (AbsDiffParamNode::*expr_no_param)() const = &AbsDiffParamNode::expr;
-
-        class_<AbsDiffParamNode, bases<AbsDiffNode>>(
-            "AbsDiffParamNode",
-            "Node for the parameterized absolute difference operator",
-            init<node_ptr, node_ptr, int, double, double>(
-                (arg("self"), arg("feat_1"), arg("feat_2"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor\n\nArgs:\n    feat_1 (Node): shared_ptr of the feature to operate on (A)\n    feat_2 (Node): shared_ptr of the feature to operate on (B)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &AbsDiffParamNode::unit, "")
-            // .add_property("rung", &AbsDiffParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerAbsParamNode()
-    {
-        void (AbsParamNode::*set_value_no_param)(int, bool) const = &AbsParamNode::set_value;
-        void (AbsParamNode::*set_test_value_no_param)(int, bool) const = &AbsParamNode::set_test_value;
-        std::string (AbsParamNode::*expr_no_param)() const = &AbsParamNode::expr;
-
-        class_<AbsParamNode, bases<AbsNode>>(
-            "AbsParamNode",
-            "Node for the parameterized absolute value operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &AbsParamNode::unit, "")
-            // .add_property("rung", &AbsParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerInvParamNode()
-    {
-        void (InvParamNode::*set_value_no_param)(int, bool) const = &InvParamNode::set_value;
-        void (InvParamNode::*set_test_value_no_param)(int, bool) const = &InvParamNode::set_test_value;
-        std::string (InvParamNode::*expr_no_param)() const = &InvParamNode::expr;
-
-        class_<InvParamNode, bases<InvNode>>(
-            "InvParamNode",
-            "Node for the parameterized inverse operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &InvParamNode::unit, "")
-            // .add_property("rung", &InvParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerLogParamNode()
-    {
-        void (LogParamNode::*set_value_no_param)(int, bool) const = &LogParamNode::set_value;
-        void (LogParamNode::*set_test_value_no_param)(int, bool) const = &LogParamNode::set_test_value;
-        std::string (LogParamNode::*expr_no_param)() const = &LogParamNode::expr;
-
-        class_<LogParamNode, bases<LogNode>>(
-            "LogParamNode",
-            "Node for the parameterized logarithm operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &LogParamNode::unit, "")
-            // .add_property("rung", &LogParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerExpParamNode()
-    {
-        void (ExpParamNode::*set_value_no_param)(int, bool) const = &ExpParamNode::set_value;
-        void (ExpParamNode::*set_test_value_no_param)(int, bool) const = &ExpParamNode::set_test_value;
-        std::string (ExpParamNode::*expr_no_param)() const = &ExpParamNode::expr;
-
-        class_<ExpParamNode, bases<ExpNode>>(
-            "ExpParamNode",
-            "Node for the parameterized exponential operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                ""
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &ExpParamNode::unit, "")
-            // .add_property("rung", &ExpParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerNegExpParamNode()
-    {
-        void (NegExpParamNode::*set_value_no_param)(int, bool) const = &NegExpParamNode::set_value;
-        void (NegExpParamNode::*set_test_value_no_param)(int, bool) const = &NegExpParamNode::set_test_value;
-        std::string (NegExpParamNode::*expr_no_param)() const = &NegExpParamNode::expr;
-
-        class_<NegExpParamNode, bases<NegExpNode>>(
-            "NegExpParamNode",
-            "Node for the parameterized negative exponential operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &NegExpParamNode::unit, "")
-            // .add_property("rung", &NegExpParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerSinParamNode()
-    {
-        void (SinParamNode::*set_value_no_param)(int, bool) const = &SinParamNode::set_value;
-        void (SinParamNode::*set_test_value_no_param)(int, bool) const = &SinParamNode::set_test_value;
-        std::string (SinParamNode::*expr_no_param)() const = &SinParamNode::expr;
-
-        class_<SinParamNode, bases<SinNode>>(
-            "SinParamNode",
-            "Node for the parameterized sine operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &SinParamNode::unit, "")
-            // .add_property("rung", &SinParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerCosParamNode()
-    {
-        void (CosParamNode::*set_value_no_param)(int, bool) const = &CosParamNode::set_value;
-        void (CosParamNode::*set_test_value_no_param)(int, bool) const = &CosParamNode::set_test_value;
-        std::string (CosParamNode::*expr_no_param)() const = &CosParamNode::expr;
-
-        class_<CosParamNode, bases<CosNode>>(
-            "CosParamNode",
-            "Node for the parameterized cosine operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &CosParamNode::unit, "")
-            // .add_property("rung", &CosParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerCbParamNode()
-    {
-        void (CbParamNode::*set_value_no_param)(int, bool) const = &CbParamNode::set_value;
-        void (CbParamNode::*set_test_value_no_param)(int, bool) const = &CbParamNode::set_test_value;
-        std::string (CbParamNode::*expr_no_param)() const = &CbParamNode::expr;
-
-        class_<CbParamNode, bases<CbNode>>(
-            "CbParamNode",
-            "Node for the parameterized cube operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &CbParamNode::unit, "")
-            // .add_property("rung", &CbParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerCbrtParamNode()
-    {
-        void (CbrtParamNode::*set_value_no_param)(int, bool) const = &CbrtParamNode::set_value;
-        void (CbrtParamNode::*set_test_value_no_param)(int, bool) const = &CbrtParamNode::set_test_value;
-        std::string (CbrtParamNode::*expr_no_param)() const = &CbrtParamNode::expr;
-
-        class_<CbrtParamNode, bases<CbrtNode>>(
-            "CbrtParamNode",
-            "Node for the parameterized cube root operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &CbrtParamNode::unit, "")
-            // .add_property("rung", &CbrtParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerSqParamNode()
-    {
-        void (SqParamNode::*set_value_no_param)(int, bool) const = &SqParamNode::set_value;
-        void (SqParamNode::*set_test_value_no_param)(int, bool) const = &SqParamNode::set_test_value;
-        std::string (SqParamNode::*expr_no_param)() const = &SqParamNode::expr;
-
-        class_<SqParamNode, bases<SqNode>>(
-            "SqParamNode",
-            "Node for the parameterized square operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &SqParamNode::unit, "")
-            // .add_property("rung", &SqParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerSqrtParamNode()
-    {
-        void (SqrtParamNode::*set_value_no_param)(int, bool) const = &SqrtParamNode::set_value;
-        void (SqrtParamNode::*set_test_value_no_param)(int, bool) const = &SqrtParamNode::set_test_value;
-        std::string (SqrtParamNode::*expr_no_param)() const = &SqrtParamNode::expr;
-
-        class_<SqrtParamNode, bases<SqrtNode>>(
-            "SqrtParamNode",
-            "Node for the parameterized square root operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &SqrtParamNode::unit, "")
-            // .add_property("rung", &SqrtParamNode::rung, "")
-        ;
-    }
-
-    void sisso::feature_creation::node::registerSixPowParamNode()
-    {
-        void (SixPowParamNode::*set_value_no_param)(int, bool) const = &SixPowParamNode::set_value;
-        void (SixPowParamNode::*set_test_value_no_param)(int, bool) const = &SixPowParamNode::set_test_value;
-        std::string (SixPowParamNode::*expr_no_param)() const = &SixPowParamNode::expr;
-
-        class_<SixPowParamNode, bases<SixPowNode>>(
-            "SixPowParamNode",
-            "Node for the parameterized sixth power operator",
-            init<node_ptr, int, double, double>(
-                (arg("self"), arg("feat"), arg("feat_ind"), arg("min_abs_feat_val"), arg("max_abs_feat_val")),
-                "Constructor including bounds on the maximum absolute value of the Node\n\nArgs:\n    feat (Node): shared_ptr of the feature to operate on (A)\n    feat_ind (int): Index of the new feature\n    l_bound (double): Minimum absolute value allowed for the feature.\n    u_bound (double): Maximum absolute value allowed for the feature."
-            )
-        )
-            .def("set_value", set_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all training samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .def("set_test_value", set_test_value_no_param, (arg("self"), arg("offset"), arg("for_comp")), "Set the value of all test samples for the feature inside the central data storage array\n\nArgs:\n    offset (int): Where the current node is in the binary expression tree relative to other nodes at the same depth\n    for_comp (bool): If true then the evaluation is used for comparing features")
-            .add_property("expr", expr_no_param, "A human readable equation representing the feature")
-            // .add_property("unit", &SixPowParamNode::unit, "")
-            // .add_property("rung", &SixPowParamNode::rung, "")
-        ;
-    }
-#endif
-
-void sisso::descriptor_identifier::registerModel()
-{
-    np::ndarray (Model::*eval_many_dict)(py::dict) const = &Model::eval_many_py;
-    np::ndarray (Model::*eval_many_ndarr)(np::ndarray) const = &Model::eval_many_py;
-
-    double (Model::*eval_ndarr)(np::ndarray) const = &Model::eval_py;
-    double (Model::*eval_list)(py::list) const = &Model::eval_py;
-    double (Model::*eval_dict)(py::dict) const = &Model::eval_py;
-
-    class_<sisso::descriptor_identifier::Model_Wrap, boost::noncopyable>("Model", "Base class to store the output models from SISSO", no_init)
-        .def("eval", eval_ndarr, (arg("self"), arg("x_in")), "Evaluate the model for a new point\n\nArgs:\n    x_in (np.ndarray): The data point to evaluate the model (order the same as appending the results of _feats[nn]->get_x_in_expr_list() for all feature)\n\nReturns:\n     The prediction of the model for a given data point")
-        .def("eval", eval_list, (arg("self"), arg("x_in")), "Evaluate the model for a new point\n\nArgs:\n    x_in (list): The data point to evaluate the model (order the same as appending the results of _feats[nn]->get_x_in_expr_list() for all feature)\n\nReturns:\n     The prediction of the model for a given data point")
-        .def("eval", eval_dict, (arg("self"), arg("x_in")), "Evaluate the model for a new point\n\nArgs:\n    x_in_dct (dict): Dictionary describing the new point (\"feature expr\": value)\n\nReturns:\n     The prediction of the model for a given data point")
-        .def("eval_many", eval_many_ndarr, (arg("self"), arg("x_in")), "Evaluate the model for a set of new points\n\nArgs:\n    x_in (np.ndarray): The set data for a set of new data points (size of n_feature x n_points, and order the same as appending the results of _feats[nn]->get_x_in_expr_list() for all feature)\n\nReturns:\n     The prediction of the model for a given data point")
-        .def("eval_many", eval_many_dict, (arg("self"), arg("x_in")), "Evaluate the model for a set of new points\n\nArgs:\n    x_in_dct (dict): The set of data points to evaluate the model. Keys must be strings representing feature expressions and vectors must be the same length\n\nReturns:\n     The prediction of the model for a given data point")
-        .def("write_matlab_fxn", &Model::write_matlab_fxn, (arg("self"), arg("fxn_filename")), "Convert the model into a Matlab function\n\nArgs:\n    fxn_filename: name of the file to print the function to")
-        .def("to_file", &Model::to_file, (arg("self"), arg("filename"), arg("train")), "")
-        .add_property("n_samp_train", &Model::n_samp_train, "The number of samples in the training data per feature")
-        .add_property("n_samp_test", &Model::n_samp_test, "The number of samples in the test data per feature")
-        .add_property("n_dim", &Model::n_dim, "The dimensionality of the data")
-        .add_property("prop_train", &Model::prop_train_py, "The property vector for all of the training samples")
-        .add_property("prop_test", &Model::prop_test_py, "The property vector for all of the test samples")
-        .add_property("train_error", &Model::train_error_py, "The error vector for the training data as a numpy array")
-        .add_property("test_error", &Model::test_error_py, "The error vector for the test data as a numpy array")
-        .add_property("fit", &Model::prop_train_est_py, "The estimated property vector for all of the training samples")
-        .add_property("predict", &Model::prop_test_est_py, "The estimated property vector for all of the test samples")
-        .add_property("feats", &Model::feats, "A python list of all the features of the model")
-        .add_property("coefs", &Model::coefs_py, "The coefficient array for the model (n_task, n_dim + bias term)")
-        .add_property("prop_unit", &Model::prop_unit, "The unit of the property")
-        .add_property("prop_label", &Model::prop_label, "The label for the property")
-        .add_property("leave_out_inds", &Model::leave_out_inds, "The indexes of the samples for the test set")
-        .add_property("task_size_train", &Model::task_sizes_train_py, "The number of training samples per task")
-        .add_property("task_size_test", &Model::task_sizes_test_py, "The number of test samples per task")
-        .add_property("task_eval", &Model::get_task_eval, &Model::set_task_eval, "Gets which set of coefficients the model should use for evaluating new data points\n@returns _task_eval Task to evaluate")
-        .add_property("fix_intercept", &Model::fix_intercept, "True if the bias term is 0.0")
-    ;
-}
-
-void sisso::descriptor_identifier::registerModelRegressor()
-{
-    class_<ModelRegressor, bases<Model>>("ModelRegressor", "Class to store the output models from SISSORegressor\nDefault Constructor", init<std::string>((arg("self"), arg("train_file")), "Construct a ModelRegressor from a training output file\n\nArgs:\n    train_file (str): Previously generated model output file for the training data"))
-        .def(init<std::string, std::string>((arg("self"), arg("train_file"), arg("test_file")), "Construct a ModelRegressor from a training and testing output file\n\nArgs:\n    train_file (str): Previously generated model output file for the training data\n    test_file (str): Previously generated model output file for the test data"))
-        .def("__str__", &ModelRegressor::toString, (arg("self")), "Convert the model to a string")
-        .def("__repr__", &ModelRegressor::toString, (arg("self")), "Convert the model to a string")
-        .add_property("latex_str", &ModelRegressor::toLatexString, "Convert the model to a latexified string")
-        .add_property("r2", &ModelRegressor::r2, "The training R^2 of the model")
-        .add_property("test_r2", &ModelRegressor::test_r2, "The test R^2 of the model")
-        .add_property("rmse", &ModelRegressor::rmse, "The training root mean square error of the model")
-        .add_property("test_rmse", &ModelRegressor::test_rmse, "The test root mean square error of the model")
-        .add_property("max_ae", &ModelRegressor::max_ae, "The max absolute error of the training data")
-        .add_property("test_max_ae", &ModelRegressor::test_max_ae, "The max absolute error of the testing data")
-        .add_property("mae", &ModelRegressor::mae, "The mean absolute error of the model")
-        .add_property("test_mae", &ModelRegressor::test_mae, "The mean absolute test error of the model")
-        .add_property("mape", &ModelRegressor::mape, "The mean absolute percent error of the model")
-        .add_property("test_mape", &ModelRegressor::test_mape, "The mean absolute percent test error of the model")
-        .add_property("percentile_25_ae", &ModelRegressor::percentile_25_ae, "The the 25 percentile error of the model")
-        .add_property("percentile_25_test_ae", &ModelRegressor::percentile_25_test_ae, "The 25 percentile test error of the model")
-        .add_property("percentile_50_ae", &ModelRegressor::percentile_50_ae, "The 50 percentile error of the model")
-        .add_property("percentile_50_test_ae", &ModelRegressor::percentile_50_test_ae, "The 50 percentile test error of the model")
-        .add_property("percentile_75_ae", &ModelRegressor::percentile_75_ae, "The 75 percentile error of the model")
-        .add_property("percentile_75_test_ae", &ModelRegressor::percentile_75_test_ae, "The 75 percentile test error of the model")
-        .add_property("percentile_95_ae", &ModelRegressor::percentile_95_ae, "The 95 percentile error of the model")
-        .add_property("percentile_95_test_ae", &ModelRegressor::percentile_95_ae, "The 95 percentile test error of the model")
-    ;
-}
-
-
-void sisso::descriptor_identifier::registerModelLogRegressor()
-{
-    class_<ModelLogRegressor, bases<ModelRegressor>>("ModelLogRegressor", "Class to store the output models from SISSOLogRegressor", init<std::string>((arg("self"), arg("train_file")), "Construct a ModelLogRegressor from a training output file\n\nArgs:\n    train_file (str): Previously generated model output file for the training data"))
-        .def(init<std::string, std::string>((arg("self"), arg("train_file"), arg("test_file")), "Construct a ModelLogRegressor from a training and testing output file\n\nArgs:\n    train_file (str): Previously generated model output file for the training data\n    test_file (str): Previously generated model output file for the test data"))
-        .def("__str__", &ModelLogRegressor::toString, (arg("self")), "Convert the model to a string")
-        .def("__repr__", &ModelLogRegressor::toString, (arg("self")), "Convert the model to a string")
-        .add_property("latex_str", &ModelLogRegressor::toLatexString, "Convert the model to a latexified string")
-    ;
-}
-
-void sisso::descriptor_identifier::registerModelClassifier()
-{
-    class_<ModelClassifier, bases<Model>>("ModelClassifier", "Class to store the output models from SISSOClassifier", init<std::string>((arg("self"), arg("train_file")), "Construct a ModelClassifier from a training output file\n\nArgs:\n    train_file (str): Previously generated model output file for the training data"))
-        .def(init<std::string, std::string>((arg("self"), arg("train_file"), arg("test_file")), "Construct a ModelClassifier from a training and testing output file\n\nArgs:\n    train_file (str): Previously generated model output file for the training data\n    test_file (str): Previously generated model output file for the test data"))
-        .def(init<ModelClassifier, py::list, np::ndarray, np::ndarray>((arg("self"), arg("o"), arg("new_coefs"), arg("prop_train_est"), arg("prop_test_est")), "Construct a new ModelClassifier with updated SVM coefficient\n\nArgs:\n    o (Model): Model to be copied\n    new_coefs (list): The new coefficients\n    prop_train_est (list): The estimated property values for the training set\n    prop_test_est (list): The estimated property values for the validation set"))
-        .def(init<ModelClassifier, np::ndarray, np::ndarray, np::ndarray>((arg("self"), arg("o"), arg("new_coefs"), arg("prop_train_est"), arg("prop_test_est")), "Construct a new ModelClassifier with updated SVM coefficient\n\nArgs:\n    o (Model): Model to be copied\n    new_coefs (np.ndarray): The new coefficients\n    prop_train_est (np.ndarray): The estimated property values for the training set\n    prop_test_est (np.ndarray): The estimated property values for the validation set"))
-        .def("__str__", &ModelClassifier::toString, (arg("self")), "Convert the model to a string")
-        .def("__repr__", &ModelClassifier::toString, (arg("self")), "Convert the model to a string")
-        .add_property("latex_str", &ModelClassifier::toLatexString, "Convert the model to a latexified string")
-        .add_property("percent_error", &ModelClassifier::percent_train_error, "Percent of all training samples that are in the Convex Hull overlap region")
-        .add_property("percent_test_error", &ModelClassifier::percent_test_error, "Percent of all test samples that are in the Convex Hull overlap region")
-        .add_property("n_convex_overlap_train", &ModelClassifier::n_convex_overlap_train, "The number of samples in overlapping convex hull regions (training data)")
-        .add_property("n_convex_overlap_test", &ModelClassifier::n_convex_overlap_test, "The number of samples in overlapping convex hull regions (test data)")
-        .add_property("n_svm_misclassified_train", &ModelClassifier::n_svm_misclassified_train, "The number of samples misclassified by SVM (training data)")
-        .add_property("n_svm_misclassified_test", &ModelClassifier::n_svm_misclassified_test, "The number of samples misclassified by SVM (training data)")
-    ;
-}
-
-void sisso::descriptor_identifier::registerSISSOSolver()
-{
-    class_<sisso::descriptor_identifier::SISSOSolver_Wrap, boost::noncopyable>("SISSOSolver", "Base class for SISSO solvers", no_init)
-        .add_property("prop_train", &SISSOSolver::prop_train_py, "The property vector for all of the training samples as a numpy array")
-        .add_property("prop_test", &SISSOSolver::prop_test_py, "The property error for all of the test samples as a numpy array")
-        .add_property("n_samp", &SISSOSolver::n_samp, "The number of samples in the training data per feature")
-        .add_property("n_dim", &SISSOSolver::n_dim, "The maximum number of features allowed in the linear model")
-        .add_property("n_residual", &SISSOSolver::n_residual, "The number of residuals each iteration of SIS acts on")
-        .add_property("n_models_store", &SISSOSolver::n_models_store, "")
-        .add_property("feat_space", &SISSOSolver::feat_space, "")
-        .add_property("task_sizes_train", &SISSOSolver::task_sizes_train, "The number of training samples per task")
-        .add_property("task_sizes_test", &SISSOSolver::task_sizes_test, "The number of test samples per task")
-    ;
-}
-
-void sisso::descriptor_identifier::registerSISSORegressor()
-{
-    class_<SISSORegressor, bases<SISSOSolver>>(
-        "SISSORegressor",
-        "Uses SISSO to solve a regression problem",
-        init<InputParser, std::shared_ptr<FeatureSpace>>(
-            (arg("self"), arg("self"), arg("feat_space")),
-            "Constructor for the regressor\n\nArgs:\n    inputs: The InputParser object for the calculation\n    feat_space: Feature Space for the problem"
-        )
-    )
-        .def("fit", &SISSORegressor::fit, (arg("self")), "Iteratively run SISSO on the FeatureSpace an Property vector until the maximum dimenisonality is reached")
-        .add_property("models", &SISSORegressor::models_py, "The selected models (n_dim, n_models_store)")
-    ;
-}
-
-void sisso::descriptor_identifier::registerSISSOLogRegressor()
-{
-    class_<SISSOLogRegressor, bases<SISSORegressor>>(
-        "SISSOLogRegressor",
-        "Uses SISSO to solve a log regression problem",
-        init<InputParser, std::shared_ptr<FeatureSpace>>(
-            (arg("self"), arg("self"), arg("feat_space")),
-            ""
-        )
-    )
-        .add_property("models", &SISSOLogRegressor::models_log_reg_py, "The selected models (n_dim, n_models_store)")
-    ;
-}
-
-void sisso::descriptor_identifier::registerSISSOClassifier()
-{
-    class_<SISSOClassifier, bases<SISSOSolver>>(
-        "SISSOClassifier",
-        "Uses SISSO to solve a classification problem",
-        init<InputParser, std::shared_ptr<FeatureSpace>>(
-            (arg("self"), arg("self"), arg("feat_space")),
-            ""
-        )
-    )
-        .def("fit", &SISSOClassifier::fit, (arg("self")), "Iteratively run SISSO on the FeatureSpace an Property vector until the maximum dimenisonality is reached")
-        .add_property("models", &SISSOClassifier::models_py, "The selected models (n_dim, n_models_store)")
-    ;
-}
diff --git a/src/python/py_binding_cpp_def/bindings.hpp b/src/python/py_binding_cpp_def/bindings.hpp
deleted file mode 100644
index d2dc3166..00000000
--- a/src/python/py_binding_cpp_def/bindings.hpp
+++ /dev/null
@@ -1,599 +0,0 @@
-// Copyright 2021 Thomas A. R. Purcell
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/** @file python/py_bindings_cpp_def/bindings.hpp
- *  @brief Definitions to convert C++ classes into python classes
- *
- *  @author Thomas A. R. Purcell (tpurcell90)
- *  @bug No known bugs.
- */
-
-#ifndef PYTHON_BINDING
-#define PYTHON_BINDINGS
-
-#define BOOST_PYTHON_MAX_ARITY 20
-
-#include "descriptor_identifier/solver/SISSOLogRegressor.hpp"
-#include "descriptor_identifier/solver/SISSOClassifier.hpp"
-#include "python/py_binding_cpp_def/feature_creation/node_utils.hpp"
-#include <boost/config.hpp>
-
-#ifdef PARAMETERIZE
-#include "nl_opt/NLOptWrapper.hpp"
-#endif
-
-namespace py = boost::python;
-namespace np = boost::python::numpy;
-
-namespace sisso
-{
-    /**
-     * @brief Register all C++ classes as python classes
-     * @details [long description]
-     */
-    void register_all();
-
-    static void registerInputs();
-
-    namespace feature_creation
-    {
-        static void registerFeatureSpace();
-        static void registerDomain();
-        static void registerUnit();
-        #ifdef PARAMETERIZE
-        namespace nloptimizer
-        {
-            struct NLOptimizerWrap : NLOptimizer, py::wrapper<NLOptimizer>
-            {
-            public:
-                inline std::shared_ptr<ConvexHull1D> convex_hull()const {return this->get_override("convex_hull")();}
-                inline double* feature_gradient(int ind){return this->get_override("feature_gradient")();}
-                inline double* residuals(int ind){return this->get_override("residuals")();}
-                inline double cauchy_scaling()const {return this->get_override("cauchy_scaling")();}
-            };
-            static void registerNLOptimizer();
-            static void registerNLOptimizerClassification();
-            static void registerNLOptimizerRegression();
-            static void registerNLOptimizerLogRegression();
-
-        }
-        #endif
-        namespace node
-        {
-            #ifdef PARAMETERIZE
-            /**
-             * @brief struct used wrap a Node object for conversion
-             */
-            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")();}
-                inline std::string get_latex_expr(double*, int depth=1) const {return this->get_override("latex_expr")();}
-                inline std::string matlab_fxn_expr() const {return this->get_override("matlab_fxn_expr")();}
-                inline std::string matlab_fxn_expr(const double*, int depth=1) const {return this->get_override("matlab_fxn_expr")();}
-                inline Unit unit() const {return this->get_override("unit")();}
-                inline unsigned long long sort_score(unsigned int max_ind) const {return this->get_override("sort_score")();}
-                inline std::vector<double> value() const {return this->get_override("value")();}
-                inline std::vector<double> test_value() const {return this->get_override("test_value")();}
-                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 double* value_ptr(int offset=-1, const bool for_comp=false) const {return this->get_override("value_ptr")();}
-                inline double* test_value_ptr(int offset=-1, const bool for_comp=false) const {return this->get_override("test_value_ptr")();}
-                inline void set_value(double* params, int offset=-1, int depth=1) const {this->get_override("set_value")();}
-                inline void set_test_value(double* params, int offset=-1, int depth=1) const {this->get_override("set_test_value")();}
-                inline double* value_ptr(double* params, int offset=-1, int depth=1) const {return this->get_override("value_ptr")();}
-                inline double* test_value_ptr(double* params, int offset=-1, int depth=1) const {return this->get_override("test_value_ptr")();}
-                inline bool is_nan() const {return this->get_override("is_nan")();}
-                inline bool is_const() const {return this->get_override("is_const")();}
-                inline NODE_TYPE type() const {return this->get_override("type")();}
-                inline int rung(int cur_rung = 0) const {return this->get_override("rung")();}
-                inline std::map<int, int> primary_feature_decomp() const {return this->get_override("primary_feature_decomp")();}
-                inline void update_primary_feature_decomp(std::map<int, int>& pf_decomp) const {this->get_override("update_primary_feature_decomp")();}
-                inline void update_postfix(std::string& cur_expr) const {this->get_override("update_postfix")();}
-                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")();}
-                inline void set_bounds(double* lb, double* ub, const int depth=1) const {this->get_override("set_bounds")();}
-                inline void initialize_params(double* params, int depth=1) const {this->get_override("set_bounds")();}
-                inline int n_feats() const {return this->get_override("n_feats")();}
-                inline std::shared_ptr<Node> feat(const int ind) const {return this->get_override("feat")();}
-                inline void param_derivative(const double* params, double* dfdp) const {this->get_override("param_derivative");}
-                inline void gradient(double* grad, double* dfdp) const {this->get_override("gradient");}
-                inline void gradient(double* grad, double* dfdp, const double* params) const {this->get_override("gradient");}
-                inline std::vector<std::string> get_x_in_expr_list() const {return this->get_override("get_x_in_expr_list")();}
-                inline int n_leaves(int n_cur_leaves=0) const {return this->get_override("n_cur_leaves")();}
-
-            };
-            /**
-             * @brief struct used wrap an OperatorNode object for conversion
-             */
-            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")();}
-                inline void set_test_value(const double* params, int offset=-1, bool for_comp=false, int depth=1) const {this->get_override("set_test_value")();}
-                inline NODE_TYPE type() const {return this->get_override("type")();}
-                inline int rung(int cur_rung = 0) const {return this->get_override("rung")();}
-                inline Unit unit() const {return this->get_override("unit")();}
-                inline std::string get_postfix_term() const {return this->get_override("get_postfix_term")();}
-                inline std::string expr(const double* params, const int depth=1) const {return this->get_override("expr")();}
-                inline std::string expr() const {return this->get_override("expr")();}
-                inline std::string get_latex_expr(const double* params, const int depth=1) const {return this->get_override("latex_expr")();}
-                inline std::string get_latex_expr() const {return this->get_override("latex_expr")();}
-                inline std::string matlab_fxn_expr() const {return this->get_override("matlab_fxn_expr")();}
-                inline std::string matlab_fxn_expr(const double*, int depth=1) const {return this->get_override("matlab_fxn_expr")();}
-                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 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")();}
-                inline std::vector<double> parameters() const {return this->get_override("parameters")();}
-                inline void set_bounds(double* lb, double* ub, const int depth=1) const {this->get_override("set_bounds")();}
-                inline void initialize_params(double* params, int depth=1) const {this->get_override("set_bounds")();}
-                inline void param_derivative(const double* params, double* dfdp) const {this->get_override("param_derivative");}
-            };
-            #else
-            /**
-             * @brief struct used wrap a Node object for conversion
-             */
-            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 get_latex_expr() const
-                {
-                    return this->get_override("latex_expr")();
-                }
-                inline std::string matlab_fxn_expr() const
-                {
-                    return this->get_override("matlab_fxn_expr")();
-                }
-                inline Unit unit() const
-                {
-                    return this->get_override("unit")();
-                }
-                inline unsigned long long sort_score(unsigned int max_ind) const
-                {
-                    return this->get_override("sort_score")();
-                }
-                inline std::vector<double> value() const
-                {
-                    return this->get_override("value")();
-                }
-                inline std::vector<double> test_value() const
-                {
-                    return this->get_override("test_value")();
-                }
-                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 double* value_ptr(int offset=-1, const bool for_comp=false) const
-                {
-                    return this->get_override("value_ptr")();
-                }
-                inline double* test_value_ptr(int offset=-1, const bool for_comp=false) const
-                {
-                    return this->get_override("test_value_ptr")();
-                }
-                inline bool is_nan() const
-                {
-                    return this->get_override("is_nan")();
-                }
-                inline bool is_const() const
-                {
-                    return this->get_override("is_const")();
-                }
-                inline NODE_TYPE type() const
-                {
-                    return this->get_override("type")();
-                }
-                inline int rung(int cur_rung = 0) const
-                {
-                    return this->get_override("rung")();
-                }
-                inline std::map<int, int> primary_feature_decomp() const
-                {
-                    return this->get_override("primary_feature_decomp")();
-                }
-                inline void update_primary_feature_decomp(std::map<int, int>& pf_decomp) const
-                {
-                    this->get_override("update_primary_feature_decomp")();
-                }
-                inline void update_postfix(std::string& cur_expr) const
-                {
-                    this->get_override("update_postfix")();
-                }
-                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 int n_feats() const
-                {
-                    return this->get_override("n_feats")();
-                }
-                inline std::shared_ptr<Node> feat(const int ind) const
-                {
-                    return this->get_override("feat")();
-                }
-                inline std::vector<std::string> get_x_in_expr_list() const
-                {
-                    return this->get_override("get_x_in_expr_list")();
-                }
-                inline int n_leaves(int n_cur_leaves=0) const
-                {
-                    return this->get_override("n_cur_leaves")();
-                }
-
-            };
-            /**
-             * @brief struct used wrap an OperatorNode object for conversion
-             */
-            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 NODE_TYPE type() const
-                {
-                    return this->get_override("type")();
-                }
-                inline int rung(int cur_rung = 0) const
-                {
-                    return this->get_override("rung")();
-                }
-                inline Unit unit() const
-                {
-                    return this->get_override("unit")();
-                }
-                inline std::string get_postfix_term() const
-                {
-                    return this->get_override("get_postfix_term")();
-                }
-                inline std::string expr() const
-                {
-                    return this->get_override("expr")();
-                }
-                inline std::string get_latex_expr() const
-                {
-                    return this->get_override("latex_expr")();
-                }
-                inline std::string matlab_fxn_expr() const
-                {
-                    return this->get_override("matlab_fxn_expr")();
-                }
-                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")();
-                }
-            };
-            #endif
-
-            /**
-             * @brief Register the Node for accessing the object via python
-             */
-            static void registerNode();
-
-            /**
-             * @brief Register the FeatureNode for accessing the object via python
-             */
-            static void registerFeatureNode();
-
-            /**
-             * @brief Register the ModelNode for accessing the object via python
-             */
-            static void registerModelNode();
-
-            #ifndef PARAMETERIZE
-                /**
-                 * @brief Register the OperatorNode for accessing the object via python
-                 */
-                template<int N>
-                static void registerOperatorNode()
-                {
-                    py::class_<OperatorNodeWrap<N>, py::bases<Node>, boost::noncopyable>("OperatorNode", py::no_init)
-                        .def("is_nan", &OperatorNode<N>::is_nan, (py::arg("self")), "Check if the feature has a NaN value in it\n\nReturns:\n     True if one of the values of the feature is a NaN")
-                        .def("is_const", &OperatorNode<N>::is_const, (py::arg("self")), "Check if feature is constant for one of the tasks\n\nReturns:\n     True if the feature is constant for all samples in any task")
-                        .def("feat", &OperatorNode<N>::feat, (py::arg("self"), py::arg("ind")), "Return the ind^th feature stored by an operator node\n\nArgs:\n    ind (int): the index of the feats list to be accessed\n\nReturns:\n     The feature stored in _feats[ind]")
-                        .add_property("n_leaves", &OperatorNode<N>::n_leaves, "The number of primary features (non-unique) this feature contains (The number of leaves of the Binary Expression Tree)")
-                        .add_property("n_feats", &OperatorNode<N>::n_feats, "The number of features used for an operator (Number of child node)")
-                    ;
-                }
-            #else
-                template<int N>
-                static void registerOperatorNode()
-                {
-                    void (OperatorNode<N>::*set_params_list)(py::list) = &OperatorNode<N>::set_parameters;
-                    void (OperatorNode<N>::*set_params_arr)(np::ndarray) = &OperatorNode<N>::set_parameters;
-                    py::class_<OperatorNodeWrap<N>, py::bases<Node>, boost::noncopyable>("OperatorNode", py::no_init)
-                        .def("is_nan", &OperatorNode<N>::is_nan, (py::arg("self")), "Check if the feature has a NaN value in it\n\nReturns:\n     True if one of the values of the feature is a NaN")
-                        .def("is_const", &OperatorNode<N>::is_const, (py::arg("self")), "Check if feature is constant for one of the tasks\n\nReturns:\n     True if the feature is constant for all samples in any task")
-                        .def("get_parameters", py::pure_virtual(&OperatorNode<N>::get_parameters), (py::arg("self"), py::arg("optimizer")), "Optimize the scale and bias terms for each operation in the Node.\nUse optimizer to find the scale and bias terms that minimizes the associated loss function\n\nArgs:\n    optimizer: The optimizer used to evaluate the loss function for each optimization and find the optimal parameters")
-                        .def("set_parameters", set_params_arr, (py::arg("self"), py::arg("params")), "Set the non-linear parameters\n\nArgs:\n    params (np.ndarray): The new parameters of the node")
-                        .def("set_parameters", set_params_list, (py::arg("self"), py::arg("params")), "Set the non-linear parameters\n\nArgs:\n    params (list): The new parameters of the node")
-                        .def("feat", &OperatorNode<N>::feat, (py::arg("self"), py::arg("ind")), "Return the ind^th feature stored by an operator node\n\nArgs:\n    ind (int): the index of the feats list to be accessed\n\nReturns:\n     The feature stored in _feats[ind]")
-                        .add_property("n_leaves", &OperatorNode<N>::n_leaves, "The number of primary features (non-unique) this feature contains (The number of leaves of the Binary Expression Tree)")
-                        .add_property("n_feats", &OperatorNode<N>::n_feats, "The number of features used for an operator (Number of child node)")
-                    ;
-                }
-
-            #endif
-
-            /**
-             * @brief Register the AddNode object for conversion to a python object
-             */
-            static void registerAddNode();
-
-            /**
-             * @brief Register the SubNode object for conversion to a python object
-             */
-            static void registerSubNode();
-
-            /**
-             * @brief Register the DivNode object for conversion to a python object
-             */
-            static void registerDivNode();
-
-            /**
-             * @brief Register the MultNode object for conversion to a python object
-             */
-            static void registerMultNode();
-
-            /**
-             * @brief Register the AbsDiffNode object for conversion to a python object
-             */
-            static void registerAbsDiffNode();
-
-            /**
-             * @brief Register the AbsNode object for conversion to a python object
-             */
-            static void registerAbsNode();
-
-            /**
-             * @brief Register the InvNode object for conversion to a python object
-             */
-            static void registerInvNode();
-
-            /**
-             * @brief Register the LogNode object for conversion to a python object
-             */
-            static void registerLogNode();
-
-            /**
-             * @brief Register the ExpNode object for conversion to a python object
-             */
-            static void registerExpNode();
-
-            /**
-             * @brief Register the NegExpNode object for conversion to a python object
-             */
-            static void registerNegExpNode();
-
-            /**
-             * @brief Register the SinNode object for conversion to a python object
-             */
-            static void registerSinNode();
-
-            /**
-             * @brief Register the CosNode object for conversion to a python object
-             */
-            static void registerCosNode();
-
-            /**
-             * @brief Register the CbNode object for conversion to a python object
-             */
-            static void registerCbNode();
-
-            /**
-             * @brief Register the CbrtNode object for conversion to a python object
-             */
-            static void registerCbrtNode();
-
-            /**
-             * @brief Register the SqNode object for conversion to a python object
-             */
-            static void registerSqNode();
-
-            /**
-             * @brief Register the SqrtNode object for conversion to a python object
-             */
-            static void registerSqrtNode();
-
-            /**
-             * @brief Register the SixPowNode object for conversion to a python object
-             */
-            static void registerSixPowNode();
-
-            #ifdef PARAMETERIZE
-                /**
-                 * @brief Register the AddParamNode object for conversion to a python object
-                 */
-                static void registerAddParamNode();
-
-                /**
-                 * @brief Register the SubParamNode object for conversion to a python object
-                 */
-                static void registerSubParamNode();
-
-                /**
-                 * @brief Register the DivParamNode object for conversion to a python object
-                 */
-                static void registerDivParamNode();
-
-                /**
-                 * @brief Register the MultParamNode object for conversion to a python object
-                 */
-                static void registerMultParamNode();
-
-                /**
-                 * @brief Register the AbsDiffParamNode object for conversion to a python object
-                 */
-                static void registerAbsDiffParamNode();
-
-                /**
-                 * @brief Register the AbsParamNode object for conversion to a python object
-                 */
-                static void registerAbsParamNode();
-
-                /**
-                 * @brief Register the InvParamNode object for conversion to a python object
-                 */
-                static void registerInvParamNode();
-
-                /**
-                 * @brief Register the LogParamNode object for conversion to a python object
-                 */
-                static void registerLogParamNode();
-
-                /**
-                 * @brief Register the ExpParamNode object for conversion to a python object
-                 */
-                static void registerExpParamNode();
-
-                /**
-                 * @brief Register the NegExpParamNode object for conversion to a python object
-                 */
-                static void registerNegExpParamNode();
-
-                /**
-                 * @brief Register the SinParamNode object for conversion to a python object
-                 */
-                static void registerSinParamNode();
-
-                /**
-                 * @brief Register the CosParamNode object for conversion to a python object
-                 */
-                static void registerCosParamNode();
-
-                /**
-                 * @brief Register the CbParamNode object for conversion to a python object
-                 */
-                static void registerCbParamNode();
-
-                /**
-                 * @brief Register the CbrtParamNode object for conversion to a python object
-                 */
-                static void registerCbrtParamNode();
-
-                /**
-                 * @brief Register the SqParamNode object for conversion to a python object
-                 */
-                static void registerSqParamNode();
-
-                /**
-                 * @brief Register the SqrtParamNode object for conversion to a python object
-                 */
-                static void registerSqrtParamNode();
-
-                /**
-                 * @brief Register the SixPowParamNode object for conversion to a python object
-                 */
-                static void registerSixPowParamNode();
-            #endif
-        }
-    }
-
-    namespace descriptor_identifier
-    {
-        struct SISSOSolver_Wrap : SISSOSolver, py::wrapper<SISSOSolver>
-        {
-            inline void l0_regularization(){this->get_override("l0_regularization")();}
-            inline void fit(){this->get_override("fit")();}
-        };
-
-        struct Model_Wrap : Model, py::wrapper<Model>
-        {
-            inline void matlab_expr(){this->get_override("matlab_expr")();}
-        };
-
-        /**
-         * @brief Register the Model object for conversion to a python object
-         */
-        static void registerModel();
-
-        /**
-         * @brief Register the Model object for conversion to a python object
-         */
-        static void registerModelRegressor();
-
-        /**
-         * @brief Register the Model object for conversion to a python object
-         */
-        static void registerModelLogRegressor();
-
-        /**
-         * @brief Register the Model object for conversion to a python object
-         */
-        static void registerModelClassifier();
-
-        /**
-         * @brief Register the SISSORegressor object for conversion to a python object
-         */
-        static void registerSISSOSolver();
-
-        /**
-         * @brief Register the SISSORegressor object for conversion to a python object
-         */
-        static void registerSISSORegressor();
-
-        /**
-         * @brief Register the SISSORegressor object for conversion to a python object
-         */
-        static void registerSISSOLogRegressor();
-
-        /**
-         * @brief Register the SISSORegressor object for conversion to a python object
-         */
-        static void registerSISSOClassifier();
-    }
-}
-
-#endif
-- 
GitLab