2.1 高斯消元

数学原理

  雷米兹算法的基础是N元一次方程的求解。此外,离散傅里叶变换也用到了N元一次方程的求解。当然,实际应用中求解多元一次方程组的例子非常多,我就不一一列举。求解的方法主要有两种,一种是高斯消元,一种是递归法。
  递归法不推荐,已经被我删除。而高斯消元不仅仅是用来解方程,还可以用来求行列式、逆矩阵。
  高斯消元是利用矩阵表示N元一次方程组。然后将矩阵变成上三角矩阵或下三角矩阵。
  所谓上三角矩阵就是左下角全部为0的矩阵,下三角反之。
  如下,就是转换过程:
[ 1 1 1 1 10 2 1 1 1 11 − 1 2 1 1 10 − 3 2 1 2 14 ] \left[ \begin{matrix} 1 & 1 & 1 & 1 & 10\\ 2 & 1 & 1 & 1 & 11\\ -1 & 2 & 1 & 1 & 10\\ -3 & 2 & 1 & 2 & 14\\ \end{matrix} \right]\\ 121311221111111210111014
  将第一列变成0:
[ 1 1 1 1 10 0 1 1 1 9 0 − 3 − 2 − 2 − 20 0 − 5 − 4 − 5 − 44 ] \left[ \begin{matrix} 1&1&1&1&10\\ 0&1&1&1&9\\ 0&-3&-2&-2&-20\\ 0&-5&-4&-5&-44\\ \end{matrix} \right]\\ 10001135112411251092044
  将第二列变成0:
[ 1 1 1 1 10 0 1 1 1 9 0 0 − 1 − 1 − 7 0 0 − 1 0 − 1 ] \left[ \begin{matrix} 1&1&1&1&10\\ 0&1&1&1&9\\ 0&0&-1&-1&-7\\ 0&0&-1&0&-1\\ \end{matrix} \right]\\ 100011001111111010971
  将第三列变成0:
[ 1 1 1 1 10 0 1 1 1 9 0 0 − 1 − 1 − 7 0 0 0 1 6 ] \left[ \begin{matrix} 1&1&1&1&10\\ 0&1&1&1&9\\ 0&0&-1&-1&-7\\ 0&0&0&1&6\\ \end{matrix} \right] 100011001110111110976
  这个转换过程,就是先用第一行和后续的所有行进行计算,让后续所有行以0开始。
  然后将右下角视为一个子矩阵,继续这个运算。这个算法可以用递归实现,也可以用循环实现。但是最好实用循环实现,也就是高斯消元方法。
  然后使用代入法就可以解开,但是这时候千万不要去再转换为下三角矩阵,并且进一步转为单位矩阵。因为那样会有很多不必要的运算。

转换为三角矩阵

  这个核心的行变换方法其实就是行倍加。假设第一行的系数是 a a a,第二行的系数是 b b b,那么就是把第一行乘以 − b a -\frac{b}a ab加到第二行上。
  行例如第一行是 x + 2 y + 3 z = 6 x+2y+3z =6 x+2y+3z=6,第二行是 3 x − 3 y + 9 z = 9 3x-3y+9z=9 3x3y+9z=9,那么第一行就乘以 − 3 1 = − 3 -\frac31=-3 13=3,然后加到第二行。
  代码如下:

public Matrix<T> toUpperTriangular() {
    // 大循环,先用第一行合并以后所有行
    final T[][] ts = copyArray();
    for (int i = 0; i < ts.length - 1; i++) {
        // 循环遍历其后的所有行,其后所有行进行改变
        for (int j = i + 1; j < ts.length; j++) {
            rowOperator(ts[i], ts[j], ts[j][i], ts[i][i], i, ts[i].length);
        }
    }
    return createMatrix(ts);
}

/**
 * 行变换
 *
 * @param line1
 * @param line2       要变的行
 * @param coefficent1 第一行乘以的系数
 * @param coefficent2 第二行乘以的系数
 * @return
 */
public void rowOperator(T[] line1, T[] line2, T coefficent1, T coefficent2, int startColumn, int endColumn) {
    if (line1 == null || line2 == null) {
        throw new NullPointerException("合并的方程不能为空");
    }
    if (line1.length != line2.length) {
        throw new NullPointerException("两个方程参数不一致");
    }
    for (int i = startColumn; i < endColumn; i++) {
        final T ai = line1[i];
        final T bi = line2[i];
= subtract(multiply(ai, coefficent1), multiply(bi, coefficent2));
    }
}

  而python代码则如此:

def to_upper_triangle(self):
    # 将矩阵变成上三角矩阵
    lines = copy.deepcopy(self.__lines)
    for i in range(len(lines) - 1):
        for j in range(i + 1, len(lines)):
            Matrix.row_operate(lines[i], lines[j], lines[j][i], lines[i][i], i, len(lines[i]))
    return Matrix(lines)

行变换代码

@staticmethod
def row_operate(line1, line2, coefficient1, coefficient2, start_column, end_column):
    for i in range(start_column, end_column):
        line2[i] = line1[i] * coefficient1 - line2[i] * coefficient2

代入法

  而获取了上三角矩阵之后。
  有两种方法可以解开方程,一种办法是代入法,另一种方法是从下到上使用行倍加变换。代入法性能高一点,性能高的原因是避免了不必要的乘以0的运算。
  就是套进去解开了。解开的方法代码如下:
  其具体的思路是用最后一行代进去得到一个数字,比如如下的上三角矩阵:
[ 1 1 1 1 10 0 1 1 1 9 0 0 − 1 − 1 − 7 0 0 0 1 6 ] \left[ \begin{matrix} 1&1&1&1&10\\ 0&1&1&1&9\\ 0&0&-1&-1&-7\\ 0&0&0&1&6 \end{matrix} \right] 100011001110111110976
  从最后一行开始,得到 x 4 = 6 x_4=6 x4=6,然后 x 4 = 6 x_4=6 x4=6代入上面的每一行,矩阵变成了这样
[ 1 1 1 0 4 0 1 1 0 3 0 0 1 0 1 0 0 0 1 6 ] \left[ \begin{matrix} 1&1&1&0&4\\ 0&1&1&0&3\\ 0&0&1&0&1\\ 0&0&0&1&6\\ \end{matrix} \right] 10001100111000014316
  然后把 x 3 x_3 x3求出来,代入上面的每一行,最终,整个矩阵变成
[ 1 0 0 0 1 0 1 0 0 2 0 0 1 0 1 0 0 0 1 6 ] \left[ \begin{matrix} 1&0&0&0&1\\ 0&1&0&0&2\\ 0&0&1&0&1\\ 0&0&0&1&6 \\ \end{matrix} \right] 10000100001000011216
  所以这个方程的解就是:
x 1 = 1 x 2 = 2 x 3 = 1 x 4 = 6 x_1=1\\ x_2=2\\ x_3=1\\ x_4=6\\ x1=1x2=2x3=1x4=6

最终代码

  代入法计算性能更高,如果再转为下三角会有很多非必要的预算,再转为单位矩阵,又是一堆没必要的运算。高斯消元总体代码如下:

public T[] gaussianReduction() {
    final Matrix<T> tMatrix = this.toUpperTriangular();
    // 进行代入法变换。
    T[] solution = newArray(this.array.length);
    final T[][] ts = tMatrix.copyArray();
    final int n = ts.length;
    System.out.println();
    System.out.println(tMatrix.toBeautifulString());
    // 从最后一行出来-
    for (int i = n - 1; i >= 0; i--) {
        // 首先计算出自己
        solution[i] = divide(ts[i][n], ts[i][i]);
        // 遍历之上的所有行
        for (int j = 0; j < i; j++) {
            ts[j][n] = subtract(ts[j][n], multiply(ts[j][i], solution[i]));
        }
    }
    return solution;
}

  python代码如下:

def gaussian_reduction(self):
    matrix = self.to_upper_triangle()
    solution = [0 for _ in matrix.__lines]
    n = len(matrix.__lines)
    for i in range(n - 1, -1, -1):
        solution[i] = matrix.__lines[i][n] / matrix.__lines[i][i]
        for j in range(0, i):
            matrix.__lines[j][n] = matrix.__lines[j][n] - matrix.__lines[j][i] * solution[i]
    return solution
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒过来摸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值