public static double[] RealFastFourierTransform(Complex[] src, double amplitude = 1.0) { int n4 = 1 << (Mt.Log2Int(src.Length) - 1); int n = n4 * 4, n2 = n4 * 2, n3 = n4 * 3; int n2mask = n2 - 1; Complex[] Data = new Complex[n2]; TriangularTable Triangle = TriangularTable.Get(n); for (int i = n4; i >= 0; --i) { int j = n2 - i; Complex g1 = src[i]; Complex g2 = Complex.Conjugate(src[j]); Complex h1 = (g1 + g2); Complex h2 = (g1 - g2) * Triangle.Complex(n4 + i); Data[i] = (h1 + h2); Data[j & n2mask] = Complex.Conjugate(h1 - h2); } Data = FastFourierTransform_(Data, false); LetMul(Data, amplitude / n); double[] Dst = New.Array(n, i => (i & 1) == 0 ? Data[i / 2].Real : Data[i / 2].Imaginary); return(Dst); }
//--------------------------------------------------------------------------- #region Numerical optimization functions public static double[] ArgminSimplex(double[] arguments, double[] delta, Func <double[], double> func, double tolerance) { int EstimationCountMax = 5000; int EstimationCount = 0; int D = arguments.Length, D1 = D + 1; double[][] Args = New.Array(D + 1, j => New.Array(D, i => arguments[i] + (i == j ? delta[i] : 0.0))); double[] ArgSum = New.Array(D, i => Ex.Range(D + 1).Sum(j => Args[j][i])); double[] ArgTry = new double[D]; double[] Values = Args.Select(arg => func(arg)).ToArray(); Func <int, double, double> tryfunc = (int i, double fac) => { double[] arg = Args[i]; double fac1 = (1 - fac) / D; double fac2 = fac1 - fac; for (int j = D; --j >= 0;) { ArgTry[j] = ArgSum[j] * fac1 - arg[j] * fac2; } double y = func(ArgTry); if (Values[i] > y) { Values[i] = y; for (int j = D; --j >= 0;) { ArgSum[j] += ArgTry[j] - arg[j]; arg[j] = ArgTry[j]; } } return(y); }; while (true) { int iMin = 0; int iMax = Values[0] > Values[1] ? 0 : 1; int iMax2 = 1 - iMax; for (int i = 0; i < D1; i++) { double v = Values[i]; if (v <= Values[iMin]) { iMin = i; } if (v > Values[iMax]) { iMax2 = iMax; iMax = i; } else if (v > Values[iMax2] && i != iMax) { iMax2 = i; } } double d = 2.0 * Math.Abs(Values[iMax] - Values[iMin]) / (Math.Abs(Values[iMax]) + Math.Abs(Values[iMin]) + Mt.DoubleEps); if (d < tolerance) { break; } if (EstimationCount >= EstimationCountMax) { ThrowException.WriteLine("ArgminSimplex: too many function estimations."); break; } EstimationCount += 2; double vTry = tryfunc(iMax, -1); if (vTry <= Values[iMin]) { tryfunc(iMax, 2); continue; } if (vTry < Values[iMax2]) { EstimationCount--; continue; } double vTryPrev = Values[iMax]; vTry = tryfunc(iMax, 0.5); if (vTry < vTryPrev) { continue; } EstimationCount += D; for (int i = 0; i < D1; i++) { if (i == iMin) { continue; } for (int j = 0; j < D; j++) { Args[i][j] = (Args[i][j] + Args[iMin][j]) / 2; } Values[i] = func(Args[i]); } for (int i = D; --i >= 0;) { ArgSum[i] = Ex.Range(D + 1).Sum(j => Args[j][i]); } } return(New.Array(D, i => Ex.Range(D1).Average(j => Args[j][i]))); }