/// <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); }
/// <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 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())); }