Beispiel #1
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 }));
        }
Beispiel #2
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 }));
        }
Beispiel #3
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);
        }
Beispiel #4
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()));
        }
        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();
            }
        }