【问题标题】:Calculating an NxN matrix determinant in C#在 C# 中计算 NxN 矩阵行列式
【发布时间】:2011-02-24 17:55:27
【问题描述】:

如何计算 NxN 矩阵 C# 的行列式?

【问题讨论】:

  • 这是作业吗?
  • 定义不够:en.wikipedia.org/wiki/Determinant?当您尝试在 C# 上实现它时,您是否遇到过一些您可能会问到的特殊问题?
  • 给我们您目前制作的代码,我们会帮助您。但我们不会为您编写代码。
  • 虽然我同意这不是一个写得很好的问题,而且它确实有点像家庭作业,但我通过谷歌搜索发现了这个问题,需要和回答同样的事情。 SO 是我通常用来回答这类问题的地方,而这似乎确实是这里关于这个主题的唯一问题。我没有理由不正确回答,如果不是因为难以捉摸的@vj4u,那么至少对于像我这样的 Joe Coder。
  • 我已经发布了一个适合 4x4 案例的答案(这是我需要的)。它提出了一个问题,即当矩阵大小已知时,硬编码解决方案是否优于通用 NxN 解决方案。

标签: c# math matrix determinants


【解决方案1】:

简化为上三角形式,然后创建一个嵌套循环,将位置 i == j 处的所有值相乘。给你。

【讨论】:

  • 它甚至不需要是一个嵌套循环,因为如果你在 i == j 的位置 (i, j) 上执行它,你可以对所有位置 (i,一世)。
  • 你计算的结果可能是行列式的负数。您需要取主对角线的乘积,然后乘以 (-1)^[用于获得上三角形式的行交换数]
【解决方案2】:

OP 发布了 another question 专门询问 4x4 矩阵,该矩阵已作为该问题的完全副本而关闭。好吧,如果您不是在寻找通用解决方案,而是仅局限于 4x4 矩阵,那么您可以使用这个看起来难看但经过验证的代码:

public double GetDeterminant() {
    var m = _values;
    return
         m[12] * m[9]  * m[6]  * m[3]   -  m[8] * m[13] * m[6]  * m[3]   -
         m[12] * m[5]  * m[10] * m[3]   +  m[4] * m[13] * m[10] * m[3]   +
         m[8]  * m[5]  * m[14] * m[3]   -  m[4] * m[9]  * m[14] * m[3]   -
         m[12] * m[9]  * m[2]  * m[7]   +  m[8] * m[13] * m[2]  * m[7]   +
         m[12] * m[1]  * m[10] * m[7]   -  m[0] * m[13] * m[10] * m[7]   -
         m[8]  * m[1]  * m[14] * m[7]   +  m[0] * m[9]  * m[14] * m[7]   +
         m[12] * m[5]  * m[2]  * m[11]  -  m[4] * m[13] * m[2]  * m[11]  -
         m[12] * m[1]  * m[6]  * m[11]  +  m[0] * m[13] * m[6]  * m[11]  +
         m[4]  * m[1]  * m[14] * m[11]  -  m[0] * m[5]  * m[14] * m[11]  -
         m[8]  * m[5]  * m[2]  * m[15]  +  m[4] * m[9]  * m[2]  * m[15]  +
         m[8]  * m[1]  * m[6]  * m[15]  -  m[0] * m[9]  * m[6]  * m[15]  -
         m[4]  * m[1]  * m[10] * m[15]  +  m[0] * m[5]  * m[10] * m[15];
}

假设您将矢量数据存储在一个名为 _values 的 16 元素数组中(在这种情况下为 double,但 float 也可以),按以下顺序:

0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15

【讨论】:

  • 对于列主订单:m[3]*m[6]*m[9]*m[12] - m[2]*m[7]*m[9]*m[12] - m[3]*m[5]*m[10]*m[12] + m[1]*m[7]*m[10]*m[12] + m[2]*m[5]*m[11]*m[12] - m[1]*m[6]*m[11]*m[12] - m[3]*m[6]*m[8]*m[13] + m[2]*m[7]*m[8]*m[13] + m[3]*m[4]*m[10]*m[13] - m[0]*m[7]*m[10]*m[13] - m[2]*m[4]*m[11]*m[13] + m[0]*m[6]*m[11]*m[13] + m[3]*m[5]*m[8]*m[14] - m[1]*m[7]*m[8]*m[14] - m[3]*m[4]*m[9]*m[14] + m[0]*m[7]*m[9]*m[14] + m[1]*m[4]*m[11]*m[14] - m[0]*m[5]*m[11]*m[14] - m[2]*m[5]*m[8]*m[15] + m[1]*m[6]*m[8]*m[15] + m[2]*m[4]*m[9]*m[15] - m[0]*m[6]*m[9]*m[15] - m[1]*m[4]*m[10]*m[15] + m[0]*m[5]*m[10]*m[15]
【解决方案3】:

标准方法是LU decomposition。您可能想要使用库而不是自己编写代码。我不了解 C#,但 40 年的标准是 LAPACK。

【讨论】:

    【解决方案4】:

    此解决方案是使用行操作实现的。我采用与目标矩阵相同维度的单位矩阵,然后将目标矩阵转换为单位矩阵,这样,对目标矩阵执行的每个操作也必须对单位矩阵执行。最后,目标矩阵将变为单位矩阵,单位矩阵将保存目标矩阵的逆矩阵。

    private static double determinant(double[,] matrix, int size)
        {
            double[] diviser = new double[size];// this will be used to make 0 all the elements of a row except (i,i)th value.
            double[] temp = new double[size]; // this will hold the modified ith row after divided by (i,i)th value.
            Boolean flag = false; // this will limit the operation to be performed only when loop n != loop i
            double determinant = 1;
    
            if (varifyRowsAndColumns(matrix, size)) // verifies that no rows or columns are similar or multiple of another row or column
                for (int i = 0; i < size; i++)
                {
                    int count = 0;
                    //this will hold the values to be multiplied by temp matrix
                    double[] multiplier = new double[size - 1]; 
                    diviser[i] = matrix[i, i];
                    //if(i,i)th value is 0, determinant shall be 0
                    if (diviser[i] == 0)
                    {
                        determinant = 0;
                        break;
                    }
                    /*
                     * whole ith row will be divided by (i,i)th value and result will be stored in temp matrix.
                     * this will generate 1 at (i,i)th position in temp matrix i.e. ith row of matrix
                     */
                    for (int j = 0; j < size; j++)
                    {
                        temp[j] = matrix[i, j] / diviser[i];
                    }
                    //setting up multiplier to be used for multiplying the ith row of temp matrix
                    for (int o = 0; o < size; o++)
                        if (o != i)
                            multiplier[count++] = matrix[o, i];
    
                    count = 0;
                    //for creating 0s at every other position than (i,i)th
                    for (int n = 0; n < size; n++)
                    {
                        for (int k = 0; k < size; k++)
                        {
                            if (n != i)
                            {
                                flag = true;
                                matrix[n, k] -= (temp[k] * multiplier[count]);
                            }
                        }
                        if (flag)
                            count++;
                        flag = false;
                    }
    
                }
            else determinant = 0;
            //if determinant is not 0, (i,i)th element will be multiplied and the result will be determinant
            if (determinant != 0)
                for (int i = 0; i < size; i++)
                {
                    determinant *= matrix[i, i];
                }
            return determinant;
        }
    
    
        private static Boolean varifyRowsAndColumns(double[,] matrix, int size)
        {
            List<double[]> rows = new List<double[]>();
            List<double[]> columns = new List<double[]>();
    
    
            for (int j = 0; j < size; j++)
            {
                double[] temp = new double[size];
                for (int k = 0; k < size; k++)
                {
                    temp[j] = matrix[j, k];
                }
                rows.Add(temp);
            }
    
            for (int j = 0; j < size; j++)
            {
                double[] temp = new double[size];
                for (int k = 0; k < size; k++)
                {
                    temp[j] = matrix[k, j];
                }
                columns.Add(temp);
            }
    
            if (!RowsAndColumnsComparison(rows, size))
                return false;
            if (!RowsAndColumnsComparison(columns, size))
                return false;
            return true;
        }
        private static Boolean RowsAndColumnsComparison(List<double[]> rows, int size)
        {
            int countEquals = 0;
            int countMod = 0;
            int countMod2 = 0;
    
            for (int i = 0; i < rows.Count; i++)
            {
                for (int j = 0; j < rows.Count; j++)
                {
                    if (i != j)
                    {
                        double min = returnMin(rows.ElementAt(i), rows.ElementAt(j));
                        double max = returnMax(rows.ElementAt(i), rows.ElementAt(j));
    
                        for (int l = 0; l < size; l++)
                        {
                            if (rows.ElementAt(i)[l] == rows.ElementAt(j)[l])
                                countEquals++;
    
                            for (int m = (int)min; m <= max; m++)
                            {
                                if (rows.ElementAt(i)[l] % m == 0 && rows.ElementAt(j)[l] % m == 0)
                                    countMod++;
    
                                if (rows.ElementAt(j)[l] % m == 0 && rows.ElementAt(i)[l] % m == 0)
                                    countMod2++;
                            }
                        }
    
                        if (countEquals == size)
                        {
                            return false;
                            // one row is equal to another row. determinant is zero
                        }
    
                        if (countMod == size)
                        {
                            return false;
                        }
    
                        if (countMod2 == size)
                        {
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        private static double returnMin(double[] row1, double[] row2)
        {
            double min1 = row1[0];
            double min2 = row2[0];
    
            for (int i = 1; i < row1.Length; i++)
                if (min1 > row1[i])
                    min1 = row1[i];
    
            for (int i = 1; i < row2.Length; i++)
                if (min2 > row2[i])
                    min2 = row2[i];
    
            if (min1 < min2)
                return min1;
            else return min2;
        }
        private static double returnMax(double[] col1, double[] col2)
        {
            double max1 = col1[0];
            double max2 = col2[0];
    
            for (int i = 1; i < col1.Length; i++)
                if (max1 < col1[i])
                    max1 = col1[i];
    
            for (int i = 1; i < col2.Length; i++)
                if (max2 < col2[i])
                    max2 = col2[i];
    
            if (max1 > max2)
                return max1;
            else return max2;
        }
    

    【讨论】:

    • 我已经更新了我的答案,并在代码中添加了解释和评论以支持我的解释。如果您现在对这篇文章投赞成票,或者指导我应该进一步做什么,我将不胜感激。我在所有论坛上搜索得很好,但没有一个有 n x n 矩阵行列式解决方案,所以我对其进行了编码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2021-09-20
    • 2013-05-12
    • 2018-11-09
    • 1970-01-01
    相关资源
    最近更新 更多