Exemplo n.º 1
0
dcMatrix dcMatrix::inverse()
{	
	if (nbRows!=nbCols)
	{
		cout << "ERROR [dcMatrix::inverse] : cannot inverse a non-square matrix!"<<endl;
		exit(1);
	}
	
	unsigned int n = nbCols;
	
	// Copy this dcMatrix unsigned into A
	dcMatrix A(n);
	for (unsigned int i=0; i<n; i++) {
		for (unsigned int j=0; j<n; j++) {
			A(i,j) = val[n*i+j];
		}
	}
	
	// get the determinant of A
	double det = A.determinant();
	
	if (det==0)
	{
		cout << "ERROR [dcMatrix::inverse] : cannot inverse matrix (determinant	=0)!"<<endl;
		exit(1);
	}
	
    double oneOverDet = 1.0/det;
	
	dcMatrix AInverse(n);
	
	if (n==2)
	{
		AInverse(0,0) = A(1,1)*oneOverDet;
		AInverse(0,1) = -A(0,1)*oneOverDet;
		AInverse(1,0) = -A(1,0)*oneOverDet;
		AInverse(1,1) = A(0,0)*oneOverDet;
	}
	
	if (n>2)
	{
		dcMatrix Aminor(n-1);
		
		for(unsigned int j=0;j<n;j++)
		{
			for(unsigned int i=0;i<n;i++)
			{
				// get the co-factor (matrix) of A(j,i)
				Aminor = A.getMinor(j,i);
				
				AInverse(i,j) = oneOverDet*Aminor.determinant(); 
				
				if( (i+j)%2 == 1)
					AInverse(i,j) = -AInverse(i,j);
			}
		}
	}
	
	return AInverse;
}
GaussJordan::Return_t
GaussJordan::solve(Matrix2D const & A, Vector const & f) const {
    // Solve the equation A x = f using Gauss-Jordan elimination with row pivoting.
    // Description of algorithm: First, search for the largest element in the current
    // column use it as the pivot element. This is to reduce round-off errors. The
    // matrix ACopy will be transformed into the identity matrix, while the identity
    // matrix, AInvwerse, will be transformed into the inverse.
    // A x =  Id y is successively transformed into A^{-1} A x = A^{-1} Id f,
    // where ACopy = Id and A^{-1} = AInverse.

    BOOST_ASSERT_MSG(A.cols() == A.rows(), "Gauss::solve: Matrix must be quadratic");
    BOOST_ASSERT_MSG(A.cols() == f.size(), "Gauss::solve: r.h.s. vector size mismatch");

    IMatrix2D::size_type max_col = A.cols();
    IMatrix2D::size_type max_row = A.rows();
    bool success = false;
    Matrix2D ACopy(A);
    Matrix2D AInverse(Matrix2D::identity(max_col));
    Vector rhs(f);

    initializePivoting(max_row);

    /* This is a column index, rather than a row index.
     * Obviously, this makes no difference for a square
     * matrix, but if #columns > #rows, the problem is
     * overspecified and then least-squares could be used.
     * The other extreme is an underspecified problem, which
     * we do not bother with at all here.
     */
    for (IMatrix2D::size_type col = 0; col < max_col; ++col) {
//         ACopy.print();
//         print(ACopy);
//         AInverse.print();
//         print(AInverse);

        auto physical_pivot_row_index = getPivotElementsRowIndex(ACopy, col);

        // "swap" rows 'col' and 'row_with_pivot_element' due to row pivoting
        adjustPivotingMap(col, physical_pivot_row_index);
        double pivot_element = ACopy(physical_pivot_row_index, col);
        if (pivot_element == 0.0)
            // Matrix is singular
            return std::make_tuple(false, AInverse, rhs);

        // Divide pivot row by pivot element to set pivot element to 1
        // as part of the reduction of ACopy to the identity matrix.
        // Note: Start column is 'col', as all elements with column
        // index (0, ..., col - 1) are 0 already.
        for (IMatrix2D::size_type i = 0; i < max_col; ++i) {
            if (i >= col) {
                double & val1 = ACopy(physical_pivot_row_index, i);
                val1 /= pivot_element;
            }
            double & val2 = AInverse(physical_pivot_row_index, i);
            val2 /= pivot_element;
        }

//         ACopy.print();
//         print(ACopy);
//         AInverse.print();
//         print(AInverse);

        // Do same transformation on the rhs
        rhs(physical_pivot_row_index) /= pivot_element;

        // Add pivot row to all later rows such that all elements
        // in those rows become 0, i.e. we set the column to the
        // column of the identity matrix.
        for (IMatrix2D::size_type i = 0; i < max_row; ++i) {
            auto mapped_i = logicalToPhysicalRowIndex(i);
            if (mapped_i == physical_pivot_row_index)
                // skip pivot row
                continue;
            double val = - ACopy(mapped_i, col) / ACopy(physical_pivot_row_index, col);

            // subtract the pivot row from row 'mapped_i'
            for (IMatrix2D::size_type j = 0; j < max_col; ++j) {
                if (j >= col)
                    ACopy(mapped_i, j) += val * ACopy(physical_pivot_row_index, j);
                AInverse(mapped_i, j) += val * AInverse(physical_pivot_row_index, j);
            }

            // do same transformation on the rhs
            rhs(mapped_i) += val * rhs(physical_pivot_row_index);

//             ACopy.print();
//             print(ACopy);
//             AInverse.print();
//             print(AInverse);
        }

//         ACopy.print();
//         print(ACopy);
//         AInverse.print();
//         print(AInverse);
    }

//     AInverse.print();
//     print(AInverse);

    // Rearrange the rows in AInverse due to pivoting
    rearrangeDueToPivoting(ACopy, AInverse, rhs);

//     ACopy.print();
//     AInverse.print();

    return std::make_tuple(success, AInverse, rhs);
}