コード例 #1
0
        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));
        }
コード例 #2
0
        /// <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()));
        }
コード例 #3
0
        /// <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);
        }
コード例 #4
0
        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 }));
        }
コード例 #5
0
        /// <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);
        }
コード例 #6
0
        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 }));
        }
コード例 #7
0
        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));
        }
コード例 #8
0
        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));
            }
        }
コード例 #9
0
        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));
        }
コード例 #10
0
        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");
        }
コード例 #11
0
        /// <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);
        }
コード例 #12
0
        /// <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()));
        }
コード例 #13
0
        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();
            }
        }