数学:《线性代数》矩阵乘积 之 代码实现

背景

执行坐标变换的一工具就是使用矩阵乘法,这里给出矩阵乘法的简单实现。

矩阵乘法

核心代码

 1             public Matrix Multiply(Matrix matrix)
 2             {
 3                 if (this._n != matrix._m)
 4                 {
 5                     throw new InvalidOperationException("左侧矩阵的列不等于右侧矩阵的行");
 6                 }
 7 
 8                 var resultMatrix = new Matrix(this._m, matrix._n);
 9 
10                 for (var i = 0; i < resultMatrix._m; i++)
11                 {
12                     for (var j = 0; j < resultMatrix._n; j++)
13                     {
14                         resultMatrix._data[i][j] = Enumerable.Range(0, this._n).Sum(k => this._data[i][k] * matrix._data[k][j]);
15                     }
16                 }
17 
18                 return resultMatrix;
19             }

全部代码

  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 }

备注

上例中的几个变换方法都实现为了无副作用的,面向数学概念的结构最好实现为这样的,因为数学中的方法就是无副作用的。

原文地址:https://www.cnblogs.com/happyframework/p/3523883.html