2013-03-20 131 views
1

我想實現代碼在這裏找到&算法:deteminant N * N矩陣

deteminant of matrix 這裏: How to calculate matrix determinant? n*n or just 5*5

但我還是堅持了下來。

我的第一個問題實際上是什麼統治這個算法使用(因爲有明顯的數學由某人可以計算行列式的幾個規則) - 所以我想,如果算法是正確應用上首先要檢查。

我的第二個問題是我做錯了(我指的是執行)或什麼是錯的算法本身,因爲它看起來像3×3和正常工作的4x4,但5x5的它給人NaN的。用幾個在線矩陣行列式計算器檢查結果,除了5x5以外,結果都很好。

這是我的代碼:

using System; 

public class Matrix 
{ 
    private int row_matrix; //number of rows for matrix 
    private int column_matrix; //number of colums for matrix 
    private double[,] matrix; //holds values of matrix itself 

    //create r*c matrix and fill it with data passed to this constructor 
    public Matrix(double[,] double_array) 
    { 
     matrix = double_array; 
     row_matrix = matrix.GetLength(0); 
     column_matrix = matrix.GetLength(1); 
     Console.WriteLine("Contructor which sets matrix size {0}*{1} and fill it with initial data executed.", row_matrix, column_matrix); 
    } 

    //returns total number of rows 
    public int countRows() 
    { 
     return row_matrix; 
    } 

    //returns total number of columns 
    public int countColumns() 
    { 
     return column_matrix; 
    } 

    //returns value of an element for a given row and column of matrix 
    public double readElement(int row, int column) 
    { 
     return matrix[row, column]; 
    } 

    //sets value of an element for a given row and column of matrix 
    public void setElement(double value, int row, int column) 
    { 
     matrix[row, column] = value; 
    } 

    public double deterMatrix() 
    { 
     double det = 0; 
     double value = 0; 
     int i, j, k; 

     i = row_matrix; 
     j = column_matrix; 
     int n = i; 

     if (i != j) 
     { 
      Console.WriteLine("determinant can be calculated only for sqaure matrix!"); 
      return det; 
     } 

     for (i = 0; i < n - 1; i++) 
     { 
      for (j = i + 1; j < n; j++) 
      { 
       det = (this.readElement(j, i)/this.readElement(i, i)); 

       //Console.WriteLine("readElement(j, i): " + this.readElement(j, i)); 
       //Console.WriteLine("readElement(i, i): " + this.readElement(i, i)); 
       //Console.WriteLine("det is" + det); 
       for (k = i; k < n; k++) 
       { 
        value = this.readElement(j, k) - det * this.readElement(i, k); 

        //Console.WriteLine("Set value is:" + value); 
        this.setElement(value, j, k); 
       } 
      } 
     } 
     det = 1; 
     for (i = 0; i < n; i++) 
      det = det * this.readElement(i, i); 

     return det; 
    } 
} 

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     Matrix mat03 = new Matrix(new[,] 
     { 
      {1.0, 2.0, -1.0}, 
      {-2.0, -5.0, -1.0}, 
      {1.0, -1.0, -2.0}, 
     }); 

     Matrix mat04 = new Matrix(new[,] 
     { 
      {1.0, 2.0, 1.0, 3.0}, 
      {-2.0, -5.0, -2.0, 1.0}, 
      {1.0, -1.0, -3.0, 2.0}, 
      {4.0, -1.0, -3.0, 1.0}, 
     }); 

     Matrix mat05 = new Matrix(new[,] 
     { 
      {1.0, 2.0, 1.0, 2.0, 3.0}, 
      {2.0, 1.0, 2.0, 2.0, 1.0}, 
      {3.0, 1.0, 3.0, 1.0, 2.0}, 
      {1.0, 2.0, 4.0, 3.0, 2.0}, 
      {2.0, 2.0, 1.0, 2.0, 1.0}, 
     }); 

     double determinant = mat03.deterMatrix(); 
     Console.WriteLine("determinant is: {0}", determinant); 

     determinant = mat04.deterMatrix(); 
     Console.WriteLine("determinant is: {0}", determinant); 

     determinant = mat05.deterMatrix(); 
     Console.WriteLine("determinant is: {0}", determinant); 
    } 
} 
+1

南可能是由於「0.0/0.0」造成的。 – leppie 2013-03-20 17:16:32

+0

我知道是因爲這一點,或者甚至是因爲n/0.0,但問題是**爲什麼算法甚至會出現這種情況**。它應該是它的工作算法,正如其他帖子中所建議的那樣(我在我的問題的開頭提到了它們,此外,它適用於3x3和4x4。 – 2013-03-20 17:25:27

+1

算法似乎使用了高斯消元法,但假設除法如果這是你想要做的,我的建議是*正確地實現高斯消元*可能這個算法在給定的假設下是正確的;或許方程組允許解決方案嗎?無論如何,我會 – 2013-03-20 17:40:33

回答

2

爲什麼要重新發明輪子?一種衆所周知的用於獲取確定矩陣反轉矩陣的方法是進行LU分解。事實上,MSDN雜誌最近在C#這裏http://msdn.microsoft.com/en-us/magazine/jj863137.aspx做了一個關於如何做到這一點的帖子。

示例代碼是

矩陣行列式

在手的矩陣分解方法,可以很容易地進行編碼的方法來計算矩陣的行列式:

static double MatrixDeterminant(double[][] matrix) 
{ 
    int[] perm; 
    int toggle; 
    double[][] lum = MatrixDecompose(matrix, out perm, out toggle); 
    if (lum == null) 
    throw new Exception("Unable to compute MatrixDeterminant"); 
    double result = toggle; 
    for (int i = 0; i < lum.Length; ++i) 
    result *= lum[i][i]; 
    return result; 
} 

行列式根據分解矩陣上對角線的乘積求出與一個標誌檢查。閱讀文章瞭解更多詳情。

請注意,它們對矩陣使用鋸齒陣列,但是您可以將自己的矩陣存儲替換爲lum[i][j]lum[i,j]

+0

好吧,我要實施它並通知您結果。 – 2013-03-20 17:46:37

+0

你是對的,這是正確的做法。正如您所指出的,該文章使用靜態方法和矩陣陣列設計。由於我的完整代碼中的其他要求,我必須使用C#多維數組。我做得很好,直到現在,這是我不明白的一部分:double [] rowPtr = result [pRow];結果[pRow] =結果[j];結果[j] = rowPtr;我不知道如何「開始」:double [] rowPtr = result [pRow];即使我用Console.WriteLine打印輸出(result [pRow]);它寫道:System.Double [] – 2013-03-21 22:56:37

+1

'rowPtr []'是一維數組,其中包含矩陣單個行上的所有元素。您需要在列上進行循環才能將2D數組中的值傳輸到1D'rowPtr'數組。 'for(j = 0; j ja72 2013-03-22 16:27:56

1

@ ja72 非常感謝您的指導。計算任何n * n行列式的最終解決方案如下所示:

using System; 

internal class MatrixDecompositionProgram 
{ 
    private static void Main(string[] args) 
    { 
     float[,] m = MatrixCreate(4, 4); 
     m[0, 0] = 3.0f; m[0, 1] = 7.0f; m[0, 2] = 2.0f; m[0, 3] = 5.0f; 
     m[1, 0] = 1.0f; m[1, 1] = 8.0f; m[1, 2] = 4.0f; m[1, 3] = 2.0f; 
     m[2, 0] = 2.0f; m[2, 1] = 1.0f; m[2, 2] = 9.0f; m[2, 3] = 3.0f; 
     m[3, 0] = 5.0f; m[3, 1] = 4.0f; m[3, 2] = 7.0f; m[3, 3] = 1.0f; 

     int[] perm; 
     int toggle; 

     float[,] luMatrix = MatrixDecompose(m, out perm, out toggle); 

     float[,] lower = ExtractLower(luMatrix); 
     float[,] upper = ExtractUpper(luMatrix); 

     float det = MatrixDeterminant(m); 

     Console.WriteLine("Determinant of m computed via decomposition = " + det.ToString("F1")); 
    } 

    // -------------------------------------------------------------------------------------------------------------- 
    private static float[,] MatrixCreate(int rows, int cols) 
    { 
     // allocates/creates a matrix initialized to all 0.0. assume rows and cols > 0 
     // do error checking here 
     float[,] result = new float[rows, cols]; 
     return result; 
    } 

    // -------------------------------------------------------------------------------------------------------------- 
    private static float[,] MatrixDecompose(float[,] matrix, out int[] perm, out int toggle) 
    { 
     // Doolittle LUP decomposition with partial pivoting. 
     // rerturns: result is L (with 1s on diagonal) and U; perm holds row permutations; toggle is +1 or -1 (even or odd) 
     int rows = matrix.GetLength(0); 
     int cols = matrix.GetLength(1); 

     //Check if matrix is square 
     if (rows != cols) 
      throw new Exception("Attempt to MatrixDecompose a non-square mattrix"); 

     float[,] result = MatrixDuplicate(matrix); // make a copy of the input matrix 

     perm = new int[rows]; // set up row permutation result 
     for (int i = 0; i < rows; ++i) { perm[i] = i; } // i are rows counter 

     toggle = 1; // toggle tracks row swaps. +1 -> even, -1 -> odd. used by MatrixDeterminant 

     for (int j = 0; j < rows - 1; ++j) // each column, j is counter for coulmns 
     { 
      float colMax = Math.Abs(result[j, j]); // find largest value in col j 
      int pRow = j; 
      for (int i = j + 1; i < rows; ++i) 
      { 
       if (result[i, j] > colMax) 
       { 
        colMax = result[i, j]; 
        pRow = i; 
       } 
      } 

      if (pRow != j) // if largest value not on pivot, swap rows 
      { 
       float[] rowPtr = new float[result.GetLength(1)]; 

       //in order to preserve value of j new variable k for counter is declared 
       //rowPtr[] is a 1D array that contains all the elements on a single row of the matrix 
       //there has to be a loop over the columns to transfer the values 
       //from the 2D array to the 1D rowPtr array. 
       //----tranfer 2D array to 1D array BEGIN 

       for (int k = 0; k < result.GetLength(1); k++) 
       { 
        rowPtr[k] = result[pRow, k]; 
       } 

       for (int k = 0; k < result.GetLength(1); k++) 
       { 
        result[pRow, k] = result[j, k]; 
       } 

       for (int k = 0; k < result.GetLength(1); k++) 
       { 
        result[j, k] = rowPtr[k]; 
       } 

       //----tranfer 2D array to 1D array END 

       int tmp = perm[pRow]; // and swap perm info 
       perm[pRow] = perm[j]; 
       perm[j] = tmp; 

       toggle = -toggle; // adjust the row-swap toggle 
      } 

      if (Math.Abs(result[j, j]) < 1.0E-20) // if diagonal after swap is zero . . . 
       return null; // consider a throw 

      for (int i = j + 1; i < rows; ++i) 
      { 
       result[i, j] /= result[j, j]; 
       for (int k = j + 1; k < rows; ++k) 
       { 
        result[i, k] -= result[i, j] * result[j, k]; 
       } 
      } 
     } // main j column loop 

     return result; 
    } // MatrixDecompose 

    // -------------------------------------------------------------------------------------------------------------- 
    private static float MatrixDeterminant(float[,] matrix) 
    { 
     int[] perm; 
     int toggle; 
     float[,] lum = MatrixDecompose(matrix, out perm, out toggle); 
     if (lum == null) 
      throw new Exception("Unable to compute MatrixDeterminant"); 
     float result = toggle; 
     for (int i = 0; i < lum.GetLength(0); ++i) 
      result *= lum[i, i]; 

     return result; 
    } 

    // -------------------------------------------------------------------------------------------------------------- 
    private static float[,] MatrixDuplicate(float[,] matrix) 
    { 
     // allocates/creates a duplicate of a matrix. assumes matrix is not null. 
     float[,] result = MatrixCreate(matrix.GetLength(0), matrix.GetLength(1)); 
     for (int i = 0; i < matrix.GetLength(0); ++i) // copy the values 
      for (int j = 0; j < matrix.GetLength(1); ++j) 
       result[i, j] = matrix[i, j]; 
     return result; 
    } 

    // -------------------------------------------------------------------------------------------------------------- 
    private static float[,] ExtractLower(float[,] matrix) 
    { 
     // lower part of a Doolittle decomposition (1.0s on diagonal, 0.0s in upper) 
     int rows = matrix.GetLength(0); int cols = matrix.GetLength(1); 
     float[,] result = MatrixCreate(rows, cols); 
     for (int i = 0; i < rows; ++i) 
     { 
      for (int j = 0; j < cols; ++j) 
      { 
       if (i == j) 
        result[i, j] = 1.0f; 
       else if (i > j) 
        result[i, j] = matrix[i, j]; 
      } 
     } 
     return result; 
    } 

    // -------------------------------------------------------------------------------------------------------------- 
    private static float[,] ExtractUpper(float[,] matrix) 
    { 
     // upper part of a Doolittle decomposition (0.0s in the strictly lower part) 
     int rows = matrix.GetLength(0); int cols = matrix.GetLength(1); 
     float[,] result = MatrixCreate(rows, cols); 
     for (int i = 0; i < rows; ++i) 
     { 
      for (int j = 0; j < cols; ++j) 
      { 
       if (i <= j) 
        result[i, j] = matrix[i, j]; 
      } 
     } 
     return result; 
    } 
}