/// <summary> /// https://en.wikipedia.org/wiki/Crout_matrix_decomposition /// </summary> public static ResultEnum LUdecompose(WWMatrix inA, out WWMatrix outL, out WWMatrix outU, double epsilon = 1.0e-7) { if (inA.Row < 2 || inA.Row != inA.Column) { outL = new WWMatrix(0, 0); outU = new WWMatrix(0, 0); return(ResultEnum.UnsupportedMatrixShape); } int N = inA.Row; outL = new WWMatrix(N, N); outU = new WWMatrix(N, N); outU.SetIdentity(); for (int x = 0; x < N; ++x) { for (int y = x; y < N; ++y) { double sum = 0; for (int k = 0; k < x; ++k) { sum += outL.At(y, k) * outU.At(k, x); } outL.Set(y, x, inA.At(y, x) - sum); } for (int y = x; y < N; ++y) { double sum = 0; for (int k = 0; k < x; ++k) { sum += outL.At(x, k) * outU.At(k, y); } if (WWMathUtil.IsAlmostZero(outL.At(x, x), epsilon)) { return(ResultEnum.FailedToChoosePivot); } outU.Set(x, y, (inA.At(x, y) - sum) / outL.At(x, x)); } } return(ResultEnum.Success); }
/// <summary> /// aとbが大体同じ時true。異なるときfalse。 /// </summary> public static bool IsSame(WWMatrix a, WWMatrix b, double epsilon = 1.0e-7) { if (a.Column != b.Column || a.Row != b.Row) { return(false); } for (int y = 0; y < a.Row; ++y) { for (int x = 0; x < a.Column; ++x) { if (!WWMathUtil.IsAlmostZero(a.At(y, x) - b.At(y, x), epsilon)) { return(false); } } } return(true); }
public ulong DetermineMatType(double epsilon = 1.0e-7) { mMatTypeFlags = 0; if (mRow != mCol) { // 正方行列でない。 return(mMatTypeFlags); } // 正方行列である。 mMatTypeFlags |= (ulong)MatType.Square; { // 上三角行列か。 // 上三角行列=左下が0。 bool b = true; for (int x = 0; x < mCol; ++x) { for (int y = x + 1; y < mRow; ++y) { if (!WWMathUtil.IsAlmostZero(At(y, x), epsilon)) { b = false; break; } } if (!b) { break; } } if (b) { mMatTypeFlags |= (ulong)MatType.UpperTriangular; } } { // 下三角行列か。 // 下三角行列=右上が0。 bool b = true; for (int y = 0; y < mRow; ++y) { for (int x = y + 1; x < mCol; ++x) { if (!WWMathUtil.IsAlmostZero(At(y, x), epsilon)) { b = false; break; } } if (!b) { break; } } if (b) { mMatTypeFlags |= (ulong)MatType.LowerTriangular; } } if (0 != (mMatTypeFlags & (ulong)MatType.UpperTriangular) && 0 != (mMatTypeFlags & (ulong)MatType.LowerTriangular)) { // 上三角かつ下三角のとき、対角行列。 mMatTypeFlags |= (ulong)MatType.Diagonal; } { // 三重対角行列か。 bool isTriDiag = true; // 右上が0である事。 for (int y = 0; y < mRow; ++y) { for (int x = y + 2; x < mCol; ++x) { if (!WWMathUtil.IsAlmostZero(At(y, x), epsilon)) { isTriDiag = false; break; } } if (!isTriDiag) { break; } } if (isTriDiag) { // 左下が0である事。 for (int x = 0; x < mCol; ++x) { for (int y = x + 2; y < mRow; ++y) { if (!WWMathUtil.IsAlmostZero(At(y, x), epsilon)) { isTriDiag = false; break; } } if (!isTriDiag) { break; } } } if (isTriDiag) { mMatTypeFlags |= (ulong)MatType.Tridiagonal; } } return(mMatTypeFlags); }
/// <summary> /// https://www.student.cs.uwaterloo.ca/~cs370/notes/LUExample2.pdf /// </summary> public static ResultEnum LUdecompose2(WWMatrix inA, out WWMatrix outL, out WWMatrix outP, out WWMatrix outU, double epsilon = 1.0e-7) { if (inA.Row < 2 || inA.Row != inA.Column) { outP = new WWMatrix(0, 0); outL = new WWMatrix(0, 0); outU = new WWMatrix(0, 0); return(ResultEnum.UnsupportedMatrixShape); } int N = inA.Row; outP = new WWMatrix(N, N).SetIdentity(); outL = new WWMatrix(N, N).SetIdentity(); outU = new WWMatrix(N, N); outU = inA.DeepCopy(); var PA = new WWMatrix(N, N); // Lの0行目は [1 0 0 ... 0] for (int c = 0; c < N - 1; ++c) { // c個目のピボットを選択する。 // Uのc列を比較し、絶対値が最大のものを選ぶ。 // Pのc行目が決定する。 int maxRow = c; { double maxAbs = 0; for (int y = c; y < N; ++y) { if (maxAbs < Math.Abs(outU.At(y, c))) { maxAbs = Math.Abs(outU.At(y, c)); maxRow = y; } } } // ピボットは、maxRow行c列。 outU.ExchangeRows(c, maxRow); outP.ExchangeRows(c, maxRow); outL.ExchangeRows(c, maxRow); outL.ExchangeCols(c, maxRow); // 並び替えによりuccがピボットになった。 double ucc = outU.At(c, c); if (WWMathUtil.IsAlmostZero(ucc, epsilon)) { return(ResultEnum.FailedToChoosePivot); } for (int k = c + 1; k < N; ++k) { // Uのk列目の計算。 // Uのk列目を0にするために、1列目を何倍して足すか。 double ukc = outU.At(k, c); double ratio = ukc / ucc; for (int x = 0; x < N; ++x) { double ucx = outU.At(c, x); double ukx = outU.At(k, x); outU.Set(k, x, ukx - ratio * ucx); } // Lのk行c列 = ratio。 outL.Set(k, c, ratio); } } return(ResultEnum.Success); }