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


    背景

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

    矩阵乘法

    核心代码

     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 }

    备注

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

  • 相关阅读:
    mapr
    短信 流控规则
    js modify local file
    An O(ND) Difference Algorithm and Its Variations (1986)
    美团金融扫码付静态资源加载优化实践
    前端遇上Go: 静态资源增量更新的新实践
    小程序短信验证码登录的实现与优化
    A Practical Introduction to Blockchain with Python
    numpy计算
    小程序登录方式切换 不做url跳转
  • 原文地址:https://www.cnblogs.com/happyframework/p/3523883.html
Copyright © 2020-2023  润新知