Search for row number of maximum value in matrix column Background

I'm writing code that searches for the row number of the maximum value in a partial column of a matrix.  The partial column corresponds with the non-zero values of an equivalent lower triangular matrix.  That is, starting from the input row index idx through the final row. (This is my own version of subroutine for Gaussian Elimination with Partial Pivoting, for those who are interested).

Basically, the behavior of MaxLocColumnWise is the search of columnwise maximum location in the submatrices of A. Passing by reference, MaxLocColumnWise changes the value of k.

For example, for the following matrix
$$
A = \begin{bmatrix}1 &amp; 2 &amp; 3 \\
4 &amp; 5 &amp; 6 \\
7 &amp; 8 &amp; 9 
\end{bmatrix}
$$


when k=0, MaxLocColumnWise(A,k) converts k to the index of maximum element in [1,4,7], which is 2, which is the index of 7 i.e. we get 2 as a result of


    int k = 0;
    `MaxLocColumnWise(A,k)`;
    std::cout &lt;&lt; k &lt;&lt;"\n";



when k=1, MaxLocColumnWise(A,k) converts k to the index of maximum element in [5,8], which is 2, which is the index of 8. (This case is highlighted in red here)
when k=2, MaxLocColumnWise(A,k) converts k to the index of maximum element in [9], which is 2, which is the index of 9 




Code

Interestingly it turns out that the following code takes quite long time. 

void MaxLocColumnWise(Matrix A, int &amp;idx){
    int n = A.size();
    int col = idx;

    double currentAbsMax = abs(A[col][col]);

    for (int i=(col+1); i&lt;n; i++){
        double currentVal = abs(A[i][col]);
        if (currentVal &gt; currentAbsMax){
            currentAbsMax = currentVal;
            idx = i;
        }       
    }
}




I have implemented this subroutine to the following Gaussian elimination with partial pivoting routine:

void GaussElimPartialPivot(Matrix&amp; A, Vector&amp; b){
    int n = A.size();

    for (int j=0; j&lt;(n-1); j++){
        int index = j; 
        MaxLocColumnWise(A, index);
        SwapMatrixRows(A, j, index);
        SwapVector(b, j, index);

        // main loop
        for (int i=(j+1); i&lt;n; i++){
            double m = A[i][j]/A[j][j];
            b[i] -= m*b[j];
            for(int k=j; k&lt;n; k++){
                A[i][k] -= m*A[j][k];
            }
        }
    }
}


But when A gets large, the program gets slower exactly due to the subroutine MaxLocColumnWise, which was verified from excluding each subroutine in the main code. 

But I'm not sure exactly where in MaxLocColumnWise() to blame. Any help will be appreciated.

(An excuse for the exclusion of the code : Matrix is just from typedef std::vector&lt;Vector&gt; Matrix;, and the Vector is typedef std::vector&lt;double&gt; Vector;)
I see a number of things that may help you improve your code.

Pass by const reference where practical

The first argument to MaxLocColumnWise is a Matrix but that causes the entire input matrix to be duplicated.  Better would be to make it const Matrix &amp; because it is not modified and it doesn't need to be duplicated.  This is very likely the crux of your code's performance problem.   On my machine with a matrix of size 1000, that single change drops the execution time down from 3.1 seconds to 11 milliseconds.

Prefer return value over reference

Instead of modifying one of the passed parameters, it's often better to return a value instead.  So in this case, the function would be 

int MaxLocColumnWise(const Matrix &amp;A, int idx);


Check parameters before use

If idx is a negative number or beyond the end of the Matrix, your program will invoke undefined behavior and it could crash or worse.  Better would be to verify the value is in a valid range before use.  

Use appropriate data types

An index into an array is never negative, so instead of int, I'd recommend using std::size_t.  

Provide complete code to reviewers

This is not so much a change to the code as a change in how you present it to other people.  Without the full context of the code and an example of how to use it, it takes more effort for other people to understand your code.  This affects not only code reviews, but also maintenance of the code in the future, by you or by others.  One good way to address that is by the use of comments.  Another good technique is to include test code showing how your code is intended to be used.  I split your code into a header Gauss.h and implementation file Gauss.cpp and then created a test driver.  These are the resulting files, after applying all of the suggestions above:

Gauss.h

#ifndef GAUSS_H
#define GAUSS_H
#include &lt;vector&gt;
typedef std::vector&lt;double&gt; Vector;
typedef std::vector&lt;Vector&gt; Matrix;
std::size_t MaxLocColumnWise(const Matrix &amp;A, std::size_t idx);
void GaussElimPartialPivot(Matrix&amp; A, Vector&amp; b);
#endif // GAUSS_H


Gauss.cpp

#include "Gauss.h"
#include &lt;cmath&gt;

std::size_t MaxLocColumnWise(const Matrix &amp;A, std::size_t idx){
    auto maxIndex{idx};
    const auto col{idx};
    for (double maxValue{-1}; idx &lt; A.size(); ++idx)  {
        auto currentVal{std::abs(A[idx][col])};
        if (currentVal &gt; maxValue){
                maxValue = currentVal;
                maxIndex = idx;
        }       
    }
    return maxIndex;
}

void GaussElimPartialPivot(Matrix&amp; A, Vector&amp; b) {
    const std::size_t n{A.size()};
    for (std::size_t j{1}; j &lt; n; ++j) {
        auto maxcol{MaxLocColumnWise(A, j)};
        SwapMatrixRows(A, j, maxcol);
        SwapVector(b, j, maxcol);
        for (std::size_t i{j-1}; i &lt; n; ++i) {
            double m{A[i][j]/A[j][j]};
            b[i] -= m*b[j];
            for (auto k{j}; k &lt; n; ++k){
                A[i][k] -= m*A[j][k];
            }
        }
    }
}


main.cpp

#include "Gauss.h"
#include &lt;iostream&gt;
#include &lt;numeric&gt;

int main() {
    constexpr size_t n{1000};
    Matrix m;
    m.reserve(n);
    int startval{1};
    for (size_t i{0}; i &lt; n; ++i) {
        Vector v(n);
        std::iota(v.begin(), v.end(), startval);
        m.push_back(v);
        startval += n;
    }
    for (int i=0; i &lt; n; ++i) {
        auto max{MaxLocColumnWise(m, i)};
        if (max != n-1) {
            std::cout &lt;&lt; "Error:" &lt;&lt; i &lt;&lt; ", " &lt;&lt; MaxLocColumnWise(m, i) &lt;&lt; '\n';
        }
    }
}