From ed9347fcb60745f33890bf82b7b115a5b9163628 Mon Sep 17 00:00:00 2001
From: Thomas <purcell@fhi-berlin.mpg.de>
Date: Thu, 16 Sep 2021 09:50:16 +0200
Subject: [PATCH] Make sc_node_pair a struct not a pair

Makes some of the comparisions easier
---
 .../feature_space/FeatureSpace.cpp            | 18 ++--
 src/mpi_interface/MPI_Ops.cpp                 |  5 +-
 src/mpi_interface/MPI_Ops.hpp                 | 20 ----
 src/utils/compare_features.cpp                | 12 +--
 src/utils/compare_features.hpp                | 93 ++++++++++++++++++-
 .../googletest/utils/test_compare_features.cc |  3 +-
 6 files changed, 112 insertions(+), 39 deletions(-)

diff --git a/src/feature_creation/feature_space/FeatureSpace.cpp b/src/feature_creation/feature_space/FeatureSpace.cpp
index f210241c..a5e71e64 100644
--- a/src/feature_creation/feature_space/FeatureSpace.cpp
+++ b/src/feature_creation/feature_space/FeatureSpace.cpp
@@ -1308,11 +1308,15 @@ void FeatureSpace::sis(std::shared_ptr<LossFunction> loss)
     if(_mpi_comm->size() > 1)
     {
         // Collect the best features from all ranks
-        std::vector<node_sc_pair> local_sel(_n_sis_select, std::make_tuple<node_ptr, double>(nullptr, std::numeric_limits<double>::max()));
-        for(int ff = 0; ff < phi_sel.size(); ++ff)
-        {
-            local_sel[ff] = mpi_reduce_op::make_node_sc_pair(phi_sel[ff], scores_sel[ff]);
-        }
+        std::vector<node_sc_pair> local_sel(_n_sis_select);
+        std::transform(
+            phi_sel.begin(),
+            phi_sel.end(),
+            scores_sel.begin(),
+            local_sel.begin(),
+            [](node_ptr feat, double sc){return node_sc_pair(feat, sc);}
+        );
+
         std::vector<node_sc_pair> selected(_n_sis_select);
         mpi::all_reduce(
             *_mpi_comm,
@@ -1326,7 +1330,7 @@ void FeatureSpace::sis(std::shared_ptr<LossFunction> loss)
         cur_feat_local = 0;
         for(auto& sel : selected)
         {
-            _phi_selected.push_back(std::get<0>(sel));
+            _phi_selected.push_back(sel._feat);
             _phi_selected.back()->set_selected(true);
             _phi_selected.back()->set_d_mat_ind(cur_feat);
             _phi_selected.back()->set_value();
@@ -1342,7 +1346,7 @@ void FeatureSpace::sis(std::shared_ptr<LossFunction> loss)
             for(auto& sel : selected)
             {
                 out_file_stream << std::setw(14) <<std::left << cur_feat << _phi_selected[cur_feat]->postfix_expr() << std::endl;
-                sum_file_stream << std::setw(14) <<std::left << cur_feat << std::setw(24) << std::setprecision(18) << std::left << prefact * std::get<1>(sel);
+                sum_file_stream << std::setw(14) <<std::left << cur_feat << std::setw(24) << std::setprecision(18) << std::left << prefact * sel._score;
                 sum_file_stream << _phi_selected[cur_feat]->expr() << std::endl;
 
                 ++cur_feat;
diff --git a/src/mpi_interface/MPI_Ops.cpp b/src/mpi_interface/MPI_Ops.cpp
index f2b71fed..2b413fb3 100644
--- a/src/mpi_interface/MPI_Ops.cpp
+++ b/src/mpi_interface/MPI_Ops.cpp
@@ -65,15 +65,14 @@ std::vector<node_sc_pair> mpi_reduce_op::select_top_feats(std::vector<node_sc_pa
 
     // Merge input vectors and sort
     in_vec_2.insert(in_vec_2.end(), in_vec_1.begin(), in_vec_1.end());
-    std::sort(in_vec_2.begin(), in_vec_2.end(), my_sorter);
+    std::sort(in_vec_2.begin(), in_vec_2.end());
 
     // Populate the output vector
     int ff = 0;
     int out_ind = 0;
     while((out_ind < N_SIS_SELECT) && (ff < in_vec_2.size()))
     {
-        const node_ptr cur_node = std::get<0>(in_vec_2[ff]);
-        if(cur_node && IS_VALID(cur_node->value_ptr(), cur_node->n_samp(), CROSS_COR_MAX, out_vec, std::get<1>(in_vec_2[ff])))
+        if(in_vec_2[ff]._feat && IS_VALID(in_vec_2[ff]._feat->value_ptr(), in_vec_2[ff]._feat->n_samp(), CROSS_COR_MAX, out_vec, in_vec_2[ff]._score))
         {
             out_vec.push_back(in_vec_2[ff]);
             ++out_ind;
diff --git a/src/mpi_interface/MPI_Ops.hpp b/src/mpi_interface/MPI_Ops.hpp
index cfa62b5b..37d4758c 100644
--- a/src/mpi_interface/MPI_Ops.hpp
+++ b/src/mpi_interface/MPI_Ops.hpp
@@ -35,26 +35,6 @@ namespace mpi_reduce_op
     extern double CROSS_COR_MAX; //!< The maximum cross correlation between features
     extern int N_SIS_SELECT; //!< The number of features to select
 
-    /**
-     * @brief Create a node_sc pair from a node_ptr and a score value
-     *
-     * @param feat the node_ptr for the pair
-     * @param sc the score for the pair
-     *
-     * @return The resulting pair
-     */
-    inline node_sc_pair make_node_sc_pair(node_ptr feat, double sc){return std::make_tuple(feat, sc);}
-
-    /**
-     * @brief The function for sorting different node_sc pointers
-     *
-     * @param node_1 first node to compare
-     * @param node_2 second node to compare
-     *
-     * @return True if the score of node_1 is less then the score of node_2
-     */
-    inline bool my_sorter(node_sc_pair node_1, node_sc_pair node_2){ return (std::get<1>(node_1) < std::get<1>(node_2)); }
-
     /**
      * @brief Get the top features of the combined input vectors
      *
diff --git a/src/utils/compare_features.cpp b/src/utils/compare_features.cpp
index fa5d9660..359e9573 100644
--- a/src/utils/compare_features.cpp
+++ b/src/utils/compare_features.cpp
@@ -146,13 +146,13 @@ bool comp_feats::valid_feature_against_selected_pearson_max_corr_1_mpi_op(
 
     for(auto& feat_sc : out_vec)
     {
-        if(abs(cur_score - std::get<1>(feat_sc)) > 1e-5)
+        if(abs(cur_score - feat_sc._score) > 1e-5)
         {
             continue;
         }
 
         double comp_value  = (
-            base_val - std::abs(util_funcs::r(val_ptr, std::get<0>(feat_sc)->value_ptr(-1, true), n_samp, mean, stand_dev))
+            base_val - std::abs(util_funcs::r(val_ptr, feat_sc._feat->value_ptr(-1, true), n_samp, mean, stand_dev))
         );
         if(std::abs(comp_value) < 5.0e-9)
         {
@@ -239,7 +239,7 @@ bool comp_feats::valid_feature_against_selected_pearson_mpi_op(
     for(auto& feat_sc : out_vec)
     {
         double comp_value = (
-            base_val - std::abs(util_funcs::r(val_ptr, std::get<0>(feat_sc)->value_ptr(-1, true), n_samp, mean, stand_dev))
+            base_val - std::abs(util_funcs::r(val_ptr, feat_sc._feat->value_ptr(-1, true), n_samp, mean, stand_dev))
         );
         if(std::abs(comp_value) < (1.0 - cross_cor_max + 5.0e-9))
         {
@@ -352,13 +352,13 @@ bool comp_feats::valid_feature_against_selected_spearman_max_corr_1_mpi_op(
 
     for(auto& feat_sc : out_vec)
     {
-        if(abs(std::floor(cur_score) - std::floor(std::get<1>(feat_sc))) > 1e-5)
+        if(abs(std::floor(cur_score) - std::floor(feat_sc._score)) > 1e-5)
         {
             continue;
         }
 
         util_funcs::rank(
-            std::get<0>(feat_sc)->value_ptr(-1, true), &RANK[omp_get_thread_num() * 4 * n_samp], &INDEX[omp_get_thread_num() * 2 * n_samp], n_samp
+            feat_sc._feat->value_ptr(-1, true), &RANK[omp_get_thread_num() * 4 * n_samp], &INDEX[omp_get_thread_num() * 2 * n_samp], n_samp
         );
         double comp_value = (
             base_val - std::abs(util_funcs::r(&RANK[omp_get_thread_num() * 4 * n_samp], &RANK[(omp_get_thread_num() * 4 + 2) * n_samp], n_samp))
@@ -470,7 +470,7 @@ bool comp_feats::valid_feature_against_selected_spearman_mpi_op(
     for(auto& feat_sc : out_vec)
     {
         util_funcs::rank(
-            std::get<0>(feat_sc)->value_ptr(-1, true), &RANK[omp_get_thread_num() * 4 * n_samp], &INDEX[omp_get_thread_num() * 2 * n_samp], n_samp
+            feat_sc._feat->value_ptr(-1, true), &RANK[omp_get_thread_num() * 4 * n_samp], &INDEX[omp_get_thread_num() * 2 * n_samp], n_samp
         );
         double comp_value = (
             base_val - std::abs(util_funcs::r(&RANK[omp_get_thread_num() * 4 * n_samp], &RANK[(omp_get_thread_num() * 4 + 2) * n_samp], n_samp))
diff --git a/src/utils/compare_features.hpp b/src/utils/compare_features.hpp
index b0084cb2..d8292039 100644
--- a/src/utils/compare_features.hpp
+++ b/src/utils/compare_features.hpp
@@ -26,7 +26,98 @@
 
 #include "feature_creation/node/Node.hpp"
 
-typedef std::tuple<node_ptr, double> node_sc_pair;
+struct node_sc_pair
+{
+    /**
+     * @brief Serialization function to send over MPI
+     *
+     * @param ar Archive representation of node
+     */
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & _feat;
+        ar & _score;
+    }
+    node_ptr _feat; //!< The feature
+    double _score; //!< The score
+
+    /**
+     * @brief Default Constructor
+     */
+    node_sc_pair():
+        _feat(nullptr),
+        _score(0.0)
+    {}
+
+    /**
+     * @brief Constructor
+     *
+     * @param feat The feature
+     * @param score The score
+     */
+    node_sc_pair(node_ptr feat, double score):
+        _feat(feat),
+        _score(score)
+    {}
+
+    /**
+     * @brief Copy Constructor
+     *
+     * @param o Node to be copied
+     */
+    node_sc_pair(const node_sc_pair& o) = default;
+
+    /**
+     * @brief Move Constructor
+     *
+     * @param o Node to be copied
+     */
+    node_sc_pair(node_sc_pair&& o) = default;
+
+    /**
+     * @brief Copy Assignment operator
+     *
+     * @param o Node to be copied
+     */
+    node_sc_pair& operator= (const node_sc_pair& o) = default;
+
+    /**
+     * @brief Move Assignment operator
+     *
+     * @param o Node to be moved
+     */
+    node_sc_pair& operator= (node_sc_pair&& o) = default;
+
+    /**
+     * @brief Less than operator
+     *
+     * @param pair_2 node_sc_pair to compare against
+     * @return True if _score is less than pair_2.score
+     */
+    inline bool operator<(node_sc_pair pair_2){return _score < pair_2._score;}
+    /**
+     * @brief Greater than operator
+     *
+     * @param pair_2 node_sc_pair to compare against
+     * @return True if _score is greater than pair_2.score
+     */
+    inline bool operator>(node_sc_pair pair_2){return _score > pair_2._score;}
+    /**
+     * @brief Less than  or equal to operator
+     *
+     * @param pair_2 node_sc_pair to compare against
+     * @return True if _score is less than or equal to  pair_2.score
+     */
+    inline bool operator<=(node_sc_pair pair_2){return _score <= pair_2._score;}
+    /**
+     * @brief Greater than  or equal to operator
+     *
+     * @param pair_2 node_sc_pair to compare against
+     * @return True if _score is greater than or equal to  pair_2.score
+     */
+    inline bool operator>=(node_sc_pair pair_2){return _score >= pair_2._score;}
+};
 
 namespace comp_feats
 {
diff --git a/tests/googletest/utils/test_compare_features.cc b/tests/googletest/utils/test_compare_features.cc
index cbf0ff1a..2c6bfb9e 100644
--- a/tests/googletest/utils/test_compare_features.cc
+++ b/tests/googletest/utils/test_compare_features.cc
@@ -27,11 +27,10 @@ namespace {
         std::vector<double> scores = {0.9897782665572893};
 
         std::vector<node_ptr> selected(1);
-        std::vector<node_sc_pair> mpi_op_sel(1);
 
         node_value_arrs::initialize_values_arr({4}, {0}, 1, 0, false);
         selected[0] = std::make_shared<FeatureNode>(0, "A", val_3, std::vector<double>(), Unit());
-        mpi_op_sel[0] = mpi_reduce_op::make_node_sc_pair(selected[0], scores[0]);
+        std::vector<node_sc_pair> mpi_op_sel(1, node_sc_pair(selected[0], scores[0]));
 
         node_value_arrs::initialize_d_matrix_arr();
         node_value_arrs::resize_d_matrix_arr(1);
-- 
GitLab