Simple 3x3 matrix inverse code (C++)

后端 未结 13 2015
花落未央
花落未央 2020-12-04 19:35

What\'s the easiest way to compute a 3x3 matrix inverse?

I\'m just looking for a short code snippet that\'ll do the trick for non-singular matrices, possibly using C

相关标签:
13条回答
  • 2020-12-04 19:56

    I would also recommend Ilmbase, which is part of OpenEXR. It's a good set of templated 2,3,4-vector and matrix routines.

    0 讨论(0)
  • 2020-12-04 19:57

    I went ahead and wrote it in python since I think it's a lot more readable than in c++ for a problem like this. The function order is in order of operations for solving this by hand via this video. Just import this and call "print_invert" on your matrix.

    def print_invert (matrix):
      i_matrix = invert_matrix (matrix)
      for line in i_matrix:
        print (line)
      return
    
    def invert_matrix (matrix):
      determinant = str (determinant_of_3x3 (matrix))
      cofactor = make_cofactor (matrix)
      trans_matrix = transpose_cofactor (cofactor)
    
      trans_matrix[:] = [[str (element) +'/'+ determinant for element in row] for row in trans_matrix]
    
      return trans_matrix
    
    def determinant_of_3x3 (matrix):
      multiplication = 1
      neg_multiplication = 1
      total = 0
      for start_column in range (3):
        for row in range (3):
          multiplication *= matrix[row][(start_column+row)%3]
          neg_multiplication *= matrix[row][(start_column-row)%3]
        total += multiplication - neg_multiplication
        multiplication = neg_multiplication = 1
      if total == 0:
        total = 1
      return total
    
    def make_cofactor (matrix):
      cofactor = [[0,0,0],[0,0,0],[0,0,0]]
      matrix_2x2 = [[0,0],[0,0]]
      # For each element in matrix...
      for row in range (3):
        for column in range (3):
    
          # ...make the 2x2 matrix in this inner loop
          matrix_2x2 = make_2x2_from_spot_in_3x3 (row, column, matrix)
          cofactor[row][column] = determinant_of_2x2 (matrix_2x2)
    
      return flip_signs (cofactor)
    
    def make_2x2_from_spot_in_3x3 (row, column, matrix):
      c_count = 0
      r_count = 0
      matrix_2x2 = [[0,0],[0,0]]
      # ...make the 2x2 matrix in this inner loop
      for inner_row in range (3):
        for inner_column in range (3):
          if row is not inner_row and inner_column is not column:
            matrix_2x2[r_count % 2][c_count % 2] = matrix[inner_row][inner_column]
            c_count += 1
        if row is not inner_row:
          r_count += 1
      return matrix_2x2
    
    def determinant_of_2x2 (matrix):
      total = matrix[0][0] * matrix [1][1]
      return total - (matrix [1][0] * matrix [0][1])
    
    def flip_signs (cofactor):
      sign_pos = True 
      # For each element in matrix...
      for row in range (3):
        for column in range (3):
          if sign_pos:
            sign_pos = False
          else:
            cofactor[row][column] *= -1
            sign_pos = True
      return cofactor
    
    def transpose_cofactor (cofactor):
      new_cofactor = [[0,0,0],[0,0,0],[0,0,0]]
      for row in range (3):
        for column in range (3):
          new_cofactor[column][row] = cofactor[row][column]
      return new_cofactor
    
    0 讨论(0)
  • 2020-12-04 19:58
    //Title: Matrix Header File
    //Writer: Say OL
    //This is a beginner code not an expert one
    //No responsibilty for any errors
    //Use for your own risk
    using namespace std;
    int row,col,Row,Col;
    double Coefficient;
    //Input Matrix
    void Input(double Matrix[9][9],int Row,int Col)
    {
        for(row=1;row<=Row;row++)
            for(col=1;col<=Col;col++)
            {
                cout<<"e["<<row<<"]["<<col<<"]=";
                cin>>Matrix[row][col];
            }
    }
    //Output Matrix
    void Output(double Matrix[9][9],int Row,int Col)
    {
        for(row=1;row<=Row;row++)
        {
            for(col=1;col<=Col;col++)
                cout<<Matrix[row][col]<<"\t";
            cout<<endl;
        }
    }
    //Copy Pointer to Matrix
    void CopyPointer(double (*Pointer)[9],double Matrix[9][9],int Row,int Col)
    {
        for(row=1;row<=Row;row++)
            for(col=1;col<=Col;col++)
                Matrix[row][col]=Pointer[row][col];
    }
    //Copy Matrix to Matrix
    void CopyMatrix(double MatrixInput[9][9],double MatrixTarget[9][9],int Row,int Col)
    {
        for(row=1;row<=Row;row++)
            for(col=1;col<=Col;col++)
                MatrixTarget[row][col]=MatrixInput[row][col];
    }
    //Transpose of Matrix
    double MatrixTran[9][9];
    double (*(Transpose)(double MatrixInput[9][9],int Row,int Col))[9]
    {
        for(row=1;row<=Row;row++)
            for(col=1;col<=Col;col++)
                MatrixTran[col][row]=MatrixInput[row][col];
        return MatrixTran;
    }
    //Matrix Addition
    double MatrixAdd[9][9];
    double (*(Addition)(double MatrixA[9][9],double MatrixB[9][9],int Row,int Col))[9]
    {
        for(row=1;row<=Row;row++)
            for(col=1;col<=Col;col++)
                MatrixAdd[row][col]=MatrixA[row][col]+MatrixB[row][col];
        return MatrixAdd;
    }
    //Matrix Subtraction
    double MatrixSub[9][9];
    double (*(Subtraction)(double MatrixA[9][9],double MatrixB[9][9],int Row,int Col))[9]
    {
        for(row=1;row<=Row;row++)
            for(col=1;col<=Col;col++)
                MatrixSub[row][col]=MatrixA[row][col]-MatrixB[row][col];
        return MatrixSub;
    }
    //Matrix Multiplication
    int mRow,nCol,pCol,kcol;
    double MatrixMult[9][9];
    double (*(Multiplication)(double MatrixA[9][9],double MatrixB[9][9],int mRow,int nCol,int pCol))[9]
    {
        for(row=1;row<=mRow;row++)
            for(col=1;col<=pCol;col++)
            {
                MatrixMult[row][col]=0.0;
                for(kcol=1;kcol<=nCol;kcol++)
                    MatrixMult[row][col]+=MatrixA[row][kcol]*MatrixB[kcol][col];
            }
        return MatrixMult;
    }
    //Interchange Two Rows
    double RowTemp[9][9];
    double MatrixInter[9][9];
    double (*(InterchangeRow)(double MatrixInput[9][9],int Row,int Col,int iRow,int jRow))[9]
    {
        CopyMatrix(MatrixInput,MatrixInter,Row,Col);
        for(col=1;col<=Col;col++)
        {
            RowTemp[iRow][col]=MatrixInter[iRow][col];
            MatrixInter[iRow][col]=MatrixInter[jRow][col];
            MatrixInter[jRow][col]=RowTemp[iRow][col];
        }
        return MatrixInter;
    }
    //Pivote Downward
    double MatrixDown[9][9];
    double (*(PivoteDown)(double MatrixInput[9][9],int Row,int Col,int tRow,int tCol))[9]
    {
        CopyMatrix(MatrixInput,MatrixDown,Row,Col);
        Coefficient=MatrixDown[tRow][tCol];
        if(Coefficient!=1.0)
            for(col=1;col<=Col;col++)
                MatrixDown[tRow][col]/=Coefficient;
        if(tRow<Row)
            for(row=tRow+1;row<=Row;row++)
            {
                Coefficient=MatrixDown[row][tCol];
                for(col=1;col<=Col;col++)
                    MatrixDown[row][col]-=Coefficient*MatrixDown[tRow][col];
            }
    return MatrixDown;
    }
    //Pivote Upward
    double MatrixUp[9][9];
    double (*(PivoteUp)(double MatrixInput[9][9],int Row,int Col,int tRow,int tCol))[9]
    {
        CopyMatrix(MatrixInput,MatrixUp,Row,Col);
        Coefficient=MatrixUp[tRow][tCol];
        if(Coefficient!=1.0)
            for(col=1;col<=Col;col++)
                MatrixUp[tRow][col]/=Coefficient;
        if(tRow>1)
            for(row=tRow-1;row>=1;row--)
            {
                Coefficient=MatrixUp[row][tCol];
                for(col=1;col<=Col;col++)
                    MatrixUp[row][col]-=Coefficient*MatrixUp[tRow][col];
            }
        return MatrixUp;
    }
    //Pivote in Determinant
    double MatrixPiv[9][9];
    double (*(Pivote)(double MatrixInput[9][9],int Dim,int pTarget))[9]
    {
        CopyMatrix(MatrixInput,MatrixPiv,Dim,Dim);
        for(row=pTarget+1;row<=Dim;row++)
        {
            Coefficient=MatrixPiv[row][pTarget]/MatrixPiv[pTarget][pTarget];
            for(col=1;col<=Dim;col++)
            {
                MatrixPiv[row][col]-=Coefficient*MatrixPiv[pTarget][col];
            }
        }
        return MatrixPiv;
    }
    //Determinant of Square Matrix
    int dCounter,dRow;
    double Det;
    double MatrixDet[9][9];
    double Determinant(double MatrixInput[9][9],int Dim)
    {
        CopyMatrix(MatrixInput,MatrixDet,Dim,Dim);
        Det=1.0;
        if(Dim>1)
        {
            for(dRow=1;dRow<Dim;dRow++)
            {
                dCounter=dRow;
                while((MatrixDet[dRow][dRow]==0.0)&(dCounter<=Dim))
                {
                    dCounter++;
                    Det*=-1.0;
                    CopyPointer(InterchangeRow(MatrixDet,Dim,Dim,dRow,dCounter),MatrixDet,Dim,Dim);
                }
                if(MatrixDet[dRow][dRow]==0)
                {
                    Det=0.0;
                    break;
                }
                else
                {
                    Det*=MatrixDet[dRow][dRow];
                    CopyPointer(Pivote(MatrixDet,Dim,dRow),MatrixDet,Dim,Dim);
                }
            }
            Det*=MatrixDet[Dim][Dim];
        }
        else Det=MatrixDet[1][1];
        return Det;
    }
    //Matrix Identity
    double MatrixIdent[9][9];
    double (*(Identity)(int Dim))[9]
    {
        for(row=1;row<=Dim;row++)
            for(col=1;col<=Dim;col++)
                if(row==col)
                    MatrixIdent[row][col]=1.0;
                else
                    MatrixIdent[row][col]=0.0;
        return MatrixIdent;
    }
    //Join Matrix to be Augmented Matrix
    double MatrixJoin[9][9];
    double (*(JoinMatrix)(double MatrixA[9][9],double MatrixB[9][9],int Row,int ColA,int ColB))[9]
    {
        Col=ColA+ColB;
        for(row=1;row<=Row;row++)
            for(col=1;col<=Col;col++)
                if(col<=ColA)
                    MatrixJoin[row][col]=MatrixA[row][col];
                else
                    MatrixJoin[row][col]=MatrixB[row][col-ColA];
        return MatrixJoin;
    }
    //Inverse of Matrix
    double (*Pointer)[9];
    double IdentMatrix[9][9];
    int Counter;
    double MatrixAug[9][9];
    double MatrixInv[9][9];
    double (*(Inverse)(double MatrixInput[9][9],int Dim))[9]
    {
        Row=Dim;
        Col=Dim+Dim;
        Pointer=Identity(Dim);
        CopyPointer(Pointer,IdentMatrix,Dim,Dim);
        Pointer=JoinMatrix(MatrixInput,IdentMatrix,Dim,Dim,Dim);
        CopyPointer(Pointer,MatrixAug,Row,Col);
        for(Counter=1;Counter<=Dim;Counter++)   
        {
            Pointer=PivoteDown(MatrixAug,Row,Col,Counter,Counter);
            CopyPointer(Pointer,MatrixAug,Row,Col);
        }
        for(Counter=Dim;Counter>1;Counter--)
        {
            Pointer=PivoteUp(MatrixAug,Row,Col,Counter,Counter);
            CopyPointer(Pointer,MatrixAug,Row,Col);
        }
        for(row=1;row<=Dim;row++)
            for(col=1;col<=Dim;col++)
                MatrixInv[row][col]=MatrixAug[row][col+Dim];
        return MatrixInv;
    }
    //Gauss-Jordan Elemination
    double MatrixGJ[9][9];
    double VectorGJ[9][9];
    double (*(GaussJordan)(double MatrixInput[9][9],double VectorInput[9][9],int Dim))[9]
    {
        Row=Dim;
        Col=Dim+1;
        Pointer=JoinMatrix(MatrixInput,VectorInput,Dim,Dim,1);
        CopyPointer(Pointer,MatrixGJ,Row,Col);
        for(Counter=1;Counter<=Dim;Counter++)   
        {
            Pointer=PivoteDown(MatrixGJ,Row,Col,Counter,Counter);
            CopyPointer(Pointer,MatrixGJ,Row,Col);
        }
        for(Counter=Dim;Counter>1;Counter--)
        {
            Pointer=PivoteUp(MatrixGJ,Row,Col,Counter,Counter);
            CopyPointer(Pointer,MatrixGJ,Row,Col);
        }
        for(row=1;row<=Dim;row++)
            for(col=1;col<=1;col++)
                VectorGJ[row][col]=MatrixGJ[row][col+Dim];
        return VectorGJ;
    }
    //Generalized Gauss-Jordan Elemination
    double MatrixGGJ[9][9];
    double VectorGGJ[9][9];
    double (*(GeneralizedGaussJordan)(double MatrixInput[9][9],double VectorInput[9][9],int Dim,int vCol))[9]
    {
        Row=Dim;
        Col=Dim+vCol;
        Pointer=JoinMatrix(MatrixInput,VectorInput,Dim,Dim,vCol);
        CopyPointer(Pointer,MatrixGGJ,Row,Col);
        for(Counter=1;Counter<=Dim;Counter++)   
        {
            Pointer=PivoteDown(MatrixGGJ,Row,Col,Counter,Counter);
            CopyPointer(Pointer,MatrixGGJ,Row,Col);
        }
        for(Counter=Dim;Counter>1;Counter--)
        {
            Pointer=PivoteUp(MatrixGGJ,Row,Col,Counter,Counter);
            CopyPointer(Pointer,MatrixGGJ,Row,Col);
        }
        for(row=1;row<=Row;row++)
            for(col=1;col<=vCol;col++)
                VectorGGJ[row][col]=MatrixGGJ[row][col+Dim];
        return VectorGGJ;
    }
    //Matrix Sparse, Three Diagonal Non-Zero Elements
    double MatrixSpa[9][9];
    double (*(Sparse)(int Dimension,double FirstElement,double SecondElement,double ThirdElement))[9]
    {
        MatrixSpa[1][1]=SecondElement;
        MatrixSpa[1][2]=ThirdElement;
        MatrixSpa[Dimension][Dimension-1]=FirstElement;
        MatrixSpa[Dimension][Dimension]=SecondElement;
        for(int Counter=2;Counter<Dimension;Counter++)
        {
            MatrixSpa[Counter][Counter-1]=FirstElement;
            MatrixSpa[Counter][Counter]=SecondElement;
            MatrixSpa[Counter][Counter+1]=ThirdElement;
        }
        return MatrixSpa;
    }
    

    Copy and save the above code as Matrix.h then try the following code:

    #include<iostream>
    #include<conio.h>
    #include"Matrix.h"
    int Dim;
    double Matrix[9][9];
    int main()
    {
        cout<<"Enter your matrix dimension: ";
        cin>>Dim;
        Input(Matrix,Dim,Dim);
        cout<<"Your matrix:"<<endl;
        Output(Matrix,Dim,Dim);
        cout<<"The inverse:"<<endl;
        Output(Inverse(Matrix,Dim),Dim,Dim);
        getch();
    }
    
    0 讨论(0)
  • 2020-12-04 19:59

    Don't try to do this yourself if you're serious about getting edge cases right. So while they many naive/simple methods are theoretically exact, they can have nasty numerical behavior for nearly singular matrices. In particular you can get cancelation/round-off errors that cause you to get arbitrarily bad results.

    A "correct" way is Gaussian elimination with row and column pivoting so that you're always dividing by the largest remaining numerical value. (This is also stable for NxN matrices.). Note that row pivoting alone doesn't catch all the bad cases.

    However IMO implementing this right and fast is not worth your time - use a well tested library and there are a heap of header only ones.

    0 讨论(0)
  • 2020-12-04 20:00

    A rather nice (I think) header file containing macros for most 2x2, 3x3 and 4x4 matrix operations has been available with most OpenGL toolkits. Not as standard but I've seen it at various places.

    You can check it out here. At the end of it you will find both inverse of 2x2, 3x3 and 4x4.

    vvector.h

    0 讨论(0)
  • 2020-12-04 20:04

    I have just created a QMatrix class. It uses the built in vector > container. QMatrix.h It uses the Jordan-Gauss method to compute the inverse of a square matrix.

    You can use it as follows:

    #include "QMatrix.h"
    #include <iostream>
    
    int main(){
    QMatrix<double> A(3,3,true);
    QMatrix<double> Result = A.inverse()*A; //should give the idendity matrix
    
    std::cout<<A.inverse()<<std::endl;
    std::cout<<Result<<std::endl; // for checking
    return 0;
    }
    

    The inverse function is implemented as follows:

    Given a class with the following fields:

    template<class T> class QMatrix{
    public:
    int rows, cols;
    std::vector<std::vector<T> > A;
    

    the inverse() function:

    template<class T> 
    QMatrix<T> QMatrix<T>:: inverse(){
    Identity<T> Id(rows); //the Identity Matrix as a subclass of QMatrix.
    QMatrix<T> Result = *this; // making a copy and transforming it to the Identity matrix
    T epsilon = 0.000001;
    for(int i=0;i<rows;++i){
        //check if Result(i,i)==0, if true, switch the row with another
    
        for(int j=i;j<rows;++j){
            if(std::abs(Result(j,j))<epsilon) { //uses Overloading()(int int) to extract element from Result Matrix
                Result.replace_rows(i,j+1); //switches rows i with j+1
            }
            else break;
        }
        // main part, making a triangular matrix
        Id(i)=Id(i)*(1.0/Result(i,i));
        Result(i)=Result(i)*(1.0/Result(i,i));  // Using overloading ()(int) to get a row form the matrix
        for(int j=i+1;j<rows;++j){
            T temp = Result(j,i);
            Result(j) = Result(j) - Result(i)*temp;
            Id(j) = Id(j) - Id(i)*temp; //doing the same operations to the identity matrix
            Result(j,i)=0; //not necessary, but looks nicer than 10^-15
        }
    }
    
    // solving a triangular matrix 
    for(int i=rows-1;i>0;--i){
        for(int j=i-1;j>=0;--j){
            T temp = Result(j,i);
            Id(j) = Id(j) - temp*Id(i);
            Result(j)=Result(j)-temp*Result(i);
        }
    }
    
    return Id;
    }
    
    0 讨论(0)
提交回复
热议问题