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