Java优化的Cramers规则函数

时间:2014-05-14 01:39:44

标签: java algorithm math matrix linear-algebra

最近在prealculus中了解了Cramers规则,并决定用Java编写一个算法来帮助我更好地理解它。

以下代码100%正确工作,但它不使用任何类型的for循环以更简单的方式执行它的工作。

问题:Java中是否有更优雅的Cramers规则实现?

我正在考虑制作一个基本的行列式方法,然后在我需要采用Dx,Dy和Dz的行列式时进行一些列交换。 (对于Dx,将第4列与原始矩阵的第1列交换,然后取决定因子并除以原始行列式。) 听起来不错?

    public static void main(String[] args) {
    int[][] matrix = new int[3][3];
    matrix[0] = new int[] { 3, 5, -1, -2 };
    matrix[1] = new int[] { 1, -4, 2, 13 };
    matrix[2] = new int[] { 2, 4, 3, 1 };
    int[] r = crame(matrix);    
    info("x: " + r[0] + ", y: " + r[1] + ", z: " + r[2]);
    for(int i = 0; i < matrix.length; i++) {
        int[] base = matrix[i];
        if(check(base, r, base[3])) {
            info("System " + (i+1) + " checks!");
        } else {
            info("System " + (i+1) + " fails check!");
        }
    }
}

public static int[] crame(int[][] m) {
    int[] result;
    if (m.length == 2) {
        result = new int[2];
        int D = (m[0][0] * m[1][1]) - (m[1][0] * m[0][1]);
        int Dx = (m[0][2] * m[1][1]) - (m[1][2] * m[0][1]);
        int Dy = (m[0][0] * m[1][2]) - (m[1][0] * m[0][2]);
        result[0] = (int) (Dx / D);
        result[1] = (int) (Dy / D);
    } else if (m.length == 3) {
        result = new int[3];

        int D = (((m[0][2] * m[1][1] * m[0][2]) + (m[2][1] * m[1][2] * m[0][0]) + (m[2][2]
                * m[1][0] * m[0][2])) - ((m[0][0] * m[1][1] * m[2][2])
                + (m[0][1] * m[1][2] * m[0][2]) + (m[0][2] * m[1][0] * m[2][1])));

        int Dx = (((m[2][3] * m[1][1] * m[0][2]) + (m[2][1] * m[1][2] * m[0][3]) + (m[2][2]
                * m[1][3] * m[0][1])) - ((m[0][3] * m[1][1] * m[2][2])
                + (m[0][1] * m[1][2] * m[2][3]) + (m[0][2] * m[1][3] * m[2][1])));

        int Dy = (((m[2][0] * m[1][3] * m[0][2]) + (m[2][3] * m[1][2] * m[0][3]) + (m[2][2]
                * m[1][0] * m[0][3])) - ((m[0][0] * m[1][3] * m[2][2])
                + (m[0][3] * m[1][2] * m[2][0]) + (m[0][2] * m[1][0] * m[2][3])));

        int Dz = (((m[2][0] * m[1][1] * m[0][3]) + (m[2][1] * m[1][3] * m[0][0]) + (m[2][3]
                * m[1][0] * m[0][1])) - ((m[0][0] * m[1][1] * m[2][3])
                + (m[0][1] * m[1][3] * m[2][0]) + (m[0][3] * m[1][0] * m[2][1])));

        result[0] = (int) (Dx / D);
        result[1] = (int) (Dy / D);
        result[2] = (int) (Dz / D);
    } else {
        return new int[] {};
    }
    return result;
}

public static int product(int[] a, int[] b) {
    int p = 0;
    int[] fin = new int[(a.length -1)];
    for(int x = 0; x < fin.length; x++) {
        fin[x] = a[x] * b[x];
    }
    for (int f : fin) {
            p += f;
    }
    return p;
}

public static boolean check(int[] a, int[] b, int z) {
    return product(a, b) == z;
}

public static void info(String log) {
    System.out.println(log);
}

我的问题涉及可用于仅使用Cramers规则求解方程组的特定算法,是否有更优雅的算法?该功能仅适用于方形矩阵。

这不是一个家庭作业,在HS之后我将学习CS并且我一直致力于开发算法作为初步练习。

感谢您查看此内容

3 个答案:

答案 0 :(得分:2)

首先,有一种方法可以使Cramers规则完美:它将线性系统的代数解作为其系数中的有理函数。

然而,实际上,它有其局限性。虽然2x2系统是最完美的公式,并且仍然适用于3x3系统,但如果以直接的方式实施,其性能会随着每个额外维度而恶化。

使用Leverrier-Faddeev算法 a b 可以实现Cramers规则的几乎文字实现。它只需要计算矩阵乘积和矩阵迹线,以及矩阵对角线的操作。它不仅计算矩阵A的行列式(连同特征多项式的其他系数),它的迭代矩阵中还有adjugate或辅因子矩阵A 。关于这个矩阵的一个有趣的事实是,它允许将A * x = b的解作为(A * b)/ det(A),即A 的条目# * b已经是Cramers规则所要求的其他决定因素。

Leverrier-Faddeev需要n 4 + O(n 3 )操作。同样的结果可以通过更复杂的萨缪尔森 - Berkowitz算法获得,其具有该复杂性的三分之一,即n 4 / 3 + O(n 3 )。

如果系统(A | b)首先转换为三角形,则Cramers规则中所需的决定因素的计算变得非常简单。这可以通过Gauß消除,也就是LU分解(用于数值稳定性的旋转)或QR分解(最容易调试应该是Givens旋转的变体)来实现。然后,Cramers规则的有效应用是在三角系统中的后向替换。

答案 1 :(得分:1)

至少你的方法听起来不错;但是,我可能没有意识到任何更有效的方法。有趣的部分可能是弄清楚如何最好地实施行列式计算方法,显然它是not an inexpensive operation

但是一旦你知道那是有效的,其余的听起来对我来说还算不错。缓存原始矩阵的行列式,在列中替换等。

答案 2 :(得分:0)

准确了解如何有效地做到这一点。

http://sandsduchon.org/duchon/math/determinantJava.html

提供无缝决定因素的方法,并提及矩阵分解。我还没有学到这一点,因为它不是HS级别的概念,但我使用它时遇到了一些问题,而且它是一种可靠的方法。

最终守则:

    public static void main(String[] args) {
        int[][] matrix = new int[3][3];
        matrix[0] = new int[] { 3, 5, -1, -2 };
        matrix[1] = new int[] { 1, -4, 2, 13 };
        matrix[2] = new int[] { 2, 4, 3, 1 };
        int[] r = crame(matrix);
        info("x: " + r[0] + ", y: " + r[1] + ", z: " + r[2]);
        for (int i = 0; i < matrix.length; i++) {
          int[] base = matrix[i];
          if (check(base, r, base[3])) {
             info("System " + (i + 1) + " checks!");
          } else {
             info("System " + (i + 1) + " fails check!");
        }
    }
}

public static int getDet(int[][] a) {
    int n = a.length - 1;
    if (n < 0)
        return 0;
    int M[][][] = new int[n + 1][][];
    M[n] = a; // init first, largest, M to a
    // create working arrays
    for (int i = 0; i < n; i++)
        M[i] = new int[i + 1][i + 1];
    return getDet(M, n);
} // end method getDecDet double [][] parameter

public static int getDet(int[][][] M, int m) {
    if (m == 0)
        return M[0][0][0];
    int e = 1;
    // init subarray to upper left mxm submatrix
    for (int i = 0; i < m; i++)
        for (int j = 0; j < m; j++)
            M[m - 1][i][j] = M[m][i][j];
    int sum = M[m][m][m] * getDet(M, m - 1);
    // walk through rest of rows of M
    for (int i = m - 1; i >= 0; i--) {
        for (int j = 0; j < m; j++)
            M[m - 1][i][j] = M[m][i + 1][j];
        e = -e;
        sum += e * M[m][i][m] * getDet(M, m - 1);
    } // end for each row of matrix
    return sum;
} // end getDecDet double [][][], int

public static int[] crame(int[][] m) {
    int[] result;
    if (m.length == 2) {
        result = new int[m.length];
        int D = getDet(m);
        for (int i = 0; i < m.length; i++) {
            result[i] = getDet(slide(m, i, m.length)) / D;
        }
    } else if (m.length == 3) {
        result = new int[m.length];
        int D = getDet(m);
        for (int i = 0; i < m.length; i++) {
            result[i] = (getDet(slide(m, i, m.length)) / D);
        }
    } else {
        return new int[] {};
    }
    return result;
}

public static int[][] slide(int[][] base, int col, int fin) {
    int[][] copy = new int[base.length][];
    for (int i = 0; i < base.length; i++) {
        int[] aMatrix = base[i];
        int aLength = aMatrix.length;
        copy[i] = new int[aLength];
        System.arraycopy(aMatrix, 0, copy[i], 0, aLength);
    }
    for (int i = 0; i < base.length; i++) {
        copy[i][col] = base[i][fin];
    }
    return copy;
}

public static int product(int[] a, int[] b) {
    int p = 0;
    int[] fin = new int[(a.length - 1)];
    for (int x = 0; x < fin.length; x++) {
        fin[x] = a[x] * b[x];
    }
    for (int f : fin) {
        p += f;
    }
    return p;
}

public static boolean check(int[] a, int[] b, int z) {
    return product(a, b) == z;
}

public static void info(String log) {
    System.out.println(log);
}