矩阵求逆

您所在的位置:网站首页 单位阵的逆矩阵怎么求 矩阵求逆

矩阵求逆

2024-07-15 10:16| 来源: 网络整理| 查看: 265

        最近的学习涉及到矩阵这一块,求n阶矩阵的逆、伴随、行列式太让人头疼。于是我就想着去网上找一个求矩阵的逆相关的代码。翻了半天找到的都是什么float,double设计的计算...em,这不是我想要的,我想要的效果是:如同我们手算一样,不能用小数表示,该用分数表示就用分数表示。

        算了,还是自己苦肝一晚上,实现一个!唉,自己造一个轮子也行吧,兴许哪天用上了,即使用不到,也算上锻炼自己数学计算和编程能力,哈哈。

        涉及到的算法其实很简单,比如求矩阵A的逆矩阵,将它和单位矩阵拼接起来得到增广矩阵(A,E),然后用行变换,将原矩阵A变成单位矩阵E时,单位矩阵就变成A的逆。再比如求解矩阵的行列式的值就是按某一行展开计算的,用到了递归。代码讲解我就不多说了,看代码就行。

        关于计算遇到的分数的表示,我专门定义了一个Fraction类来处理它的相关计算。

        思路就是这么简单,实现起来还是有点小麻烦的。不过,还是让我完成了,嘻嘻。

         说明:本文代码纯原创,如有雷同,纯属巧合!若引用本文代码请标明出处。        

        

  附上测试结果:

        测试1:矩阵A:

        

        计算结果:

         

         测试2:矩阵A

        

        计算结果:

         

        好了,不废话了!上代码:(Java实现)

        1.Mat类

import java.util.Arrays; /** * 矩阵 * @author gt5b * 2023-09-07 02:23 */ public class Mat { private int rows; private int cols; private Fraction[][] elements; /** * 传入的是一维数组 * 首先判断是否是方阵,若是方阵,则返回方阵;否则返回1 × n的矩阵 * @param array 一维数组 */ public Mat(int[] array){ int n = (int)(Math.sqrt(array.length)); if(n * n == array.length){ this.rows = n; this.cols = n; }else{ this.rows = 1; this.cols = array.length; } elements = new Fraction[rows][cols]; arrayToElements(array); } public Mat(int[][] array) { this. rows = array.length; this. cols = array[0].length; elements = new Fraction[rows][cols]; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { elements[i][j] = new Fraction(array[i][j], 1); } } } /** * 通过一维数组创建矩阵 * * @param array 一维数组 * @param rows 矩阵的行数 * @param cols 矩阵的列数 */ public Mat(int[] array, int rows, int cols) { if (rows == 0 && cols == 0) { throw new IllegalArgumentException("行数和列数不能同时为0"); } if (rows == 0) { rows = array.length / cols; } else if (cols == 0) { cols = array.length / rows; } if (rows * cols != array.length) { throw new IllegalArgumentException("数组长度与行数和列数不匹配"); } this.rows = rows; this.cols = cols; elements = new Fraction[rows][cols]; arrayToElements(array); } private void arrayToElements(int[] array){ int index = 0; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { elements[i][j] = new Fraction(array[index++], 1); } } } public Mat(int rows, int cols) { this.rows = rows; this.cols = cols; this.elements = new Fraction[rows][cols]; for (int i = 0; i < rows; i++) { Arrays.fill(elements[i], new Fraction(0, 1)); } } public int getRows() { return rows; } public int getCols() { return cols; } public Fraction getElement(int row, int col) { return elements[row][col]; } public void setElement(int row, int col, Fraction value) { elements[row][col] = value; } /** * 判断是否是方阵 * @return 方阵返回true */ public boolean isSquare() { return rows == cols; } /** * 求伴随矩阵 * @return 返回矩阵A的伴随矩阵A* */ public Mat adjoinMatrix(){ //求出该矩阵的逆 Mat n = this.inverseMatrix(); Mat adjoinMatrix = new Mat(rows,cols); //求出该行列式的值 Fraction d = this.determinant(); //伴随矩阵就是 d * 它的逆 for(int i = 0; i < rows; ++i){ for(int j = 0; j < cols; ++j){ adjoinMatrix.setElement(i,j,n.getElement(i,j).multiply(d)); } } return adjoinMatrix; } /** * 求矩阵的行列式的值 * @return 返回该矩阵的行列式的精确结果 */ public Fraction determinant() { //选择按照哪一行展开成求和aij×Aij int chooseRow = 0; // 检查矩阵是否为方阵 if (!isSquare()) { throw new IllegalStateException("矩阵不是方阵"); } // 获取矩阵的阶数 int n = getRows(); // 递归计算行列式 if (n == 1) { return getElement(0, 0); } else if (n == 2) { // 2x2矩阵的行列式计算,对于二阶比较简单,可以直接用ad-bc进行计算 Fraction a = getElement(0, 0); Fraction b = getElement(0, 1); Fraction c = getElement(1, 0); Fraction d = getElement(1, 1); return a.multiply(d).subtract(b.multiply(c)); } else { // 3阶以及高阶矩阵的行列式计算,这里用递归实现的 Fraction determinant = new Fraction(0, 1); for (int j = 0; j < n; j++) { // 获取aij的代数余子式Aij Fraction cofactor = getCofactor(chooseRow, j); // 获取aij Fraction e = this.getElement(chooseRow,j); // 累加代数余子式aij×Aij determinant = determinant.add(cofactor.multiply(e)); } return determinant; } } /** * 求解aij的代数余子式 * @param row aij所在行 * @param column aij所在列 * @return aij的代数余子式Aij */ private Fraction getCofactor(int row, int column) { // 计算代数余子式的符号 int sign = (row + column) % 2 == 0 ? 1 : -1; // 计算子矩阵的行列式 Fraction subDeterminant = subMatrix(row, column).determinant(); // 代数余子式等于子矩阵行列式乘以符号 return subDeterminant.multiply(new Fraction(sign, 1)); } /** * 获取aij的子式 * @param row 元素所在行 * @param column 元素所在列 * @return 返回它的子式(去掉它所在的行和所在的列,得到的矩阵) */ private Mat subMatrix(int row, int column) { int n = getRows(); // 创建子矩阵 Mat subMatrix = new Mat(n - 1, n - 1); int rowIndex = 0; for (int i = 0; i < n; i++) { if (i == row) { continue; } int colIndex = 0; for (int j = 0; j < n; j++) { if (j == column) { continue; } // 将原矩阵的元素复制到子矩阵 subMatrix.setElement(rowIndex, colIndex, getElement(i, j)); colIndex++; } rowIndex++; } return subMatrix; } /** * 获取矩阵的逆 * @return 返回this的逆 */ public Mat inverseMatrix() { // 检查矩阵是否可逆 if (!this.isInvertible()) { throw new IllegalArgumentException("矩阵不可逆"); } // 获取矩阵的行数和列数 int rows = this.getRows(); int cols = this.getCols(); // 创建单位矩阵 Mat identityMatrix = createIdentityMatrix(rows); // 将原始矩阵和单位矩阵进行拼接 Mat augmentedMatrix = concatenateMatrices(this, identityMatrix); // 利用高斯-约当消元法求解逆矩阵 gaussianJordanElimination(augmentedMatrix); // 提取逆矩阵部分,该方法通过提取增广矩阵的最右侧列来获得逆矩阵 return extractInverseMatrix(augmentedMatrix, cols); } /** * 判断矩阵是否可逆 * @return 可逆返回true */ private boolean isInvertible() { // 检查矩阵是否为方阵 if (!this.isSquare()) { return false; } // 检查矩阵的行列式的值是否为0 if (this.determinant().equals(new Fraction(0, 1))) { throw new IllegalArgumentException("矩阵行列式值是0,不可逆"); } return true; } /** * 创建单位矩阵 * @param size 矩阵的阶 * @return 返回n阶矩阵 */ public static Mat createIdentityMatrix(int size) { Mat identityMatrix = new Mat(size, size); for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (i == j) { identityMatrix.setElement(i, j, new Fraction(1, 1)); } else { identityMatrix.setElement(i, j, new Fraction(0, 1)); } } } return identityMatrix; } /** * 将矩阵A与单位矩阵E拼接起来 * @param matrix1 原矩阵A * @param matrix2 与A同阶的单位矩阵 * @return 返会增广矩阵(A,E) */ private static Mat concatenateMatrices(Mat matrix1, Mat matrix2) { int rows1 = matrix1.getRows(); int cols1 = matrix1.getCols(); int rows2 = matrix2.getRows(); int cols2 = matrix2.getCols(); if (rows1 != rows2) { throw new IllegalArgumentException("两个矩阵的行数不相等"); } Mat resultMatrix = new Mat(rows1, cols1 + cols2); for (int i = 0; i < rows1; i++) { for (int j = 0; j < cols1; j++) { resultMatrix.setElement(i, j, matrix1.getElement(i, j)); } for (int j = 0; j < cols2; j++) { resultMatrix.setElement(i, cols1 + j, matrix2.getElement(i, j)); } } return resultMatrix; } /** * 高斯消去法求矩阵A的逆 * @param matrix */ private static void gaussianJordanElimination(Mat matrix) { int rows = matrix.getRows(); int cols = matrix.getCols(); for (int i = 0; i < rows; i++) { Fraction pivot = matrix.getElement(i, i); //若当前行处理的的元素是0 if (pivot.equals(new Fraction(0, 1))) { //找到它下面非零的元素 int swapRow = findNonZeroElementRow(matrix, i, i); //找不到则说明它下面全是0,说明矩阵不可逆 if (swapRow == -1) { throw new IllegalArgumentException("矩阵不可逆"); } //找到后交换这两行 swapRows(matrix, i, swapRow); pivot = matrix.getElement(i, i); } for (int j = 0; j < cols; j++) { Fraction element = matrix.getElement(i, j); matrix.setElement(i, j, element.divide(pivot)); } //第j行的ajk减去第i行的aik使其ajk变为0 for (int j = 0; j < rows; j++) { if (j != i) { Fraction factor = matrix.getElement(j, i); for (int k = 0; k < cols; k++) { Fraction element1 = matrix.getElement(j, k); Fraction element2 = matrix.getElement(i, k); matrix.setElement(j, k, element1.subtract(element2.multiply(factor))); } } } } } /** * 行变换时找到非零元素 * @param matrix 矩阵A * @param col aij所在列 * @param startRow aij所在的行 * @return 返回aij正下方的非零元素的下标 */ private static int findNonZeroElementRow(Mat matrix, int col, int startRow) { int rows = matrix.getRows(); for (int i = startRow; i < rows; i++) { if (!matrix.getElement(i, col).equals(new Fraction(0, 1))) { return i; } } return -1; } private static void swapRows(Mat matrix, int row1, int row2) { int cols = matrix.getCols(); for (int j = 0; j < cols; j++) { Fraction temp = matrix.getElement(row1, j); matrix.setElement(row1, j, matrix.getElement(row2, j)); matrix.setElement(row2, j, temp); } } /** * 行变换结束后,(A,E)->(E,A逆),将A的逆抽取出来 * @param matrix 增广矩阵(E,A逆) * @param cols * @return */ private static Mat extractInverseMatrix(Mat matrix, int cols) { int rows = matrix.getRows(); Mat inverseMatrix = new Mat(rows, cols); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { //因为是(E,A逆),所以获取的是右边的A逆,因此列用到j + cols inverseMatrix.setElement(i, j, matrix.getElement(i, j + cols)); } } return inverseMatrix; } public void setRows(int rows) { this.rows = rows; } public void setCols(int cols) { this.cols = cols; } public Fraction[][] getElements() { return elements; } public void setElements(Fraction[][] elements) { this.elements = elements; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Mat mat = (Mat) o; if (rows != mat.rows) return false; if (cols != mat.cols) return false; return Arrays.deepEquals(elements, mat.elements); } @Override public int hashCode() { int result = rows; result = 31 * result + cols; result = 31 * result + Arrays.deepHashCode(elements); return result; } @Override public String toString() { StringBuilder sb = new StringBuilder(); for(int i = 0; i < rows;++i){ sb.append("["); for(int j = 0; j < cols;++j){ sb.append(getElement(i, j)).append("\t,"); } sb.delete(sb.length()-1,sb.length()); sb.append("]\n"); } return sb.toString(); } }

        2.Fraction类

/** * 分数 * @author gt5b * 2023-09-07 01:12 */ public class Fraction { private int numerator; private int denominator; public Fraction(){ this.numerator = 0; this.denominator = 1; } public Fraction(int numerator, int denominator) { if (denominator == 0) { throw new IllegalArgumentException("分母不能为0"); } //若分子是0,分母不是0,直接写成0/1 if(numerator == 0){ this.numerator = 0; this.denominator = 1; }else{ //求解分子分母的最大公因数,从而将其化成最简分数 int gcd = gcd(Math.abs(numerator), Math.abs(denominator)); //判断正负 //若分子负,分母正。直接将最大公因数调整成-gcd if (denominator < 0 && numerator > 0) { gcd = -gcd; } //若分子正,分母负。将最大公因数调整成-gcd, // 为了便于后期处理,将分母变成正数,分子变成负数 else if(denominator > 0 && numerator < 0){ gcd = -gcd; denominator = -denominator; numerator = -numerator; } //若分子分母均是负数,则将其化为正数 else if(denominator < 0 && numerator < 0){ denominator = -denominator; numerator = -numerator; } this.denominator = denominator / gcd; this.numerator = numerator / gcd; } } public int getNumerator() { return numerator; } public int getDenominator() { return denominator; } /** * 求解分子和分母的最大公因数 * @param a 分子 * @param b 分母 * @return 返回分子分母的最大公因数 */ private int gcd(int a, int b) { if (b == 0) { return a; } return gcd(b, a % b); } public Fraction add(Fraction other) { int newNumerator = this.numerator * other.denominator + this.denominator * other.numerator; int newDenominator = this.denominator * other.denominator; return new Fraction(newNumerator, newDenominator); } public Fraction subtract(Fraction other) { int newNumerator = this.numerator * other.denominator - this.denominator * other.numerator; int newDenominator = this.denominator * other.denominator; return new Fraction(newNumerator, newDenominator); } public Fraction multiply(Fraction other) { int newNumerator = this.numerator * other.numerator; int newDenominator = this.denominator * other.denominator; return new Fraction(newNumerator, newDenominator); } public Fraction divide(Fraction other) { int newNumerator = this.numerator * other.denominator; int newDenominator = this.denominator * other.numerator; return new Fraction(newNumerator, newDenominator); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Fraction fraction = (Fraction) o; if (numerator != fraction.numerator) return false; return denominator == fraction.denominator; } @Override public int hashCode() { int result = numerator; result = 31 * result + denominator; return result; } public void setNumerator(int numerator) { this.numerator = numerator; } public void setDenominator(int denominator) { this.denominator = denominator; } @Override public String toString() { if (denominator == 1) { return String.valueOf(numerator); } return numerator + "/" + denominator; } }



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3