using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Mol; /* 使用例:Hirbert行列 A を用いた Ax=b を解きます(bの全要素は1)。 // LuDecomp(A,n) で A の要素は LU 要素で上書きされます。 // 元の A[i,j] 要素を保存し、検算に使用する場合は * の付いたコメントを参考(A.FieldIndexを使用)にしてください。 int n = 1000; BigMatrix A = new BigMatrix(); A.OpenRenew("Test.ldb"); DateTime dt = DateTime.Now; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { double Aij = 1.0 / (i + j + 1); A[i, j] = Aij; // * A[i,j] 要素を2つ確保。先頭要素は LU 分解で上書きされるため。 // A.AddRecord(new int[] { i, j }, new double[] { Aij, Aij }); } } T.P("書込み時間 = " + (DateTime.Now - dt)); dt = DateTime.Now; int [] ps = BigMatrix.LuDecomp(A,n); T.P("因子分解時間 = " + (DateTime.Now - dt)); double [] b = new double[n]; for(int i=0;i係数行列/LU分解の結果 /// A のサイズ /// ピボット交換用のインデックス配列(後のLuSolve()で使用) public static int[] LuDecomp(BigMatrix A, int n) { int[] ps = new int[n]; double[] scales = new double[n]; // ピボット要素の選択(行単位) for (int i = 0; i < n; ++i) { ps[i] = i; double nrmrow = 0; for (int j = 0; j < n; ++j) { double v = Math.Abs(A[i, j]); if (v > nrmrow) nrmrow = v; } if (nrmrow<=double.Epsilon) throw new Exception("Singular matrix in LuDecomp(phase-1):" + i); scales[i] = 1.0/ nrmrow; } // 消去法による三角化 int n1 = n - 1; for (int k = 0; k < n1; ++k) { double biggst = 0; int pividx = 0; for (int i = k; i < n; ++i) { double size = Math.Abs(A[ps[i], k] * scales[ps[i]]); if (size > biggst) { biggst = size; pividx = i; } } if (biggst<=double.Epsilon) throw new Exception("Singular matrix in LuDecomp(phase-2):" + k); if (pividx != k) { int j = ps[k]; ps[k] = ps[pividx]; ps[pividx] = j; } double pivot = A[ps[k], k]; for (int i = (k + 1); i < n; ++i) { double EM = A[ps[i], k] / pivot; A[ps[i], k] = EM; for (int j = (k + 1); j < n; ++j) { A[ps[i], j] -= EM * A[ps[k], j]; } } } if (Math.Abs(A[ps[n1], n1])<=double.Epsilon) throw new Exception("Singular matrix in LuDecomp(phase-3)" + n1); return ps; } /// /// LuDecomp()で LU 分解された A を使用して線形連立式 Ax = b を解きます。 /// /// LU 分解された係数行列 /// 定数ベクトル /// ピボット変換用インデックス /// 行列のサイズ /// 解ベクトル x public static double[] LuSolve(BigMatrix A, double[] b, int[] ps, int n) { double[] x = new double[n]; for (int i = 0; i < n; ++i) { double dot = 0; for (int j = 0; j < i; ++j) { dot -= A[ps[i], j] * x[j]; } x[i] = b[ps[i]] + dot; } for (int i = n - 1; i >= 0; --i) { double dot = 0; for (int j = (i + 1); j < n; ++j) { dot += A[ps[i], j] * x[j]; } dot = x[i] - dot; x[i] = dot / A[ps[i], i]; } return x; } } }