// Nelder-Mead algorithm public Object Solve(Func <Object> f, string[] vars, string pos) { Kerbulator.DebugLine("Entering solver"); int N = vars.Length; if (N == 0) { return (Object) new Object[] {} } ; // Stopping criteria int maxiter = this.maxiter == 0 ? 200 * N : this.maxiter; int maxfev = this.maxfev == 0 ? 200 * N : this.maxfev; int iterations = 1; int fcalls = 1; // Some parameters double rho = 1.0; double chi = 2.0; double psi = 0.5; double sigma = 0.5; // Variables that keep track of the current simplex double[][] sim = new double[N + 1][]; double[] fsim = new double[N + 1]; // Initialize best vertex of current simplex sim[0] = new double[N]; for (int i = 0; i < N; i++) { if (func.IsLocalDefined(vars[i])) { Object o = func.GetVar(vars[i], pos); if (o.GetType() != typeof(double)) { throw new Exception(pos + "solver cannot optimize variables of type list"); } sim[0][i] = (double)o; } else { sim[0][i] = 0.0; } } fsim[0] = CallFunc(f, vars, sim[0], pos); fcalls++; // Initialize other vertices of current simplex double nonzdelt = 1.05; double zdelt = 0.00025; for (int k = 0; k < N; k++) { double[] y = (double[])sim[0].Clone(); if (y[k] == 0.0) { y[k] = zdelt; } else { y[k] = sim[0][k] * nonzdelt; } sim[k + 1] = y; fsim[k + 1] = CallFunc(f, vars, y, pos); fcalls++; } // Sort vertices SortVertices(sim, fsim); double[] xbar = new double[N]; double[] xr = new double[N]; double[] xe = new double[N]; double[] xc = new double[N]; double[] xcc = new double[N]; while (fcalls < maxfev && iterations < maxiter) { Kerbulator.DebugLine("Iteration " + iterations); PrintVertices(sim, fsim); // Test stopping criterium double xmax = 0; double fmax = 0; for (int i = 1; i < N + 1; i++) { for (int j = 1; j < N; j++) { double xdiff = Math.Abs(sim[i][j] - sim[0][j]); if (xdiff > xmax) { xmax = xdiff; } } double fdiff = Math.Abs(fsim[i] - fsim[0]); if (fdiff > fmax) { fmax = fdiff; } } if (xmax <= xtol && fmax < ftol) { Kerbulator.DebugLine("Stopping criterium reached. (" + xmax + ", " + fmax + ")"); break; } else { Kerbulator.DebugLine("Continue. (" + xmax + ", " + fmax + ")"); } for (int i = 0; i < N; i++) { xbar[i] = 0.0; for (int j = 0; j < N; j++) { xbar[i] += sim[j][i]; } xbar[i] /= N; } for (int i = 0; i < N; i++) { xr[i] = (1 + rho) * xbar[i] - rho * sim[sim.Length - 1][i]; } double fxr = CallFunc(f, vars, xr, pos); fcalls++; bool doshrink = false; if (fxr < fsim[0]) { for (int i = 0; i < N; i++) { xe[i] = (1 + rho * chi) * xbar[i] - rho * chi * sim[sim.Length - 1][i]; } double fxe = CallFunc(f, vars, xe, pos); fcalls++; if (fxe < fxr) { for (int i = 0; i < N; i++) { sim[sim.Length - 1][i] = xe[i]; } fsim[fsim.Length - 1] = fxe; } else { for (int i = 0; i < N; i++) { sim[sim.Length - 1][i] = xr[i]; } fsim[fsim.Length - 1] = fxr; } } else // fsim[0] <= fxr { if (fxr < fsim[fsim.Length - 2]) { for (int i = 0; i < N; i++) { sim[sim.Length - 1][i] = xr[i]; } fsim[fsim.Length - 1] = fxr; } else // fxr >= fsim[-2] // Perform contraction { if (fxr < fsim[fsim.Length - 1]) { for (int i = 0; i < N; i++) { xc[i] = (1 + psi * rho) * xbar[i] - psi * rho * sim[sim.Length - 1][i]; } double fxc = CallFunc(f, vars, xc, pos); fcalls++; if (fxc <= fxr) { for (int i = 0; i < N; i++) { sim[sim.Length - 1][i] = xc[i]; } fsim[fsim.Length - 1] = fxc; } else { doshrink = true; } } else { // Perform an inside contraction for (int i = 0; i < N; i++) { xcc[i] = (1 - psi) * xbar[i] + psi * sim[sim.Length - 1][i]; } double fxcc = CallFunc(f, vars, xcc, pos); fcalls++; if (fxcc < fsim[fsim.Length - 1]) { for (int i = 0; i < N; i++) { sim[sim.Length - 1][i] = xcc[i]; } fsim[fsim.Length - 1] = fxcc; } else { doshrink = true; } } if (doshrink) { for (int j = 1; j < N + 1; j++) { for (int i = 0; i < N; i++) { sim[j][i] = sim[0][i] + sigma * (sim[j][i] - sim[0][i]); } fsim[j] = CallFunc(f, vars, sim[j], pos); fcalls++; } } } } SortVertices(sim, fsim); iterations++; } Kerbulator.DebugLine("Leaving solver"); // Copy the locals of interest to the output if (vars.Length == 1) { return(func.GetVar(vars[0], pos)); } else { List <Object> outs = new List <Object>(vars.Length); foreach (string id in vars) { outs.Add(func.GetVar(id, pos)); } return((Object)outs.ToArray()); } }