From 108375c3a28fba3903991c1727a2c9af90caeb8f Mon Sep 17 00:00:00 2001
From: Abdullah Alperen <alperena@msu.edu>
Date: Thu, 15 Feb 2018 21:27:23 -0500
Subject: [PATCH] quick select method added for choosing the k largest elements
 for SAI

---
 sPuReMD/src/lin_alg.c | 98 +++++++++++++++++++++++++++++++------------
 1 file changed, 72 insertions(+), 26 deletions(-)

diff --git a/sPuReMD/src/lin_alg.c b/sPuReMD/src/lin_alg.c
index 4f69152b..45d5e50e 100644
--- a/sPuReMD/src/lin_alg.c
+++ b/sPuReMD/src/lin_alg.c
@@ -277,14 +277,14 @@ static void compute_full_sparse_matrix( const sparse_matrix * const A,
  *   A has non-zero diagonals
  *   Each row of A has at least one non-zero (i.e., no rows with all zeros) */
 void setup_sparse_approx_inverse( const sparse_matrix * const A, sparse_matrix ** A_full,
-                                  sparse_matrix ** A_spar_patt, sparse_matrix **A_spar_patt_full,
-                                  sparse_matrix ** A_app_inv, const real filter )
+              sparse_matrix ** A_spar_patt, sparse_matrix **A_spar_patt_full,
+                    sparse_matrix ** A_app_inv, const real filter )
 {
     int i, pj, size;
-    real min, max, threshold, val;
-
-    min = 0.0;
-    max = 0.0;
+    int left, right, k, p, turn;
+    real pivot, tmp;
+    real threshold;
+    real *list;
 
     if ( *A_spar_patt == NULL )
     {
@@ -304,34 +304,78 @@ void setup_sparse_approx_inverse( const sparse_matrix * const A, sparse_matrix *
         }
     }
 
-    /* find min and max elements of matrix */
-    for ( i = 0; i < A->n; ++i )
+
+    /* quick-select algorithm for finding the kth greatest element in the matrix*/
+    /* list: values from the matrix*/
+    /* left-right: search space of the quick-select */
+
+    list = (real *) smalloc( sizeof(real) * (A->start[A->n]),"Sparse_Approx_Inverse::list" );
+
+    left = 0;
+    right = A->start[A->n] - 1;
+    k = (int)( (A->start[A->n])*filter );
+    threshold = 0.0;
+
+    for( i = left; i <= right ; ++i )
     {
-        for ( pj = A->start[i]; pj < A->start[i + 1]; ++pj )
+        list[i] = abs( A->val[i] );
+    }
+
+    turn = 0;
+    while( k ) {
+
+        p  = left;
+        turn = 1 - turn;
+        if( turn == 1)
         {
-            val = A->val[pj];
-            if ( pj == 0 )
+            pivot = list[right];
+        }
+        else
+        {
+            pivot = list[left];
+        }
+        for( i = left + 1 - turn; i <= right-turn; ++i )
+        {
+            if( list[i] > pivot )
             {
-                min = val;
-                max = val;
-            }
-            else
-            {
-                if ( min > val )
-                {
-                    min = val;
-                }
-                if ( max < val )
-                {
-                    max = val;
-                }
+                tmp = list[i];
+                list[i] = list[p];
+                list[p] = tmp;
+                p++;
             }
         }
+        if(turn == 1)
+        {
+            tmp = list[p];
+            list[p] = list[right];
+            list[right] = tmp;
+        }
+        else
+        {
+            tmp = list[p];
+            list[p] = list[left];
+            list[left] = tmp;
+        }
+
+        if( p == k - 1)
+        {
+            threshold = list[p];
+            break;
+        }
+        else if( p > k - 1 )
+        {
+            right = p - 1;
+        }
+        else
+        {
+            left = p + 1;
+        }
     }
 
-    threshold = min + (max - min) * (1.0 - filter);
+    sfree( list, "setup_sparse_approx_inverse::list" );
 
     /* fill sparsity pattern */
+    /* diagonal entries are always included */
     for ( size = 0, i = 0; i < A->n; ++i )
     {
         (*A_spar_patt)->start[i] = size;
@@ -348,11 +392,12 @@ void setup_sparse_approx_inverse( const sparse_matrix * const A, sparse_matrix *
     }
     (*A_spar_patt)->start[A->n] = size;
 
+
     compute_full_sparse_matrix( A, A_full );
     compute_full_sparse_matrix( *A_spar_patt, A_spar_patt_full );
 
     /* A_app_inv has the same sparsity pattern
-     * as A_spar_patt_full (omit non-zero values) */
+     * * as A_spar_patt_full (omit non-zero values) */
     if ( Allocate_Matrix( A_app_inv, (*A_spar_patt_full)->n, (*A_spar_patt_full)->m ) == FAILURE )
     {
         fprintf( stderr, "not enough memory for approximate inverse matrix. terminating.\n" );
@@ -360,6 +405,7 @@ void setup_sparse_approx_inverse( const sparse_matrix * const A, sparse_matrix *
     }
 }
 
+
 void Calculate_Droptol( const sparse_matrix * const A,
                         real * const droptol, const real dtol )
 {
-- 
GitLab