Gauss Elimination for NxM matrix

后端 未结 3 561
半阙折子戏
半阙折子戏 2021-02-02 04:29
/* Program to demonstrate gaussian elimination
   on a set of linear simultaneous equations
 */

#include 

        
3条回答
  •  长情又很酷
    2021-02-02 05:13

    You can apply echelon reduction, like in this snippet

    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    /*
    A rectangular matrix is in echelon form(or row echelon form) if it has the following 
        three properties :
    1. All nonzero rows are above any rows of all zeros.
    2. Each leading entry of a row is in a column to the right of the leading entry of
        the row above it.
    3. All entries in a column below a leading entry are zeros.
    
    If a matrix in echelon form satisfies the following additional conditions, 
        then it is in reduced echelon form(or reduced row echelon form) :
    4. The leading entry in each nonzero row is 1.
    5. Each leading 1 is the only nonzero entry in its column.                            
    */
    
    template  void print(const C& c) {
        for (const auto& e : c) {
            cout << setw(10) << right << e;
        }
    
        cout << endl;
    }
    template  void print2(const C& c) {
        for (const auto& e : c) {
            print(e);
        }
    
        cout << endl;
    }
    
    // input matrix consists of rows, which are vectors of double
    vector> Gauss::Reduce(const vector>& matrix)
    {
        if (matrix.size() == 0)
            throw string("Empty matrix");
        auto A{ matrix };
        auto mima = minmax_element(A.begin(), A.end(), [](const vector& a, const vector& b) {return a.size() < b.size(); });
        auto mi = mima.first - A.begin(), ma = mima.second - A.begin();
        if (A[mi].size() != A[ma].size())
            throw string("All rows shall have equal length");
        size_t height = A.size();
        size_t width = A[0].size();
        if (width == 0)
            throw string("Only empty rows");
    
        for (size_t row = 0; row != height; row++) {
            cout << "processing row " << row << endl;
    
            // Search for maximum below current row in column row and move it to current row; skip this step on the last one
            size_t col{ row }, maxRow{ 0 };
            // find pivot for current row (partial pivoting)
            while (col < width)
            {
                maxRow = distance(A.begin(), max_element(A.begin() + row, A.end(), [col](const vector& rowVectorA, const vector& rowVectorB) {return abs(rowVectorA[col]) < abs(rowVectorB[col]); }));
                if (A[maxRow][col] != 0)    // nonzero in this row and column or below found
                    break;
                ++col;
            }
            if (col == width)   // e.g. in current row and below all entries are zero 
                break;
            if (row != maxRow)
            {
                swap(A[row], A[maxRow]);
                cout << "swapped " << row << " and " << maxRow;
            }
            cout << " => leading entry in column " << col << endl;
    
            print2(A);
            // here col >= row holds; col is the column of the leading entry e.g. first nonzero column in current row
            // moreover, all entries to the left and below are zeroed
            if (row+1 < height)
                cout << "processing column " << col << endl;
    
            // Make in all rows below this one 0 in current column
            for (size_t rowBelow = row + 1; rowBelow < height; rowBelow++) {
                // subtract product of current row by factor
                double factor = A[rowBelow][col] / A[row][col];
                cout << "processing row " << rowBelow << " below the current; factor is " << factor << endl;
                if (factor == 0)
                    continue;
                for (size_t colRight{ col }; colRight < width; colRight++)
                {
                    auto d = A[rowBelow][colRight] - factor * A[row][colRight];
                    A[rowBelow][colRight] = abs(d) < DBL_EPSILON ? 0 : d;
                }
                print(A[rowBelow]);
            }
        }
        // the matrix A is in echelon form now
        cout << "matrix in echelon form" << endl;
        print2(A);
        // reduced echelon form follows (backward phase)
        size_t row(height-1);
        auto findPivot = [&row, A] () -> size_t {
            do
            {
                auto pos = find_if(A[row].begin(), A[row].end(), [](double d) {return d != 0; });
                if (pos != A[row].end())
                    return pos - A[row].begin();
            } while (row-- > 0);
            return  A[0].size();
        };
        do
        {
            auto col = findPivot(); 
            if (col == width)
                break;
            cout << "processing row " << row << endl;
            if (A[row][col] != 1)
            {
                //scale row row to make element at [row][col] equal one
                auto f = 1 / A[row][col];
                transform(A[row].begin()+col, A[row].end(), A[row].begin()+col, [f](double d) {return d * f; });            
            }
            auto rowAbove{ row};
            while (rowAbove > 0)
            {
                rowAbove--;
                double factor = A[rowAbove][col];
                if (abs(factor) > 0)
                {
                    for (auto colAbove{ 0 }; colAbove < width; colAbove++)
                    {
                        auto d = A[rowAbove][colAbove] - factor * A[row][colAbove];
                        A[rowAbove][colAbove] = abs(d) < DBL_EPSILON ? 0 : d;                   
                    }
                    cout << "transformed row " << rowAbove << endl;
                    print(A[rowAbove]);
                }
            }
        } while (row-- > 0);
    
        return A;
    }
    

提交回复
热议问题