矩阵相关的算法比较多,也是比较重要的,而且算法之间的性能差异确实比较大,初等变换法求逆比古典法求逆快不是一点点。矩阵的计算量和数值其实都是比较大的,特别是20阶以上,我在机器上最多只搞到40阶,随机产生的矩阵,很容易就爆掉decimal和double类型。
另外,这里使用了操作符重载,后面的一元符号运算也用到了操作符重载,后面如果有时间,我会将这些算法利用这些特性统一起来,本来它们的计算就应该是统一的。特别是符号运算。如果符号运算搞完,还可以试试自动命题证明玩玩。
好了,上矩阵的菜(有点长,但基本都调试过,至少书上的题都能正确计算出来!):
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyMathLib { /// <summary> /// 矩阵及相关算法. /// </summary> public class TMatrix { private int _Rank = -1; public bool IsZero { get; private set; } public bool IsUnit { get; private set; } private double[][] _Elements; public double[,] Elements { get { var theElements = new double[RowCount, ColCount]; for (int i = 0; i < RowCount; i++) { for (int j = 0; j < ColCount; j++) { theElements[i, j] = _Elements[i][j]; } } return theElements; } } public int ColCount { get; private set; } public int RowCount { get; private set; } /// <summary> /// 构造Row行,Col列矩阵,并用InitValue初始化。 /// </summary> /// <param name="Row">矩阵行数</param> /// <param name="Col">矩阵列数</param> /// <param name="InitValue">初始值</param> public TMatrix(int Row, int Col, double InitValue = 0) { IsZero = InitValue == 0; IsUnit = true; this.RowCount = Row; this.ColCount = Col; _Elements = new double[this.RowCount][]; for (int i = 0; i < Row; i++) { _Elements[i] = new double[this.ColCount]; for (int j = 0; j < this.ColCount; j++) { _Elements[i][j] = InitValue; if (Row == Col) { if (i == j) { if (InitValue != 1) { IsUnit = false; } } else { if (InitValue != 0) { IsUnit = false; } } } else { IsUnit = false; } } } } /// <summary> /// 构造Row行,Row列方阵.并用InitValue初始化 /// </summary> /// <param name="Row">方阵行列数</param> /// <param name="OnlyInitDiagonal">仅初始化对角线</param> public TMatrix(int Row, double InitValue = 0, bool OnlyInitDiagonal = false) { IsZero = InitValue == 0; IsUnit = (InitValue == 1 && OnlyInitDiagonal); this.RowCount = Row; this.ColCount = Row; _Elements = new double[this.RowCount][]; for (int i = 0; i < Row; i++) { _Elements[i] = new double[this.ColCount]; if (OnlyInitDiagonal) { _Elements[i][i] = InitValue; } else { for (int j = 0; j < this.ColCount; j++) { _Elements[i][j] = InitValue; } } } } public TMatrix(double[][] InitElements) { if (InitElements == null) { throw new Exception("矩阵不能为空!"); } IsZero = true; IsUnit = true; _Elements = InitElements; RowCount = _Elements.Length; ColCount = _Elements[0].Length; for (int i = 0; i < RowCount; i++) { for (int j = 0; j < this.ColCount; j++) { if (_Elements[i][j] != 0) { IsZero = false; } if (RowCount == ColCount) { if (i == j) { if (_Elements[i][j] != 1) { IsUnit = false; } } else { if (_Elements[i][j] != 0) { IsUnit = false; } } } else { IsUnit = false; } } } } public TMatrix(double[,] InitElements) { if (InitElements == null) { throw new Exception("矩阵不能为空!"); } IsZero = true; IsUnit = true; RowCount = InitElements.GetLength(0); ColCount = InitElements.GetLength(1); _Elements = new double[RowCount][]; for (int i = 0; i < RowCount; i++) { _Elements[i] = new double[ColCount]; for (int j = 0; j < ColCount; j++) { this[i, j] = InitElements[i, j]; } } } public double this[int i, int j] { get { return _Elements[i][j]; } set { if (value != 0) { this.IsZero = false; } if (Math.Round(value,8) != 1) { this.IsUnit = false; } else { if (i != j) { this.IsUnit = false; } } _Elements[i][j] = value; } } public double[] this[int i] { get { return _Elements[i]; } } public double[] this[int i, bool GetCol] { get { double[] theResult = new double[RowCount]; for (int k = 0; k < RowCount; k++) { theResult[k] = _Elements[k][i]; } return theResult; } } public void SwapRow(int i, int j) { if (i != j) { double[] theTemp = _Elements[i]; _Elements[i] = _Elements[j]; _Elements[j] = theTemp; } } public void SwapCol(int i, int j) { if (i != j) { for (int k = 0; k < RowCount; k++) { double theTemp = _Elements[k][j]; _Elements[k][j] = _Elements[k][i]; _Elements[k][i] = theTemp; } } } public bool IsSquareMatrix { get { return this.ColCount == this.RowCount; } } public void CopyFrom(TMatrix A) { if (A.RowCount != this.RowCount || A.ColCount != this.ColCount) { throw new Exception("不是同型矩阵不能拷贝!"); } for (int i = 0; i < A.RowCount; i++) { for (int j = 0; j < A.ColCount; j++) { this[i, j] = A[i, j]; } } } #region 初等变换 /// <summary> /// 行初等变换1:交换两行. /// </summary> /// <param name="i"></param> /// <param name="j"></param> private void EleTransRow1(int i, int j) { SwapRow(i, j); } /// <summary> /// 行初等变换2:用一个非零数乘以一行. /// </summary> /// <param name="RowIndex">行号</param> /// <param name="Multiplier">乘数,不能为零</param> private void EleTransRow2(int RowIndex, double Multiplier) { if (Multiplier == 1) { return; } if (Multiplier != 0) { for (int j = 0; j < ColCount; j++) { this[RowIndex, j] = this[RowIndex, j] * Multiplier; } } } /// <summary> /// 行初等变换3:行1减行2 /// </summary> /// <param name="Row1">行号1</param> /// <param name="Row2">行号2</param> private void EleTransRow3(int Row1, int Row2, double Multiplier) { for (int j = 0; j < ColCount; j++) { this[Row1, j] = this[Row1, j] - this[Row2, j] * Multiplier; } } /// <summary> /// 行初等变换4:行1 * 系数1 - 行2 * 系数2 /// </summary> /// <param name="Row1">行号</param> /// <param name="M1">乘数1,不能为零</param> /// <param name="M2">乘数2,不能为零</param> private void EleTransRow4(int Row1, int Row2,double M1,double M2) { for (int j = 0; j < ColCount; j++) { this[Row1, j] = this[Row1, j] * M1 - this[Row2, j] * M2; } } /// <summary> /// 列初等变换1:交换两列. /// </summary> /// <param name="i"></param> /// <param name="j"></param> public void EleTransCol1(int i, int j) { SwapCol(i, j); } /// <summary> /// 列初等变换2:用一个非零数乘以一列. /// </summary> /// <param name="ColIndex">列号</param> /// <param name="Multiplier">乘数,不能为零</param> public void EleTransCol2(int ColIndex, double Multiplier) { if (Multiplier != 0) { for (int j = 0; j < RowCount; j++) { this[j, ColIndex] = this[j, ColIndex] * Multiplier; } } } /// <summary> /// 列初等变换3:列1减列2 /// </summary> /// <param name="Row1">列号1</param> /// <param name="Row2">列号2</param> public void EleTransCol3(int Col1, int Col2, double Multiplier) { for (int j = 0; j < RowCount; j++) { this[j, Col1] = this[j, Col1] - this[j, Col2] * Multiplier; } } /// <summary> /// 列初等变换4:列1 * 系数1 - 列2 * 系数2 /// </summary> /// <param name="Col1">列号</param> /// <param name="Col2">列号2</param> /// <param name="M1">乘数1,不能为零</param> /// <param name="M2">乘数2,不能为零</param> public void EleTransCol4(int Col1, int Col2, double M1, double M2) { for (int j = 0; j < RowCount; j++) { this[j, Col1] = this[j, Col1] * M1 - this[j, Col2] * M2; } } #endregion /// <summary> /// 矩阵消元,转换成阶梯矩阵 /// 本算法也可以用来求矩阵的秩. /// 仅用行初等变换. /// </summary> public void TransToEchelonMatrix(List<TransformItem> TransformRecords) { //从第1列到第theE列进行变换. //最大非0行,用以标记进行变换到现在,可以继续进行处理的最小行号. var theNoZeroIndex = 0; for (int i = 0; i < this.ColCount; i++) { var theR = -1; for (int j = theNoZeroIndex; j < this.RowCount; j++) { if (this[j, i] != 0) { theR = j; break; } } if (theR >= 0) { //将找到非零元素行交换到当前行. TransformRecords.Add(TransformItem.CreateEleTransRow1(theR, theNoZeroIndex)); EleTransRow1(theR, theNoZeroIndex); //将大于当前行的列初等变换为0 var theM1 = this[theNoZeroIndex, i]; for (int k = theNoZeroIndex + 1; k < this.RowCount; k++) { var theRate = Math.Round(this[k, i] / theM1,ConstDef.Decimals); TransformRecords.Add(TransformItem.CreateEleTransRow4(k, theNoZeroIndex, 1, theRate)); EleTransRow4(k, theNoZeroIndex, 1, theRate); } theNoZeroIndex++; } } } /// <summary> /// 变换成标准形.方法很简单:先用行初等变换,尽量消元,然后用列初等变换,尽量消元. /// 但在这里会同时用到行列的初等变换.这里采用变换函数,如果为了效率,其实可以将初等 /// 变换代码直接写到函数里。 /// </summary> public List<TransformItem> TransToStandardForm() { var theTransList = new List<TransformItem>(); //从第i=1行开始,使得[i,i]不等于0,然后将剩余的i行,i列的元素通过初等变换变成0. //如果[i,i]无法获得非零元素则变换终止. for (int i = 0; i < this.RowCount; i++) { //如果[i,i]等于0,则进行行交换直到到交换到[i,i]变为非零元素, //如果没找到,就找列,如果都没找到,则终止 var theRow = -1; var theCol = -1; //在行>i,列>i的所有元素中找到一个非零值,如果找到,就进行初等变换 //如果没找到,则说明完成标准型转换. var theFind = false; for (int r = i; r < this.RowCount; r++) { for (int c = i; c < this.ColCount; c++) { if (this[r, c] != 0) { theRow = r; theCol = c; theFind = true; break; } } if (theFind) { break; } } if (theFind) { //先做行变换,再做列变换,目的是将找到的非零元素交换到当前位置. //行初等变换1, theTransList.Add(TransformItem.CreateEleTransRow1(i, theRow)); EleTransRow1(i, theRow); //列初等变换 theTransList.Add(TransformItem.CreateEleTransCol1(i, theCol)); EleTransCol1(i, theCol); //将[i,i] 变为1 double theMultipler = Math.Round((double)1 / this[i, i], ConstDef.Decimals); //行初等变换2(这里采用列也是一样,是等价的) theTransList.Add(TransformItem.CreateEleTransRow2(i, theMultipler)); EleTransRow2(i, theMultipler); //将i行上>i的列上的其它元素变换成0 for (int c = i + 1; c < this.ColCount; c++) { var theM2 = this[i,c]; //c=c*1-i*theM2,这个函数其实是综合了几个初等变换. theTransList.Add(TransformItem.CreateEleTransCol4(c, i,1, theM2)); EleTransCol4(c, i, 1, theM2); } //将i列上>i的行上的其它元素变换成0 for (int r = i + 1; r < this.RowCount; r++) { var theM2 = this[r, i]; //c=c*1-i*theM2,这个函数其实是综合了几个初等变换. theTransList.Add(TransformItem.CreateEleTransRow4(r, i,1,theM2)); EleTransRow4(r, i, 1, theM2); } } else { break; } } return theTransList; } /// <summary> /// 变换成标准形:这里仅采用行变换.但需要注意的是这里如果不是满秩矩阵, /// 得到的就不一定是标准型.这个转换主要用于求矩阵的逆. /// </summary> /// <returns>变换过程记录.</returns> public List<TransformItem> TransToStandardForm2() { var theTransfromRecords = new List<TransformItem>(); //先把矩阵转换成上三角矩阵。 TransToEchelonMatrix(theTransfromRecords); //然后从最后一列开始,第1行开始变换为0. for (int j = this.ColCount - 1; j >= 0; j--) { //从下到上找到第1个非0行,作为基准行(减少行) //因为矩阵的下半部分全为0,则开始找的位置在对角线上开始. int theR = -1; int theStartIndex = Math.Min(j,this.RowCount-1); for (int i = theStartIndex; i >= 0; i--) { if (this[i, j] != 0) { theR = i; break; } } //如果找到基准行,则开始变换,利用减去基准行*一个系数来消除第0到thR-1行的元素 if (theR >= 0) { for (int i = 0; i < theR; i++) { var theRate = Math.Round(this[i, j] / this[theR, j], ConstDef.Decimals); theTransfromRecords.Add(TransformItem.CreateEleTransRow4(i, theR, 1, theRate)); EleTransRow4(i, theR, 1, theRate); } } } //将对角线上的元素化为1 var theMinRC = Math.Min(this.ColCount, this.RowCount); for (int i = 0; i < theMinRC; i++) { if (this[i, i] != 0) { var theRate = Math.Round((double)1.0 / this[i, i], ConstDef.Decimals); EleTransRow2(i, theRate); theTransfromRecords.Add(TransformItem.CreateEleTransRow2(i, theRate)); } } return theTransfromRecords; } /// <summary> /// 对矩阵按照TransformItems里的变换做变换 /// </summary> /// <param name="TransformItems">变换集合</param> public void DoTransform(List<TransformItem> TransformItems) { if (TransformItems == null) { return; } for (int i = 0; i < TransformItems.Count; i++) { var theTransItem = TransformItems[i]; switch (theTransItem.RowOrCol) { case TransRowOrCol.Row: switch (theTransItem.TransMethod) { case BasicTransMethod.Swap: EleTransRow1(theTransItem.i, theTransItem.j); break; case BasicTransMethod.Multipler: EleTransRow2(theTransItem.i, theTransItem.M1); break; case BasicTransMethod.CoPlus1: EleTransRow3(theTransItem.i, theTransItem.j, theTransItem.M1); break; case BasicTransMethod.CoPlus2: EleTransRow4(theTransItem.i, theTransItem.j,theTransItem.M1,theTransItem.M2); break; } break; case TransRowOrCol.Col: switch (theTransItem.TransMethod) { case BasicTransMethod.Swap: EleTransCol1(theTransItem.i, theTransItem.j); break; case BasicTransMethod.Multipler: EleTransCol2(theTransItem.i, theTransItem.M1); break; case BasicTransMethod.CoPlus1: EleTransCol3(theTransItem.i, theTransItem.j, theTransItem.M1); break; case BasicTransMethod.CoPlus2: EleTransCol4(theTransItem.i, theTransItem.j, theTransItem.M1, theTransItem.M2); break; } break; } } } public TMatrix Clone() { var theA = new TMatrix(this.RowCount, this.ColCount); for (int i = 0; i < theA.RowCount; i++) { for (int j = 0; j < theA.ColCount; j++) { theA[i, j] = this[i, j]; } } return theA; } public static TMatrix NewZeroMatrix(int Row, int Col) { return new TMatrix(Row, Col, 0); } public static TMatrix NewSquareMatrix(int n) { return new TMatrix(n, 1, true); } /// <summary> /// 转置矩阵 /// </summary> /// <param name="A">矩阵</param> /// <returns>转置矩阵</returns> public static TMatrix Transposition(TMatrix A) { var theRetM = new TMatrix(A.ColCount, A.RowCount); for (int i = 0; i < A.RowCount; i++) { for (int j = 0; j < A.ColCount; j++) { theRetM[j, i] = A[i, j]; } } return theRetM; } public static TMatrix SwapRow(TMatrix A, int i, int j) { var theA = A.Clone(); theA.SwapRow(i, j); return theA; } public static TMatrix SwapCol(TMatrix A, int i, int j) { var theA = A.Clone(); theA.SwapCol(i, j); return theA; } public static TMatrix operator +(TMatrix A, TMatrix B) { if (A.RowCount != B.RowCount || A.ColCount != B.ColCount) { throw new Exception("不是同型矩阵不能相加!"); } double[][] theResult = new double[A.RowCount][]; for (int i = 0; i < A.RowCount; i++) { theResult[i] = new double[A.ColCount]; for (int j = 0; j < A.ColCount; j++) { theResult[i][j] = A[i, j] + B[i, j]; } } return new TMatrix(theResult); } public static TMatrix operator -(TMatrix A) { var theA = new TMatrix(A.RowCount, A.ColCount); for (int i = 0; i < A.RowCount; i++) { for (int j = 0; j < A.ColCount; j++) { theA[i, j] = 0 - A[i, j]; } } return theA; } public static TMatrix operator -(TMatrix A, TMatrix B) { if (A.RowCount != B.RowCount || A.ColCount != B.ColCount) { throw new Exception("不是同型矩阵,不能相减"); } var theA = new TMatrix(A.RowCount, A.ColCount); for (int i = 0; i < A.RowCount; i++) { for (int j = 0; j < A.ColCount; j++) { theA[i, j] = A[i, j] - B[i, j]; } } return theA; } public static TMatrix operator *(double K, TMatrix A) { if (A.IsZero) { return TMatrix.NewZeroMatrix(A.RowCount, A.ColCount); } var theA = new TMatrix(A.RowCount, A.ColCount); for (int i = 0; i < A.RowCount; i++) { for (int j = 0; j < A.ColCount; j++) { theA[i, j] = K * A[i, j]; } } return theA; } public static TMatrix operator *(decimal K, TMatrix A) { return K * A; } public static TMatrix operator *(TMatrix A, double K) { return K * A; } public static TMatrix operator *(TMatrix A, TMatrix B) { if (A.ColCount != B.RowCount) { throw new Exception("A的列数不等于B的行数,不能相乘!"); } if (A.IsZero) { return TMatrix.NewZeroMatrix(A.RowCount, B.ColCount); } if (A.IsUnit) { return B.Clone(); } if (B.IsUnit) { return A.Clone(); } double[][] theResult = new double[A.RowCount][]; for (int i = 0; i < A.RowCount; i++) { theResult[i] = new double[B.ColCount]; for (int j = 0; j < B.ColCount; j++) { theResult[i][j] = 0; for (int k = 0; k < A.ColCount; k++) { theResult[i][j] += A[i, k] * B[k, j]; } } } return new TMatrix(theResult); } public static TMatrix operator ^(TMatrix A, int K) { if (A.IsSquareMatrix) { if (A.IsUnit) { return A.Clone(); } if (A.IsZero) { return TMatrix.NewZeroMatrix(A.RowCount, A.ColCount); } if (K == 0) { return TMatrix.NewSquareMatrix(A.RowCount); } if (K == 1) { return A.Clone(); } var theA = A; if (K < 0) { theA = GetInverseMatrix(A); } var theRet = theA; for (int i = 1; i < K; K++) { theRet = theRet * theA; } return theRet; } throw new Exception("只有方阵才能做幂运算!"); } public static bool operator ==(TMatrix A, TMatrix B) { if (A.RowCount != B.RowCount || A.ColCount != B.ColCount) { throw new Exception("不是同型矩阵,不能比较"); } if (A.IsUnit && B.IsUnit || A.IsZero && B.IsZero) { return true; } for (int i = 0; i < A.RowCount; i++) { for (int j = 0; j < A.ColCount; j++) { if (A[i, j] != B[i, j]) { return false; } } } return true; } public static bool operator !=(TMatrix A, TMatrix B) { if (A.RowCount != B.RowCount || A.ColCount != B.ColCount) { throw new Exception("不是同型矩阵,不能比较"); } if (A.IsUnit && B.IsUnit || A.IsZero && B.IsZero) { return false; } for (int i = 0; i < A.RowCount; i++) { for (int j = 0; j < A.ColCount; j++) { if (A[i, j] != B[i, j]) { return true; } } } return true; } /// <summary> /// 初等变换法求矩阵A的逆. /// </summary> /// <param name="A"></param> /// <returns></returns> public static TMatrix GetInverseMatrix(TMatrix A) { var theA = A.Clone(); var theTransItems = theA.TransToStandardForm2(); var theE = new TMatrix(theA.RowCount, 1, true); theE.DoTransform(theTransItems); return theE; } /// <summary> /// 古典法求逆矩阵 /// </summary> /// <param name="A">方阵</param> /// <returns></returns> public static TMatrix GetInverseMatrix2(TMatrix A) { if (A.RowCount != A.ColCount) { throw new Exception("次函数仅支持方阵!"); } //计算其行列式的值 var theValOfA = LinearAlgebra.CalcDeterminant(A.Elements); if (theValOfA == 0) { throw new Exception("不可逆!"); } if (A.RowCount == 1) { return new TMatrix(1, 1, Math.Round((double)1.0 / theValOfA,ConstDef.Decimals)); } //求伴随矩阵 //var theAdjoint = new TMatrix(A.RowCount); var theAElements = A.Elements; var theMElements = new double[A.RowCount, A.ColCount]; for (int i = 0; i < A.RowCount; i++) { for (int j = 0; j < A.ColCount; j++) { var theMij = LinearAlgebra.GetDeterminantMij(theAElements, i + 1, j + 1); var theSign = LinearAlgebra.CalcDeterMijSign(i+1, j+1); var theValOfAij = theSign * LinearAlgebra.CalcDeterminant(theMij); //注意这里.弄反了,结果就是逆矩阵的转置矩阵. theMElements[j, i] = theValOfAij; } } //计算伴随矩阵结果. return (Math.Round((double)1.0 / theValOfA,ConstDef.Decimals)) * (new TMatrix(theMElements)); } /// <summary> /// 获取矩阵的秩. /// </summary> /// <returns></returns> public int GetRank() { if (_Rank < 0) { var theA = this.Clone(); theA.TransToStandardForm(); _Rank = GetRank(theA); } return _Rank; } public static int GetRank(TMatrix StdForm) { int theRank = 0; for (int i = 0; i < StdForm.ColCount && i < StdForm.RowCount; i++) { if (StdForm[i, i] == 1) { theRank++; continue; } } return theRank; } /// <summary> /// 是否是标量矩阵 /// </summary> public bool IsScalarMatrix { get { if (this.RowCount != this.ColCount) { return false; } var theScalar = _Elements[0][0]; for (int i = 0; i < this.RowCount; i++) { for (int j = 0; j < this.ColCount; j++) { if (i != j) { if (_Elements[i][j] != 0) { return false; } } else { if (_Elements[i][i] != theScalar) { return false; } } } } return true; } } /// <summary> /// 对角矩阵 非对角线上的元素全部为0方阵 /// </summary> public bool IsDiagonalMatrix { get { if (this.RowCount != this.ColCount) { return false; } for (int i = 0; i < this.RowCount; i++) { for (int j = 0; j < this.ColCount; j++) { if (i != j) { if (_Elements[i][j] != 0) { return false; } } } } return true; } } /// <summary> /// 上三角矩阵 /// </summary> public bool IsUpperTriangularMatrix { get { if (this.RowCount != this.ColCount) { return false; } for (int i = 0; i < this.ColCount; i++) { for (int j = i + 1; j < this.RowCount; j++) { if (_Elements[j][i] != 0) { return false; } } } return true; } } /// <summary> /// 下三角矩阵 /// </summary> public bool IsLowerTriangularMatrix { get { if (this.RowCount != this.ColCount) { return false; } for (int i = 0; i < this.ColCount; i++) { for (int j = 0; j < i; j++) { if (_Elements[j][i] != 0) { return false; } } } return true; } } /// <summary> /// 对称矩阵Aij=Aij. /// </summary> public bool IsSymmetricMatrix { get { if (this.RowCount != this.ColCount) { return false; } for (int i = 0; i < this.RowCount; i++) { for (int j = 0; j < this.ColCount; j++) { if (_Elements[j][i] != _Elements[i][j]) { return false; } } } return true; } } /// <summary> /// 反对称矩阵Aij=-Aji.注意其对角线元素为0. /// </summary> public bool IsAntisymmetricMatrix { get { if (this.RowCount != this.ColCount) { return false; } for (int i = 0; i < this.RowCount; i++) { for (int j = 0; j < this.ColCount; j++) { if (i == j) { if (_Elements[j][i] != 0) { return false; } } else { if (_Elements[j][i] != -_Elements[i][j]) { return false; } } } } return true; } } /// <summary> /// 正交矩阵A*t(A)=E. /// </summary> public bool IsOrthogonalMatrix { get { if (this.RowCount != this.ColCount) { return false; } var theA = this.Clone(); var theAt = Transposition(theA); var theRet = theA * theAt; return theRet.IsUnit; } } /// <summary> /// 零幂矩阵(A^k=O)。 /// |A|==0 /// </summary> public bool IsZeroPowerMatrix { get { if (this.RowCount != this.ColCount) { return false; } var theVal = LinearAlgebra.CalcDeterminant(this.Elements); return theVal == 0; } } } }
时间: 2024-10-12 09:18:12