背景
给定坐标,我可以使用变换方阵对其进行右乘进行坐标转换,如果使用一个堆栈记录下执行过的变换方阵,然后执行一系列出栈操作,对出栈的方阵求逆,然后使用逆方阵右乘坐标就可以得到之前的坐标。
方阵求逆
理论
求逆
对 A:E 进行矩阵的最简算法得出 E:A-¹。
证明:
D1D2DkA = E
D1D2DkAA-¹ = EA-¹
D1D2DkE = A-¹
上面的三个公式说明,对 A 做有限的初等变换可以得到 E,同样对 E 做同样的初等变换可得到 A-¹,因此 我们求 A:E 的最简矩阵就可以得出 A-¹。
代码实现
核心代码
1 public Matrix Inverse() 2 { 3 if (_m != _n) 4 { 5 throw new InvalidOperationException("只有方阵可以求逆"); 6 } 7 8 var combinedMatrix = this.Combine(this.E()); 9 combinedMatrix = combinedMatrix.Simplify(); 10 11 var resultMatrix = new Matrix(_m, _m); 12 for (var i = 0; i < resultMatrix._m; i++) 13 { 14 Array.Copy(combinedMatrix._data[i], resultMatrix._m, resultMatrix._data[i], 0, resultMatrix._m); 15 } 16 17 return resultMatrix; 18 }
全部代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace DataStuctureStudy.Matrixes 8 { 9 class MatrixTest 10 { 11 public static void Test() 12 { 13 var matrixA = 14 new Matrix(3, 3) 15 .SetRowData(0, 1, 2, 3) 16 .SetRowData(1, 1, 2, 7) 17 .SetRowData(2, 4, 9, 2); 18 19 var matrixB = matrixA.Simplify(); 20 var matrixC = matrixA.Inverse(); 21 22 matrixA.Dispaly(); 23 matrixB.Dispaly(); 24 matrixC.Dispaly(); 25 matrixA.Multiply(matrixC).Dispaly(); 26 27 } 28 class Matrix 29 { 30 private readonly int _m; 31 private readonly int _n; 32 private readonly double[][] _data; 33 34 public Matrix(int m, int n) 35 { 36 _m = m; 37 _n = n; 38 _data = new double[m][]; 39 for (var i = 0; i < m; i++) 40 { 41 _data[i] = new double[n]; 42 } 43 } 44 45 public Matrix SetRowData(int row, params double[] values) 46 { 47 Array.Copy(values, _data[row], _n); 48 49 return this; 50 } 51 52 public Matrix SwapRow(int rowX, int rowY) 53 { 54 var resultMatrix = this.ConeSelf(); 55 56 var temp = resultMatrix._data[rowX]; 57 resultMatrix._data[rowX] = resultMatrix._data[rowY]; 58 resultMatrix._data[rowY] = temp; 59 60 return resultMatrix; 61 } 62 63 public Matrix MultiplyRow(int row, double operand) 64 { 65 var resultMatrix = this.ConeSelf(); 66 67 for (var i = 0; i < resultMatrix._n; i++) 68 { 69 resultMatrix._data[row][i] *= operand; 70 } 71 72 return resultMatrix; 73 } 74 75 76 public Matrix AddSourceRowToTargetRow(int sourceRow, double operand, int targetRow) 77 { 78 var resultMatrix = this.ConeSelf(); 79 80 for (var i = 0; i < resultMatrix._n; i++) 81 { 82 resultMatrix._data[targetRow][i] += resultMatrix._data[sourceRow][i] * operand; 83 } 84 85 return resultMatrix; 86 } 87 88 public Matrix Simplify() 89 { 90 var resultMatrix = this.ConeSelf(); 91 92 for (var col = 0; col < resultMatrix._n; col++) 93 { 94 if (col >= _m) 95 { 96 break; 97 } 98 99 if (resultMatrix._data[col][col] == 0) 100 { 101 var nonZeroRowIndex = resultMatrix.FindNonZeroRowIndex(col, col + 1); 102 if (nonZeroRowIndex == -1) 103 { 104 break; 105 } 106 resultMatrix = resultMatrix.SwapRow(col, nonZeroRowIndex); 107 } 108 109 resultMatrix = resultMatrix.MultiplyRow(col, 1 / resultMatrix._data[col][col]); 110 111 for (var row = 0; row < _m; row++) 112 { 113 if (row == col) 114 { 115 continue; 116 } 117 resultMatrix = resultMatrix.AddSourceRowToTargetRow(col, -1 * resultMatrix._data[row][col], row); 118 } 119 } 120 121 return resultMatrix; 122 } 123 124 public Matrix Multiply(Matrix matrix) 125 { 126 if (this._n != matrix._m) 127 { 128 throw new InvalidOperationException("左侧矩阵的列不等于右侧矩阵的行"); 129 } 130 131 var resultMatrix = new Matrix(this._m, matrix._n); 132 133 for (var i = 0; i < resultMatrix._m; i++) 134 { 135 for (var j = 0; j < resultMatrix._n; j++) 136 { 137 resultMatrix._data[i][j] = Enumerable.Range(0, this._n).Sum(k => this._data[i][k] * matrix._data[k][j]); 138 } 139 } 140 141 return resultMatrix; 142 } 143 144 public Matrix Inverse() 145 { 146 if (_m != _n) 147 { 148 throw new InvalidOperationException("只有方阵可以求逆"); 149 } 150 151 var combinedMatrix = this.Combine(this.E()); 152 combinedMatrix = combinedMatrix.Simplify(); 153 154 var resultMatrix = new Matrix(_m, _m); 155 for (var i = 0; i < resultMatrix._m; i++) 156 { 157 Array.Copy(combinedMatrix._data[i], resultMatrix._m, resultMatrix._data[i], 0, resultMatrix._m); 158 } 159 160 return resultMatrix; 161 } 162 163 public Matrix Combine(Matrix matrix) 164 { 165 if (this._m != matrix._m) 166 { 167 throw new InvalidOperationException("左侧矩阵的行不等于右侧矩阵的行"); 168 } 169 170 var resultMatrix = new Matrix(this._m, this._n + matrix._n); 171 for (var i = 0; i < resultMatrix._m; i++) 172 { 173 Array.Copy(this._data[i], 0, resultMatrix._data[i], 0, this._data[i].Length); 174 Array.Copy(matrix._data[i], 0, resultMatrix._data[i], this._data[i].Length, matrix._data[i].Length); 175 } 176 177 return resultMatrix; 178 } 179 180 public Matrix E() 181 { 182 return E(_m); 183 } 184 185 public static Matrix E(int m) 186 { 187 var matrix = new Matrix(m, m); 188 for (var i = 0; i < m; i++) 189 { 190 matrix._data[i][i] = 1; 191 } 192 193 return matrix; 194 } 195 196 public Matrix ConeSelf() 197 { 198 var resultMatrix = new Matrix(this._m, this._n); 199 for (var i = 0; i < this._m; i++) 200 { 201 Array.Copy(this._data[i], resultMatrix._data[i], this._n); 202 } 203 204 return resultMatrix; 205 } 206 207 public void Dispaly() 208 { 209 Console.WriteLine(); 210 foreach (var row in _data) 211 { 212 Console.WriteLine("[ " + String.Join(" , ", row) + " ]"); 213 } 214 Console.WriteLine(); 215 } 216 217 private int FindNonZeroRowIndex(int col, int startRow) 218 { 219 if (startRow >= _m) 220 { 221 return -1; 222 } 223 224 for (var i = startRow; i < _m; i++) 225 { 226 if (_data[i][col] != 0) 227 { 228 return i; 229 } 230 } 231 232 return -1; 233 } 234 } 235 } 236 }