【问题标题】:deteminant of matrix矩阵的行列式
【发布时间】:2011-03-02 02:27:25
【问题描述】:

假设给定一个二维数组

int a[][]=new int[4][4];

我正在尝试找到矩阵的行列式,请帮助我知道如何在数学上找到它,但我正在尝试以编程方式找到它 我正在使用语言 java 和 c#,但在这种情况下,我认为 c++ 也会有所帮助

【问题讨论】:

  • 到目前为止你有什么,它怎么不工作?
  • 您想为一般情况下的 NxN 方阵还是只为 4x4 情况?还指定您正在编程的语言可能会有所帮助。从您的代码示例来看,它看起来像 C#,但是是吗?请重新标记您的问题。

标签: c# java algorithm


【解决方案1】:

我知道这个问题已经得到解答,但是对于任何可能需要一种算法来计算具有任何维度的矩阵的行列式的人来说,这就是我想出的。

这个类使用许多不同的方法来使矩阵成为三角形,然后计算它的行​​列式。它可以用于高维矩阵,如 500 x 500 甚至更大。这门课的好处是你可以得到BigDecimal的结果,所以没有无穷大,你总是会得到准确的答案。顺便说一句,使用许多不同的方法并避免递归会导致更快的方法和更高的答案性能。希望对您有所帮助。

import java.math.BigDecimal;


public class DeterminantCalc {

private double[][] matrix;
private int sign = 1;


DeterminantCalc(double[][] matrix) {
    this.matrix = matrix;
}

public int getSign() {
    return sign;
}

public BigDecimal determinant() {

    BigDecimal deter;
    if (isUpperTriangular() || isLowerTriangular())
        deter = multiplyDiameter().multiply(BigDecimal.valueOf(sign));

    else {
        makeTriangular();
        deter = multiplyDiameter().multiply(BigDecimal.valueOf(sign));

    }
    return deter;
}


/*  receives a matrix and makes it triangular using allowed operations
    on columns and rows
*/
public void makeTriangular() {

    for (int j = 0; j < matrix.length; j++) {
        sortCol(j);
        for (int i = matrix.length - 1; i > j; i--) {
            if (matrix[i][j] == 0)
                continue;

            double x = matrix[i][j];
            double y = matrix[i - 1][j];
            multiplyRow(i, (-y / x));
            addRow(i, i - 1);
            multiplyRow(i, (-x / y));
        }
    }
}


public boolean isUpperTriangular() {

    if (matrix.length < 2)
        return false;

    for (int i = 0; i < matrix.length; i++) {
        for (int j = 0; j < i; j++) {
            if (matrix[i][j] != 0)
                return false;

        }

    }
    return true;
}


public boolean isLowerTriangular() {

    if (matrix.length < 2)
        return false;

    for (int j = 0; j < matrix.length; j++) {
        for (int i = 0; j > i; i++) {
            if (matrix[i][j] != 0)
                return false;

        }

    }
    return true;
}


public BigDecimal multiplyDiameter() {

    BigDecimal result = BigDecimal.ONE;
    for (int i = 0; i < matrix.length; i++) {
        for (int j = 0; j < matrix.length; j++) {
            if (i == j)
                result = result.multiply(BigDecimal.valueOf(matrix[i][j]));

        }

    }
    return result;
}


// when matrix[i][j] = 0 it makes it's value non-zero
public void makeNonZero(int rowPos, int colPos) {

    int len = matrix.length;

    outer:
    for (int i = 0; i < len; i++) {
        for (int j = 0; j < len; j++) {
            if (matrix[i][j] != 0) {
                if (i == rowPos) { // found "!= 0" in it's own row, so cols must be added
                    addCol(colPos, j);
                    break outer;

                }
                if (j == colPos) { // found "!= 0" in it's own col, so rows must be added
                    addRow(rowPos, i);
                    break outer;
                }
            }
        }
    }
}


//add row1 to row2 and store in row1
public void addRow(int row1, int row2) {

    for (int j = 0; j < matrix.length; j++)
        matrix[row1][j] += matrix[row2][j];
}


//add col1 to col2 and store in col1
public void addCol(int col1, int col2) {

    for (int i = 0; i < matrix.length; i++)
        matrix[i][col1] += matrix[i][col2];
}


//multiply the whole row by num
public void multiplyRow(int row, double num) {

    if (num < 0)
        sign *= -1;


    for (int j = 0; j < matrix.length; j++) {
        matrix[row][j] *= num;
    }
}


//multiply the whole column by num
public void multiplyCol(int col, double num) {

    if (num < 0)
        sign *= -1;

    for (int i = 0; i < matrix.length; i++)
        matrix[i][col] *= num;

}


// sort the cols from the biggest to the lowest value
public void sortCol(int col) {

    for (int i = matrix.length - 1; i >= col; i--) {
        for (int k = matrix.length - 1; k >= col; k--) {
            double tmp1 = matrix[i][col];
            double tmp2 = matrix[k][col];

            if (Math.abs(tmp1) < Math.abs(tmp2))
                replaceRow(i, k);
        }
    }
}


//replace row1 with row2
public void replaceRow(int row1, int row2) {

    if (row1 != row2)
        sign *= -1;

    double[] tempRow = new double[matrix.length];

    for (int j = 0; j < matrix.length; j++) {
        tempRow[j] = matrix[row1][j];
        matrix[row1][j] = matrix[row2][j];
        matrix[row2][j] = tempRow[j];
    }
}


//replace col1 with col2
public void replaceCol(int col1, int col2) {

    if (col1 != col2)
        sign *= -1;

    System.out.printf("replace col%d with col%d, sign = %d%n", col1, col2, sign);
    double[][] tempCol = new double[matrix.length][1];

    for (int i = 0; i < matrix.length; i++) {
        tempCol[i][0] = matrix[i][col1];
        matrix[i][col1] = matrix[i][col2];
        matrix[i][col2] = tempCol[i][0];
    }
}

}

然后这个类从用户那里接收一个 n×n 的矩阵,或者可以生成一个 n×n 的随机矩阵,然后计算它的行​​列式。它还显示了解和最终的三角矩阵。

import java.math.BigDecimal;
import java.security.SecureRandom;
import java.text.NumberFormat;
import java.util.Scanner;


public class DeterminantTest {

public static void main(String[] args) {

    String determinant;

    //generating random numbers
int len = 500;
SecureRandom random = new SecureRandom();
double[][] matrix = new double[len][len];

for (int i = 0; i < len; i++) {
    for (int j = 0; j < len; j++) {
        matrix[i][j] = random.nextInt(500);
        System.out.printf("%15.2f", matrix[i][j]);
    }
}
System.out.println();

/*double[][] matrix = {
    {1, 5, 2, -2, 3, 2, 5, 1, 0, 5},
    {4, 6, 0, -2, -2, 0, 1, 1, -2, 1},
    {0, 5, 1, 0, 1, -5, -9, 0, 4, 1},
    {2, 3, 5, -1, 2, 2, 0, 4, 5, -1},
    {1, 0, 3, -1, 5, 1, 0, 2, 0, 2},
    {1, 1, 0, -2, 5, 1, 2, 1, 1, 6},
    {1, 0, 1, -1, 1, 1, 0, 1, 1, 1},
    {1, 5, 5, 0, 3, 5, 5, 0, 0, 6},
    {1, -5, 2, -2, 3, 2, 5, 1, 1, 5},
    {1, 5, -2, -2, 3, 1, 5, 0, 0, 1}
};

    double[][] matrix = menu();*/

    DeterminantCalc deter = new DeterminantCalc(matrix);

    BigDecimal det = deter.determinant();

    determinant = NumberFormat.getInstance().format(det);

    for (int i = 0; i < matrix.length; i++) {
        for (int j = 0; j < matrix.length; j++) {
            System.out.printf("%15.2f", matrix[i][j]);
        }
        System.out.println();
    }

    System.out.println();
    System.out.printf("%s%s%n", "Determinant: ", determinant);
    System.out.printf("%s%d", "sign: ", deter.getSign());

}


public static double[][] menu() {

    Scanner scanner = new Scanner(System.in);

    System.out.print("Matrix Dimension: ");
    int dim = scanner.nextInt();

    double[][] inputMatrix = new double[dim][dim];

    System.out.println("Set the Matrix: ");
    for (int i = 0; i < dim; i++) {
        System.out.printf("%5s%d%n", "row", i + 1);
        for (int j = 0; j < dim; j++) {

            System.out.printf("M[%d][%d] = ", i + 1, j + 1);
            inputMatrix[i][j] = scanner.nextDouble();
        }
        System.out.println();
    }
    scanner.close();

    return inputMatrix;
}

}

【讨论】:

    【解决方案2】:
    static double DeterminantGaussElimination(double[,] matrix)
    {
        int n = int.Parse(System.Math.Sqrt(matrix.Length).ToString());
        int nm1 = n - 1;
        int kp1;
        double p;
        double det=1;
        for (int k = 0; k < nm1; k++)
        {
            kp1 = k + 1;
            for(int i=kp1;i<n;i++)
            {
                p = matrix[i, k] / matrix[k, k];
                for (int j = kp1; j < n; j++)
                    matrix[i, j] = matrix[i, j] - p * matrix[k, j];
            }
        }
        for (int i = 0; i < n; i++)
            det = det * matrix[i, i];
        return det;
    
    }
    

    这个方法不一定有效,因为你必须除以你的矩阵的一个成员,如果你的矩阵的一个成员是0,你可以得到结果det = NaN。

    【讨论】:

      【解决方案3】:

      我可以确认之前的解决方案适用于 3x3 和 4x4,但不适用于 5x5 等。 遵循适用于任何尺寸(也是 5x5 或更大)的解决方案(非常简单)。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;    
      
      namespace MatrixTest
      {
      public class Matrix
      {
          private int dimension; //number of rows & colums for matrix
          private double[][] matrix; //holds values of matrix itself
      
          /// <summary>
          /// Create dim*dim matrix and fill it with data passed to this constructor.
          /// </summary>
          /// <param name="double_array"></param>
          /// <param name="dim"></param>
          public Matrix(double[][] double_array)
          {
              matrix = double_array;
              dimension = matrix.Length;
              // check square matrix:
              for (int i = 0; i < dimension; i++)
                  if (matrix[i].Length != dimension)
                      throw new Exception("Matrix is not square");
          }
      
          /// <summary>
          /// Get determinant of current matrix
          /// </summary>
          /// <returns></returns>
          public double Determinant()
          {
              if (dimension == 1)
                  return matrix[0][0];
              // else ricorsive call:
              double det = 0;
              for (int j = 0; j < dimension; j++)
              {
                  if (j % 2 == 0)
                      det += matrix[0][j] * GetSubmatrix(this, 0, j).Determinant();
                  else
                      det -= matrix[0][j] * GetSubmatrix(this, 0, j).Determinant();
              }
              return det;
          }
      
          /// <summary>
          /// Return a new Matrix with:
          /// dimension = passed matrix dimension - 1
          /// elements = all element of the original matrix, except row and column specified
          /// </summary>
          /// <param name="m"></param>
          /// <param name="rowToExclude"></param>
          /// <param name="colToExclude"></param>
          /// <returns></returns>
          public Matrix GetSubmatrix(Matrix m, int rowToExclude, int colToExclude)
          {
              double[][] values = new double[m.dimension - 1][];
              for (int i = 0; i < m.dimension; i++)
              {
                  // create row array:
                  if (i < m.dimension - 1)
                      values[i] = new double[m.dimension - 1];
                  // copy values:
                  for (int j = 0; j < m.dimension; j++)
                      if (i != rowToExclude && j != colToExclude)
                          values[i < rowToExclude ? i : i - 1][j < colToExclude ? j : j - 1] = m.matrix[i][j];
              }
              return new Matrix(values);
          }
      
          internal class Program
          {
              private static void Main(string[] args)
              {
                  Matrix mat02 = new Matrix(
                      new double[][] {
                      new double[] { 1.0, 2.0},
                      new double[] { -2.0, -5.0} });
      
                  Matrix mat03 = new Matrix(
                      new double[][] {
                      new double[] { 1.0, 2.0, -1.0 },
                      new double[] { -2.0, -5.0, -1.0},
                      new double[] { 1.0, -1.0, -2.0 } });
      
                  Matrix mat04 = new Matrix(
                      new double[][] {
                      new double[] {1.0, 2.0, 1.0, 3.0},
                      new double[] { -2.0, -5.0, -2.0, 1.0 },
                      new double[] { 1.0, -1.0, -3.0, 2.0 },
                      new double[] {4.0, -1.0, -3.0, 1.0} });
      
                  Matrix mat05 = new Matrix(
                      new double[][] {
                      new double[] {1.0, 2.0, 1.0, 2.0, 3.0},
                      new double[] {2.0, 1.0, 2.0, 2.0, 1.0},
                      new double[] {3.0, 1.0, 3.0, 1.0, 2.0},
                      new double[] {1.0, 2.0, 4.0, 3.0, 2.0},
                      new double[] {2.0, 2.0, 1.0, 2.0, 1.0} });
      
      
                  double determinant = mat02.Determinant();
                  Console.WriteLine("determinant is: {0}", determinant);
      
                  determinant = mat03.Determinant();
                  Console.WriteLine("determinant is: {0}", determinant);
      
                  determinant = mat04.Determinant();
                  Console.WriteLine("determinant is: {0}", determinant);
      
                  determinant = mat05.Determinant();
                  Console.WriteLine("determinant is: {0}", determinant);
      
                  Console.ReadLine();
              }
          }
      }
      

      }

      【讨论】:

        【解决方案4】:

        对于任何可能在寻找矩阵计算行列式算法时遇到此问题的人,请注意上面发布的包含此代码的解决方案:

        static double DeterminantGaussElimination(double[,] matrix)
                {
                    int n = int.Parse(System.Math.Sqrt(matrix.Length).ToString());
                    int nm1 = n - 1;
                    int kp1;
                    double p;
                    double det=1;
                    for (int k = 0; k < nm1; k++)
                    {
                        kp1 = k + 1;
                        for(int i=kp1;i<n;i++)
                        {
                            p = matrix[i, k] / matrix[k, k];
                            for (int j = kp1; j < n; j++)
                                matrix[i, j] = matrix[i, j] - p * matrix[k, j];
                        }
                    }
                    for (int i = 0; i < n; i++)
                        det = det * matrix[i, i];
                    return det;
        
                }
        

        适用于 3x3 和 4x4,但不适用于 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()
            {
                int n = int.Parse(System.Math.Sqrt(matrix.Length).ToString());
                int nm1 = n - 1;
                int kp1;
                double p;
                double det = 1;
                for (int k = 0; k < nm1; k++)
                {
                    kp1 = k + 1;
                    for (int i = kp1; i < n; i++)
                    {
                        p = matrix[i, k] / matrix[k, k];
                        for (int j = kp1; j < n; j++)
                            matrix[i, j] = matrix[i, j] - p * matrix[k, j];
                    }
                }
                for (int i = 0; i < n; i++)
                    det = det * matrix[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);
            }
        }
        

        但是,作为 4x4 的特定问题,我发现该算法是正确的(至少在我测试的几个案例中)。

        如果你运行上面的代码,你会得到:

        行列式是:-8 行列式是:-142 行列式是:NaN

        【讨论】:

          【解决方案5】:

          生成整数 1..N 的所有排列,并且对于每个这样的序列 s_1..s_N,计算单元格 M(i,s_i) 的值乘以符号值 p(s_1..s_i) 的乘积),如果 i-s_1 是偶数则为 1,否则为 -1。对所有这些产品求和。

          后记

          正如 polygene 所说,存在效率低下的算法,而这个算法是 O(N!),因为它不断重新计算共享子产品。但如果懒惰地完成,它既直观又节省空间。

          哦,上面的符号函数是错误的:P(s_1..s_i) 是 +1,如果 s_i 在序列 1..N 中有奇数索引,并且 s_1..s_{i-1} 被删除,并且 - 1 表示偶数索引。

          【讨论】:

            【解决方案6】:

            如果您知道如何进行数学运算,那么应用这些知识并编写代码,其功能与您必须手动计算行列式(在纸上)时所做的完全相同。正如 Ignacio 在他的评论中告诉你的那样,请告诉我们你尝试了什么,也许你会得到更好的答案。我很乐意编辑我的答案并为您提供帮助。

            编辑:

            看来这里的问题不在于公式本身,而在于了解如何使用数组,我会建议类似本教程的内容(我假设您使用 C#): how to: arrays in C#

            【讨论】:

            • 我还没有做任何事情,因为我需要确定如何进入数组并触摸从左到右从下到上的元素,依此类推
            【解决方案7】:

            如果您固定为 4x4,最简单的解决方案就是对公式进行硬编码。

            public double determinant(int[][] m) {
              return
            
              m[0][3] * m[1][2] * m[2][1] * m[3][0] - m[0][2] * m[1][3] * m[2][1] * m[3][0] -
              m[0][3] * m[1][1] * m[2][2] * m[3][0] + m[0][1] * m[1][3] * m[2][2] * m[3][0] +
              m[0][2] * m[1][1] * m[2][3] * m[3][0] - m[0][1] * m[1][2] * m[2][3] * m[3][0] -
              m[0][3] * m[1][2] * m[2][0] * m[3][1] + m[0][2] * m[1][3] * m[2][0] * m[3][1] +
              m[0][3] * m[1][0] * m[2][2] * m[3][1] - m[0][0] * m[1][3] * m[2][2] * m[3][1] -
              m[0][2] * m[1][0] * m[2][3] * m[3][1] + m[0][0] * m[1][2] * m[2][3] * m[3][1] +
              m[0][3] * m[1][1] * m[2][0] * m[3][2] - m[0][1] * m[1][3] * m[2][0] * m[3][2] -
              m[0][3] * m[1][0] * m[2][1] * m[3][2] + m[0][0] * m[1][3] * m[2][1] * m[3][2] +
              m[0][1] * m[1][0] * m[2][3] * m[3][2] - m[0][0] * m[1][1] * m[2][3] * m[3][2] -
              m[0][2] * m[1][1] * m[2][0] * m[3][3] + m[0][1] * m[1][2] * m[2][0] * m[3][3] +
              m[0][2] * m[1][0] * m[2][1] * m[3][3] - m[0][0] * m[1][2] * m[2][1] * m[3][3] -
              m[0][1] * m[1][0] * m[2][2] * m[3][3] + m[0][0] * m[1][1] * m[2][2] * m[3][3];
            }
            

            对于一般的NxN,问题要困难得多,各种算法按O(N!)O(N^3)等顺序排列。

            参考文献

            相关问题

            【讨论】:

            • @isola:是的。我+1喜欢它。我们现在可以做一个 5x5 矩阵吗?
            • 至少对于“小”矩阵而言,这并不像人们想象的那么荒谬,尤其是在考虑代码生成器的情况下;对于“大型”矩阵,应使用更复杂的算法之一,因为渐近时间复杂度变得更加重要
            • 值得一提的是O(n^3)算法叫做Gaussian elimination
            猜你喜欢
            • 2021-03-08
            • 2018-03-14
            • 2015-05-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-05-12
            • 1970-01-01
            • 2014-02-08
            相关资源
            最近更新 更多