/// <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); }
/// <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); }
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> /// aを縦行列と見做して後から掛ける /// rv := M x aT /// 自分自身を変更しない。 /// </summary> /// <returns>乗算結果の行列を転置したもの</returns> public double[] Mul(double[] a) { if (mCol != a.Length) { throw new ArgumentException("a.Length != mat.Col"); } var aT = new WWMatrix(a.Length, 1, a); var rv = Mul(aT); return(rv.ToArray()); }
public WWMatrix ToMatrix() { WWMatrix rv = new WWMatrix(mRow, mCol); for (int r = 0; r < mRow; ++r) { for (int c = 0; c < mCol; ++c) { rv.Set(r, c, At(r, c).Val); } } return(rv); }
/// <summary> /// 転置した行列を作って戻す。 /// 自分自身を変更しない。 /// </summary> /// <returns>転置した行列。</returns> public WWMatrix Transpose() { var t = new WWMatrix(mCol, mRow); for (int y = 0; y < mRow; ++y) { for (int x = 0; x < mCol; ++x) { t.Set(x, y, At(y, x)); } } return(t); }
/// <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> /// Solve and find f for Ku = f /// </summary> /// <param name="K">N * N matrix</param> /// <param name="f">N elem vertical vector</param> /// <returns>u : N elem vertical vector. zero elem vector returns when failed.</returns> public static double[] SolveKu_eq_f(WWMatrix K, double[] f) { int N = K.Row; if (K.Column != N) { throw new ArgumentException("K.col != K.row"); } if (f.Length != N) { throw new ArgumentException("f.Length != K.row"); } var u = new double[N]; WWMatrix L; WWMatrix P; WWMatrix U; var r = WWMatrix.LUdecompose2(K, out L, out P, out U); if (r != WWMatrix.ResultEnum.Success) { return(new double[0]); } // Reorder f var fr = P.Mul(f); var c = new double[N]; // 前進消去 Lc=fによりcを求める。 // L c = f // L → L (既知) // c → c (既知) // f → fr (既知) for (int i = 0; i < N; ++i) { double t = fr[i]; for (int j = 0; j < i; ++j) { // i: row番号、j:col番号。 t -= L.At(i, j) * c[j]; } c[i] = t / L.At(i, i); } // cが求まった。 // U u = c // U → U (既知) // u → u (解) // c → c (既知) // 後退代入で解uを得る。 for (int i = N - 1; 0 <= i; --i) { double t = c[i]; // j=i+1行目より下のu_jは求まっている。 for (int j = i + 1; j < N; ++j) { t -= U.At(i, j) * u[j]; } u[i] = t / U.At(i, i); } return(u); }
/// <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); }
/// <summary> /// rv := this x a /// 自分自身を変更しない。 /// </summary> /// <returns>乗算結果。</returns> public WWMatrix Mul(WWMatrix a) { return(Mul(this, a)); }
/// <summary> /// コピーを作って戻す。 /// mの実体も複製される。 /// </summary> public WWMatrix DeepCopy() { var r = new WWMatrix(mRow, mCol, m); return(r); }