A lite library for operations in linear algebra

MATRIX_PRIMITIVE.cpp

Committer:
benson516
Date:
2017-02-10
Revision:
0:33b75d52d2a7

File content as of revision 0:33b75d52d2a7:

#include "MATRIX_PRIMITIVE.h"

//
// using namespace MATRIX_PRIMITIVE;
//

// Namespace MATRIX_PRIMITIVE
//////////////////////////
namespace MATRIX_PRIMITIVE
{
// Utilities
///////////////////////////
void Mat_multiply_Vec(vector<float> &v_out, vector<vector<float> > &m_left, vector<float> &v_right){ // v_out = m_left*v_right
    vector<float>::iterator it_out;
    vector<float>::iterator it_m_row;
    vector<float>::iterator it_v;
    //
    it_out = v_out.begin();
    for (size_t i = 0; i < m_left.size(); ++i){
        *it_out = 0.0;
        it_m_row = m_left[i].begin();
        it_v = v_right.begin();
        for (size_t j = 0; j < m_left[i].size(); ++j){
            // *it_out += m_left[i][j] * v_right[j];
            if (*it_m_row != 0.0 && *it_v != 0.0){
                (*it_out) += (*it_m_row) * (*it_v);
            }else{
                // (*it_out) += 0.0
            }
            // (*it_out) += (*it_m_row) * (*it_v);
            //
            it_m_row++;
            it_v++;
        }
        it_out++;
    }
}
vector<float> Mat_multiply_Vec(vector<vector<float> > &m_left, vector<float> &v_right){ // v_out = m_left*v_right
    static vector<float> v_out;
    // Size check
    if (v_out.size() != m_left.size()){
        v_out.resize(m_left.size());
    }
    // Iterators
    vector<float>::iterator it_out;
    vector<float>::iterator it_m_row;
    vector<float>::iterator it_v;
    //
    it_out = v_out.begin();
    for (size_t i = 0; i < m_left.size(); ++i){
        *it_out = 0.0;
        it_m_row = m_left[i].begin();
        it_v = v_right.begin();
        for (size_t j = 0; j < m_left[i].size(); ++j){
            // *it_out += m_left[i][j] * v_right[j];
            if (*it_m_row != 0.0 && *it_v != 0.0){
                (*it_out) += (*it_m_row) * (*it_v);
            }else{
                // (*it_out) += 0.0
            }
            // (*it_out) += (*it_m_row) * (*it_v);
            //
            it_m_row++;
            it_v++;
        }
        it_out++;
    }
    return v_out;
}

// New function for matrix multiply matrix
vector<vector<float> > Mat_multiply_Mat(vector<vector<float> > &m_left, vector<vector<float> > &m_right){ // m_out = m_left*m_right
    static vector<vector<float> > m_out;

    // mxn = (mxk)*(kxn)
    size_t M, K, N;
    //
    M = m_left.size();
    K = m_left[0].size();
    N = m_right[0].size();

    // Size check
    if (m_out.size() != M || m_out[0].size() != N ){
        m_out.resize(M, vector<float>( N ) );
    }

    // Using indexing
    for (size_t i = 0; i < M; ++i){ // row in m_out
        for (size_t j = 0; j < N; ++j){ // column in m_out
            m_out[i][j] = 0.0;
            for (size_t k = 0; k < K; ++k){
                if (m_left[i][k] != 0.0 && m_right[k][j] != 0.0)
                    m_out[i][j] += m_left[i][k]*m_right[k][j];
            }
        }
    }

    return m_out;
}

vector<float> Get_VectorPlus(const vector<float> &v_a, const vector<float> &v_b, bool is_minus) // v_a + (or -) v_b
{
    static vector<float> v_c;
    // Size check
    if (v_c.size() != v_a.size()){
        v_c.resize(v_a.size());
    }
    //
    for (size_t i = 0; i < v_a.size(); ++i){
        if (is_minus){
            v_c[i] = v_a[i] - v_b[i];
        }else{
            v_c[i] = v_a[i] + v_b[i];
        }
    }
    return v_c;
}
vector<float> Get_VectorScalarMultiply(const vector<float> &v_a, float scale) // scale*v_a
{
    static vector<float> v_c;
    // Size check
    if (v_c.size() != v_a.size()){
        v_c.resize(v_a.size());
    }
    // for pure negative
    if (scale == -1.0){
        for (size_t i = 0; i < v_a.size(); ++i){
            v_c[i] = -v_a[i];
        }
        return v_c;
    }
    // else
    for (size_t i = 0; i < v_a.size(); ++i){
        v_c[i] = scale*v_a[i];

    }
    return v_c;
}

// Important!
// New function for scale-up a vector
// v_a *= scale
void Get_VectorScaleUp(vector<float> &v_a, float scale) // v_a *= scale
{
    // for pure negative
    if (scale == -1.0){
        for (size_t i = 0; i < v_a.size(); ++i){
            v_a[i] = -v_a[i];
        }
        //
    }else{
        // else
        for (size_t i = 0; i < v_a.size(); ++i){
            v_a[i] *= scale;
        }
        //
    }
}

// Increment
void Get_VectorIncrement(vector<float> &v_a, const vector<float> &v_b, bool is_minus){ // v_a += (or -=) v_b
    // Size check
    if (v_a.size() != v_b.size()){
        v_a.resize(v_b.size());
    }
    //
    if (is_minus){ // -=
        for (size_t i = 0; i < v_b.size(); ++i){
            v_a[i] -= v_b[i];
        }
    }else{ // +=
        for (size_t i = 0; i < v_b.size(); ++i){
            v_a[i] += v_b[i];
        }
    }

}
/////////////////////////// end Utilities


// Matrix inversion, using Gauss method
/////////////////////////////////////////
bool SolveSingularityOnDiag(vector<vector<float> > &M, vector<vector<float> > &M_inv, size_t i){
    // Return value: is_singular
    //-----------------------------------//
    // true: the matrix is singular
    // false: the singularity is not yet been found or the matrix is invertible
    //-----------------------------------//


    // For ith-row
    //-----------------------------------//
    // If the ith element on diagonal is zero, find a row with it ith elemnt non-zero and add to the current row (ith row)
    // For both M and M_inv

    size_t n = M.size();
    // Search for other non-zero elements
    float max_absValue = 0.0;
    size_t idx_max = i;

    // The following block of code is wrong.
    /*
    for (size_t j = 0; j < n; ++j){
        if (j != i){ // Other than i
            float absValue = fabs(M[j][i]);
            if ( absValue > max_absValue){
                max_absValue = absValue;
                idx_max = j;
                //
                // break; // Once found a non-zero element, break it (Not going to find the maximum one)
                //
            }
        }
    }
    */

    // It's sufficient and "should" only looking downward
    for (size_t j = (i+1); j < n; ++j){
        // Below ith-row
        float absValue = fabs(M[j][i]);
        if ( absValue > max_absValue){
            max_absValue = absValue;
            idx_max = j;
            //
            // break; // Once found a non-zero element, break it (Not going to find the maximum one)
            //
        }
        //
    }

    //
    if (idx_max == i){ // The matrix is singular !!
        return true; // is_singular
    }

    // Add that row to the current row
    Get_VectorIncrement(M[i], M[idx_max], false); // +=
    Get_VectorIncrement(M_inv[i], M_inv[idx_max], false); // +=
    //
    return false; // may be non-singular
}
vector<vector<float> > MatrixInversion(vector<vector<float> > M){
    //
    size_t n = M.size(); // The size of the square matrix

    // Check if M is a square matrix
    if (n != M[0].size()){
        return M;
    }

    // Output matrix
    vector<vector<float> > M_inv(n,vector<float>(n, 0.0));

    // Initialize the identity matrix M_inv
    for (size_t i = 0; i < n; ++i){
        M_inv[i][i] = 1.0;
    }

    //
    // cout << "M_inv:\n";
    // printMatrix(M_inv);


    // A row vector
    vector<float> row_left;
    vector<float> row_right;
    float M_diag = 1.0;

    /*
    // Check if each element on diagonal is not zero
    // If it is zero, find a row with a non-zero element on that column and add that row to the current row
    for (size_t i = 0; i < n; ++i){
        M_diag = M[i][i];
        if (M_diag == 0.0){
            // Search for other non-zero elements
            // SolveSingularityOnDiag(M, M_inv, i);

            // Search for other non-zero elements
            float max_absValue = 0.0;
            size_t idx_max = i;
            for (size_t j = 0; j < n; ++j){
                if (j != i){ // Other that i
                    float absValue = fabs(M[j][i]);
                    if ( absValue > max_absValue){
                        max_absValue = absValue;
                        idx_max = j;
                    }
                }
            }
            // Add that row to the current row
            Get_VectorIncrement(M[i], M[idx_max], false); // +=
            Get_VectorIncrement(M_inv[i], M_inv[idx_max], false); // +=
            //

        }else{
            // Fine! Nothing to do.
        }
    }
    */

    //
    /*
    cout << "M:\n";
    printMatrix(M);
    //
    cout << "M_inv:\n";
    printMatrix(M_inv);
    */
    //

    /*
    // Scale each row vector for normalizing each elements on the diagonal to 1.0
    for (size_t i = 0; i < n; ++i){
        float ratio;
        ratio = 1.0/M[i][i];
        //
        Get_VectorScaleUp(M[i], ratio);
        Get_VectorScaleUp(M_inv[i], ratio);
        //
        // M[i] = Get_VectorScalarMultiply(M[i], ratio);
        // M_inv[i] = Get_VectorScalarMultiply(M_inv[i], ratio);
        //
    }
    */

    /*
    //
    cout << "M:\n";
    printMatrix(M);
    //
    cout << "M_inv:\n";
    printMatrix(M_inv);
    //
    */

    //
    // The flag for singularity
    bool is_singular = false;
    //

    // Eliminate all the other elements except those on the diagonal
    for (size_t i = 0; i < n; ++i){ // For each element on diagonal
        float ratio;

        // For solving the problem of that diagonal element is zero
        if (M[i][i] == 0.0){
            is_singular |= SolveSingularityOnDiag(M, M_inv, i);
        }

        //
        if (is_singular){
            // The matrix is singular,
            // stop this meaningless process and return.
            // break;
            return M_inv;
        }

        // Normalize the diagonal element in M to 1.0
        if (M[i][i] != 1.0){
            ratio = 1.0/M[i][i];
            Get_VectorScaleUp(M[i], ratio);
            Get_VectorScaleUp(M_inv[i], ratio);
        }
        //

        //
        row_left = M[i];
        row_right = M_inv[i];
        //
        // M_diag = M[i][i]; // This has been normalized, which is 1.0
        //
        for (size_t j = 0; j < n; ++j){ // For the row other than than the current row
            if (j != i){ // Not going to do anything with that row itself
                //
                // ratio = M[j][i]/M_diag;
                ratio = M[j][i]; // Because M_diag = 1.0
                Get_VectorIncrement(M[j], Get_VectorScalarMultiply(row_left, ratio), true); // -=
                Get_VectorIncrement(M_inv[j], Get_VectorScalarMultiply(row_right, ratio), true); // -=
                //
                /*
                Get_VectorIncrement(M[j], Get_VectorScalarMultiply(M[i], ratio), true); // -=
                Get_VectorIncrement(M_inv[j], Get_VectorScalarMultiply(M_inv[i], ratio), true); // -=
                */
            }
        }

        /*
        //
        cout << "Diagonal element i = " << i << "\n";
        //
        cout << "M:\n";
        printMatrix(M);
        //
        cout << "M_inv:\n";
        printMatrix(M_inv);
        */
    }
    return M_inv;

}
///////////////////////////////////////// end Matrix inversion, using Gauss method


}
////////////////////////// end Namespace MATRIX_PRIMITIVE