public void MatrixLU() { int N = 2; var A = new WWMatrix(N, N, new double[] { 4, 3, 6, 3 }); WWMatrix L; WWMatrix U; var result = WWMatrix.LUdecompose(A, out L, out U); Assert.IsTrue(result == WWMatrix.ResultEnum.Success); // Lは下三角行列。 var Ltype = L.DetermineMatType(); Assert.IsTrue(0 != (Ltype & (ulong)WWMatrix.MatType.LowerTriangular)); // Uは上三角行列。 var Utype = U.DetermineMatType(); Assert.IsTrue(0 != (Utype & (ulong)WWMatrix.MatType.UpperTriangular)); // L * U = A WWMatrix Arecovered = WWMatrix.Mul(L, U); Assert.IsTrue(WWMatrix.IsSame(A, Arecovered)); }
/// <summary> /// 接続行列AとA^T*CAを表示。 /// </summary> private void CalcConnectionMat() { var pList = mDGEditor.PointList(); var eList = mDGEditor.EdgeList(); if (pList.Count == 0 || eList.Count == 0) { return; } var A = CalcA(); AddLog(string.Format("A: {0}", A.ToString())); var C = CalcC(); AddLog(string.Format("C: {0}", C.ToString())); var CA = WWMatrix.Mul(C, A); var AT = A.Transpose(); var AT_CA = WWMatrix.Mul(AT, CA); AddLog(string.Format("A^T*CA: {0}", AT_CA.ToString())); }
/// <summary> /// 接続行列Aを戻す。 /// </summary> private WWMatrix CalcA() { var pList = mDGEditor.PointList(); var eList = mDGEditor.EdgeList(); var earthP = mDGEditor.EarthedPoint(); int aRow = eList.Count; int aCol = pList.Count; if (earthP != null) { // アースによって1列除去。これによりATAが可逆になる。 aCol = pList.Count - 1; } var A = new WWMatrix(aRow, aCol); { // 行列A(接続行列)を作成する。 // ストラング, 計算理工学 p143 for (int e = 0; e < eList.Count; ++e) { var edge = eList[e]; int nP = 0; for (int p = 0; p < pList.Count; ++p) { var point = pList[p]; if (point == earthP) { // アースされている点は除外。 continue; } double v = 0; // エッジのfromがpのとき、-1 // エッジのto がpのとき、+1 if (edge.fromPointIdx == point.Idx) { v = -1; } if (edge.toPointIdx == point.Idx) { v = +1; } A.Set(e, nP, v); ++nP; } } } return(A); }
public void SolveTestK3_1() { int N = 3; var K = new WWMatrix(N, N, new double[] { 2, -1, 0, -1, 2, -1, 0, -1, 2 }); var f = new double[] { 4, 0, 0 }; double[] u = WWLinearEquation.SolveKu_eq_f(K, f); Assert.IsTrue(IsApproxSame(u, new double[] { 3, 2, 1 })); }
/// <summary> /// 重み行列Cの逆行列。 /// </summary> private WWMatrix CalcCinv() { var eList = mDGEditor.EdgeList(); var Cinv = new WWMatrix(eList.Count, eList.Count); { // 行列C 重み行列。 for (int x = 0; x < eList.Count; ++x) { var edge = eList[x]; Cinv.Set(x, x, 1.0 / edge.C); } } return(Cinv); }
public void SolveTestK4_1() { int N = 4; var K = new WWMatrix(N, N, new double[] { 2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2 }); var f = new double[] { 1, 0, 0, 0 }; double[] u = WWLinearEquation.SolveKu_eq_f(K, f); Assert.IsTrue(IsApproxSame(u, new double[] { 4.0 / 5, 3.0 / 5, 2.0 / 5, 1.0 / 5 })); }
public void MatrixJoinH() { int N = 2; var A = new WWMatrix(N, N, new double[] { 1, 2, 3, 4 }); var B = new WWMatrix(N, N, new double[] { 5, 6, 7, 8 }); var AB = WWMatrix.JoinH(A, B); var ABref = new WWMatrix(N, N * 2, new double[] { 1, 2, 5, 6, 3, 4, 7, 8 }); Assert.IsTrue(WWMatrix.IsSame(AB, ABref)); }
public void MatrixLPU_4x4() { int N = 4; var r = new Random(); for (int i = 0; i < 1000; ++i) { var A = new WWMatrix(N, N, new double[] { r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10), r.Next(10) }); WWMatrix P; WWMatrix L; WWMatrix U; var result = WWMatrix.LUdecompose2(A, out L, out P, out U); if (result == WWMatrix.ResultEnum.FailedToChoosePivot) { continue; } Assert.IsTrue(result == WWMatrix.ResultEnum.Success); // Lは下三角行列。 var Ltype = L.DetermineMatType(); Assert.IsTrue(0 != (Ltype & (ulong)WWMatrix.MatType.LowerTriangular)); // Uは上三角行列。 var Utype = U.DetermineMatType(); Assert.IsTrue(0 != (Utype & (ulong)WWMatrix.MatType.UpperTriangular)); A.Print("A"); L.Print("L"); U.Print("U"); P.Print("P"); // P * A = L * U var LU = WWMatrix.Mul(L, U); var PA = WWMatrix.Mul(P, A); Assert.IsTrue(WWMatrix.IsSame(PA, LU)); } }
public void MatrixLPU_3x3a() { int N = 3; var A = new WWMatrix(N, N, new double[] { 6, 4, 1, 3, 3, 2, 7, 7, 3 }); WWMatrix P; WWMatrix L; WWMatrix U; var result = WWMatrix.LUdecompose2(A, out L, out P, out U); Assert.IsTrue(result == WWMatrix.ResultEnum.Success); // Lは下三角行列。 var Ltype = L.DetermineMatType(); Assert.IsTrue(0 != (Ltype & (ulong)WWMatrix.MatType.LowerTriangular)); // Uは上三角行列。 var Utype = U.DetermineMatType(); Assert.IsTrue(0 != (Utype & (ulong)WWMatrix.MatType.UpperTriangular)); A.Print("A"); L.Print("L"); U.Print("U"); P.Print("P"); // P * A = L * U var LU = WWMatrix.Mul(L, U); var PA = WWMatrix.Mul(P, A); Assert.IsTrue(WWMatrix.IsSame(PA, LU)); }
public void Test(double[] recorded) { // 動作テスト int N = mOrder; int P = (1 << N) - 1; var from = new double[P + 1]; { int copySize = recorded.Length; if (from.Length < copySize) { copySize = from.Length; } Array.Copy(recorded, from, copySize); } byte[] mlsSeq; { var mls = new MaximumLengthSequence(N); mlsSeq = mls.Sequence(); for (int i = 0; i < mlsSeq.Length; ++i) { Console.Write("{0} ", mlsSeq[i]); } Console.WriteLine(""); } { var mlsD = new double[mlsSeq.Length]; for (int i = 0; i < mlsD.Length; ++i) { mlsD[i] = mlsSeq[i] * 2.0 - 1.0; } var ccc = CrossCorrelation.CalcCircularCrossCorrelation(mlsD, mlsD); for (int i = 0; i < ccc.Length; ++i) { Console.Write("{0:g2} ", ccc[i]); } Console.WriteLine(""); } var mlsMat = new MatrixGF2(P, P); { for (int y = 0; y < P; ++y) { for (int x = 0; x < P; ++x) { mlsMat.Set(y, x, (0 != mlsSeq[(x + y) % P]) ? GF2.One : GF2.Zero); } } } mlsMat.Print("MLS matrix"); // σ: mlsMatの左上N*N要素 var σ = mlsMat.Subset(0, 0, N, N); σ.Print("σ"); var σInv = σ.Inverse(); σInv.Print("σ^-1"); // S: MLS行列の上N行。 var S = mlsMat.Subset(0, 0, N, P); S.Print("S"); // Sの転置S^T S.Transpose().Print("S^T"); // L: Sの転置 x σInv var L = S.Transpose().Mul(σInv); L.Print("L"); // L x S == MLS行列 var LS = L.Mul(S); LS.Print("L x S"); int diff = LS.CompareTo(mlsMat); System.Diagnostics.Debug.Assert(diff == 0); // 2進で0~P-1までの値が入っている行列 var B = new MatrixGF2(P + 1, N); var Bt = new MatrixGF2(N, P + 1); for (int r = 0; r < P + 1; ++r) { for (int c = 0; c < N; ++c) { int v = r & (1 << (N - 1 - c)); var b = (v == 0) ? GF2.Zero : GF2.One; B.Set(r, c, b); Bt.Set(c, r, b); } } B.Print("B"); Bt.Print("Bt"); // アダマール行列H8 var H8 = MatrixGF2.Mul(B, Bt); H8.Print("H8"); var vTest = new double[P + 1]; for (int i = 0; i < P + 1; ++i) { vTest[i] = i; } var r1 = H8.ToMatrix().Mul(vTest); Print(r1, "R1"); var r2 = FastWalshHadamardTransform.Transform(vTest); Print(r2, "R2"); // Ps: S行列の列の値を2進数として、順番入れ替え行列を作る var Ps = new MatrixGF2(P + 1, P + 1); var PsReorder = new List <int>(); PsReorder.Add(0); for (int c = 0; c < P; ++c) { int sum = 0; for (int r = 0; r < N; ++r) { sum += (1 << (N - 1 - r)) * S.At(r, c).Val; } Console.WriteLine("Ps: c={0} sum={1}", c, sum); Ps.Set(sum, c + 1, GF2.One); PsReorder.Add(sum); } Ps.Print("Ps"); { var testMat = new WWMatrix(P + 1, 1); for (int r = 0; r < P + 1; ++r) { testMat.Set(r, 0, PsReorder[r]); } var PsTest = Ps.ToMatrix().Mul(testMat); PsTest.Print("Ps x n"); } // Pl: L行列の列の値を2進数として、順番入れ替え行列を作る var Pl = new MatrixGF2(P + 1, P + 1); var PlReorder = new List <int>(); PlReorder.Add(0); for (int r = 0; r < P; ++r) { int sum = 0; for (int c = 0; c < N; ++c) { sum += (1 << (N - 1 - c)) * L.At(r, c).Val; } Console.WriteLine("Pl: r={0} sum={1}", r, sum); Pl.Set(r + 1, sum, GF2.One); PlReorder.Add(sum); } Pl.Print("Pl"); S.Print("S"); var BtPs = Bt.Mul(Ps); BtPs.Print("BtPs"); L.Print("L"); var PlB = Pl.Mul(B); PlB.Print("PlB"); { var test2Mat = new WWMatrix(P + 1, 1); for (int r = 0; r < P + 1; ++r) { test2Mat.Set(r, 0, r); } var PlTest = Pl.ToMatrix().Mul(test2Mat); PlTest.Print("Pl x n"); } mlsMat.Print("MLS mat"); var Mhat = Pl.Mul(H8).Mul(Ps); Mhat.Print("Mhat"); // MLS deconvolution var decon = Mhat.ToMatrix().Mul(from); Print(decon, "decon"); // 同じ処理をWalsh-Hadamard変換を使って行う。 var reorderedFrom = new double[P + 1]; for (int i = 0; i < P + 1; ++i) { reorderedFrom[PsReorder[i]] = from[i]; } #if true var hR = FastWalshHadamardTransform.Transform(reorderedFrom); #else var hR = H8.ToMatrix().Mul(reorderedFrom); #endif var hTo = new double[P + 1]; for (int i = 0; i < P + 1; ++i) { hTo[i] = hR[PlReorder[i]]; } Print(hTo, "hTo"); }
/// <summary> /// Polynomial function fitting. /// </summary> /// <param name="knownYs">known y values.</param> /// <param name="knownXs">known x values.</param> /// <param name="nthOrder">Order of fitting polynomial function.</param> /// <returns>List of nth order polynomial function coefficients.</returns> public static Result Calc(double[] knownYs, double[] knownXs, int nthOrder) { System.Diagnostics.Debug.Assert(knownYs.Length == knownXs.Length); System.Diagnostics.Debug.Assert(0 < nthOrder); System.Diagnostics.Debug.Assert(nthOrder < knownXs.Length); // 2d coordinate data sample count int count = knownXs.Length; int maxOrderXn = 2 * nthOrder; var sumXn = new double[maxOrderXn + 1]; for (int i = 0; i < count; ++i) { double x = knownXs[i]; for (int h = 0; h <= maxOrderXn; ++h) { sumXn[h] += System.Math.Pow(x, h); } } // Create Vandermonde matrix vm var vm = new WWMatrix(nthOrder + 1, nthOrder + 1); for (int y = 0; y <= nthOrder; ++y) { for (int x = 0; x <= nthOrder; ++x) { int order = (nthOrder - x) + (nthOrder - y); vm.Set(y, x, sumXn[order]); } } var sumXnY = new double[nthOrder + 1]; for (int i = 0; i < count; ++i) { double x = knownXs[i]; double y = knownYs[i]; for (int h = 0; h <= nthOrder; ++h) { sumXnY[h] += System.Math.Pow(x, h) * y; } } // 若干わかり難いが、 // f[0] = sumXnY[nthOrder] // f[nthOrder] = sumXnY[0] なので、 // fはnthOrder+1要素必要。 var f = new double[nthOrder + 1]; for (int i = 0; i <= nthOrder; ++i) { f[i] = sumXnY[nthOrder - i]; } // Solve vm u = f to get u var u = WWLinearEquation.SolveKu_eq_f(vm, f); var r = new Result(); r.c = new double[nthOrder + 1]; for (int i = 0; i <= nthOrder; ++i) { r.c[i] = u[nthOrder - i]; } return(r); }
/// <summary> /// KKT行列を作って解く。 /// </summary> private void SolveKKT() { var pList = mDGEditor.PointList(); var eList = mDGEditor.EdgeList(); var earthP = mDGEditor.EarthedPoint(); if (pList.Count == 0 || eList.Count == 0) { return; } var A = CalcA(); AddLog(string.Format("A: {0}", A.ToString())); var C = CalcC(); // A^T var AT = A.Transpose(); // K = A^T C Aを作る。 var K = new WWMatrix(pList.Count - 1, pList.Count - 1); { var CA = WWMatrix.Mul(C, A); K = WWMatrix.Mul(AT, CA); } AddLog(string.Format("K: {0}", K.ToString())); var b = new WWMatrix(eList.Count, 1); { // 電圧源b for (int i = 0; i < eList.Count; ++i) { var e = eList[i]; b.Set(i, 0, e.B); } } AddLog(string.Format("b: {0}", b.ToString())); var f = new WWMatrix(pList.Count - 1, 1); { // fを作る。 int nP = 0; for (int i = 0; i < pList.Count; ++i) { var point = pList[i]; if (point == earthP) { // アースされている点は除外。 continue; } f.Set(nP, 0, point.F); ++nP; } } AddLog(string.Format("f: {0}", f.ToString())); WWMatrix KKT; { // KKT行列 var Cinv = CalcCinv(); var Cinv_A = WWMatrix.JoinH(Cinv, A); var AT_zero = WWMatrix.JoinH(AT, new WWMatrix(A.Column, A.Column)); KKT = WWMatrix.JoinV(Cinv_A, AT_zero); } AddLog(string.Format("KKT: {0}", KKT.ToString())); WWMatrix bf; { // bとfを縦に連結した縦ベクトル。 bf = WWMatrix.JoinV(b, f); } AddLog(string.Format("bf: {0}", bf.ToString())); var bfA = bf.ToArray(); // KKT u = bfを解いて uを求める。 var uA = WWLinearEquation.SolveKu_eq_f(KKT, bfA); var u = new WWMatrix(uA.Length, 1, uA); AddLog(string.Format("u: {0}", u.ToString())); }
private void Calc() { int N = 0; if (!int.TryParse(textBoxNumElems.Text, out N) || N <= 0) { MessageBox.Show("Error: Num of Elems should be integer larger than 0"); return; } // 試験関数Vkとf(x)との積分Fk=∫f(x)Vk dxを求める。 var f = new double[N]; for (int i = 0; i < N; ++i) { double x = (double)(i + 1) / N; double y = mGraphFx.Sample(x); // 最後の区間は半区間。 double Vk = (i == N - 1) ? (1.0 / N / 2) : (1.0 / N); f[i] = y * Vk; } // 合成行列K // Kij = ∫c(x)dVi/dx dVj/dx dx // i=j=0のとき、dVi/dxは、 // 0≦x<1/N の区間でVi'=Vj'= +N → Vi'*Vj' = N^2 // 1/N≦x<2/Nの区間でVi'=Vj'= -N → Vi'*Vj' = N^2 // 区間 値 // ∫c(x)dVi/dx dVj/dx dx = (2/N) * N^2 // i=0,j=1のとき // 0≦x<1/N の区間でVi'=+N, Vj'= 0 → Vi'Vj' = 0 // 1/N≦x<2/Nの区間でVi'=-N, Vj'= N → Vi'Vj' = -N^2 // 2/N≦x<3/Nの区間でVi'= 0, Vj'=-N → Vi'Vj' = 0 // 区間 値 // ∫c(x)dVi/dx dVj/dx dx = (1/N) * (-N^2) // i=N-1, j=N-1のとき // N-1/N≦x<1の区間でVi'=Vj'=N → Vi'Vj' = N^2 // 区間 値 // ∫c(x)dVi/dx dVj/dx dx = (1/N) * (N^2) var Kij = new double[N * N]; for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) { int pos = i * N + j; double x = (double)(i + 1) / N; double c = mGraphCx.Sample(x); if (i == N - 1 && j == N - 1) { Kij[pos] = c * (double)(1.0 / N) * N * N; } else if (i == j) { Kij[pos] = c * (double)(2.0 / N) * N * N; } else if (Math.Abs(i - j) == 1) { Kij[pos] = c * (double)(1.0 / N) * (-N * N); } else { Kij[pos] = 0; } } } var K = new WWMatrix(N, N, Kij); // Ku=fを解いてUを求める。 var u = WWLinearEquation.SolveKu_eq_f(K, f); { // 求まったUをグラフにする。 mGraphUx.SetArbitraryFunctionStart(); // U(0) = 0 : 境界条件。 mGraphUx.SetArbitraryFunctionPoint(0, 0); for (int i = 0; i < u.Length; ++i) { double x = (double)(i + 1) / N; double y = u[i]; mGraphUx.SetArbitraryFunctionPoint(x, y); } mGraphUx.SetArbitraryFunctionEnd(); } }