/// <summary> /// 2つの行列を上側、下側として連結した1個の行列を戻す。 /// </summary> /// <param name="top">上側の行列</param> /// <param name="bottom">下側の行列</param> /// <returns>[top;bottom]</returns> public static WWMatrix JoinV(WWMatrix top, WWMatrix bottom) { if (top.Column != bottom.Column) { throw new ArgumentException("top.column != bottom.column"); } var r = new WWMatrix(top.Row + bottom.Row, top.Column); for (int y = 0; y < top.Row; ++y) { for (int x = 0; x < top.Column; ++x) { r.Set(y, x, top.At(y, x)); } } for (int y = 0; y < bottom.Row; ++y) { for (int x = 0; x < bottom.Column; ++x) { r.Set(top.Row + y, x, bottom.At(y, x)); } } return(r); }
/// <summary> /// 2つの行列を左側右側として連結した1個の行列を戻す。 /// </summary> /// <param name="left">左側の行列</param> /// <param name="right">右側の行列</param> /// <returns>[left right]</returns> public static WWMatrix JoinH(WWMatrix left, WWMatrix right) { if (left.Row != right.Row) { throw new ArgumentException("left.Row != right.Row"); } var r = new WWMatrix(left.Row, left.Column + right.Column); for (int y = 0; y < left.Row; ++y) { for (int x = 0; x < left.Column; ++x) { r.Set(y, x, left.At(y, x)); } } for (int y = 0; y < right.Row; ++y) { for (int x = 0; x < right.Column; ++x) { r.Set(y, left.Column + x, right.At(y, x)); } } return(r); }
public static WWMatrix Mul(WWMatrix lhs, WWMatrix rhs) { if (lhs.Column != rhs.Row) { throw new ArgumentException("lhs.Column != rhs.Row"); } int loopCount = lhs.Column; var rv = new WWMatrix(lhs.Row, rhs.Column); for (int r = 0; r < rv.Row; ++r) { for (int c = 0; c < rv.Column; ++c) { double v = 0; for (int i = 0; i < loopCount; ++i) { v += lhs.At(r, i) * rhs.At(i, c); } rv.Set(r, c, v); } } return(rv); }
/// <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); }
public static double[] Transform(double[] from) { if (!IsPowerOf2(from.Length)) { throw new ArgumentException("from length is not power of 2"); } int L = from.Length; // Lは2のN乗。 int N = 0; for (int i = L; 1 < i; i /= 2) { ++N; } var m = new WWMatrix(L, N + 1); for (int r = 0; r < L; ++r) { m.Set(r, 0, from[r]); } for (int c = 0; c < N; ++c) { for (int r = 0; r < L / 2; ++r) { m.Set(r, c + 1, m.At(r * 2, c) + m.At(r * 2 + 1, c)); } for (int r = 0; r < L / 2; ++r) { m.Set(r + L / 2, c + 1, m.At(r * 2, c) - m.At(r * 2 + 1, c)); } } var rv = new double[L]; for (int r = 0; r < L; ++r) { rv[r] = m.At(r, N); } return(rv); }
/// <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); }
/// <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); }