private void init(int n) { this.n = n; this.stop = new GeneralConvergence(n); nelderMead = new NelderMead(nsmax, subspace_func); nelderMead.Convergence = this.stop; xstep = new double[n]; xstep0 = new double[n]; for (int i = 0; i < xstep0.Length; i++) { xstep0[i] = 1e-5; } p = new int[n]; dx = new double[n]; xprev = new double[n]; absdx = new double[n]; lb = new double[n]; for (int i = 0; i < lb.Length; i++) { lb[i] = Double.NegativeInfinity; } ub = new double[n]; for (int i = 0; i < ub.Length; i++) { ub[i] = Double.PositiveInfinity; } }
NelderMeadStatus sbplx_minimize() { var ret = NelderMeadStatus.Success; double[] x = Solution; Value = Function(x); this.stop.Evaluations++; if (NelderMead.nlopt_stop_forced(stop)) { return(NelderMeadStatus.ForcedStop); } if (Value < this.minf_max) { return(NelderMeadStatus.MinimumAllowedValueReached); } if (NelderMead.nlopt_stop_evals(stop)) { return(NelderMeadStatus.MaximumEvaluationsReached); } if (NelderMead.nlopt_stop_time(stop)) { return(NelderMeadStatus.MaximumTimeReached); } Array.Copy(xstep0, xstep, xstep.Length); while (true) { double normi = 0; double normdx = 0; int ns, nsubs = 0; int nevals = this.stop.Evaluations; double fdiff, fdiff_max = 0; Array.Copy(x, xprev, x.Length); double fprev = Value; // sort indices into the progress vector dx // by decreasing order of magnitude abs(dx) // for (int i = 0; i < p.Length; i++) { p[i] = i; } for (int j = 0; j < absdx.Length; j++) { absdx[j] = Math.Abs(dx[j]); } Array.Sort(p, absdx); // find the subspaces, and perform nelder-mead on each one for (int i = 0; i < absdx.Length; i++) { normdx += absdx[i]; // L1 norm } int last = 0; for (int i = 0; i + nsmin < n; i += ns) { last = i; // find subspace starting at index i double ns_goodness = -Double.MaxValue; double norm = normi; int nk = i + nsmax > n ? n : i + nsmax; // max k for this subspace for (int k = i; k < i + nsmin - 1; k++) { norm += absdx[p[k]]; } ns = nsmin; for (int k = i + nsmin - 1; k < nk; k++) { double goodness; norm += absdx[p[k]]; // remaining subspaces must be big enough to partition if (n - (k + 1) < nsmin) { continue; } // maximize figure of merit defined by Rowan thesis: // look for sudden drops in average |dx| if (k + 1 < n) { goodness = norm / (k + 1) - (normdx - norm) / (n - (k + 1)); } else { goodness = normdx / n; } if (goodness > ns_goodness) { ns_goodness = goodness; ns = (k + 1) - i; } } for (int k = i; k < i + ns; ++k) { normi += absdx[p[k]]; } // do nelder-mead on subspace of dimension ns starting w/i sindex = i; for (int k = i; k < i + ns; ++k) { nelderMead.Solution[k - i] = x[p[k]]; nelderMead.StepSize[k - i] = xstep[p[k]]; nelderMead.LowerBounds[k - i] = lb[p[k]]; nelderMead.UpperBounds[k - i] = ub[p[k]]; } nsubs++; nevals = this.stop.Evaluations; nelderMead.NumberOfVariables = ns; nelderMead.DiameterTolerance = psi; ret = nelderMead.Minimize(Value); fdiff = nelderMead.Difference; Value = nelderMead.Value; if (fdiff > fdiff_max) { fdiff_max = fdiff; } Trace.WriteLine(String.Format("{0} NM iterations for ({1},{2}) subspace", this.stop.Evaluations - nevals, sindex, ns)); for (int k = i; k < i + ns; k++) { x[p[k]] = nelderMead.Solution[k - i]; } if (ret == NelderMeadStatus.Failure) { return(NelderMeadStatus.SolutionToleranceReached); } if (ret != NelderMeadStatus.SolutionToleranceReached) { return(ret); } } // nelder-mead on last subspace ns = n - last; sindex = last; for (int i = last; i < n; i++) { nelderMead.Solution[i - sindex] = x[p[i]]; nelderMead.StepSize[i - sindex] = xstep[p[i]]; nelderMead.LowerBounds[i - sindex] = lb[p[i]]; nelderMead.UpperBounds[i - sindex] = ub[p[i]]; } nsubs++; nevals = this.stop.Evaluations; nelderMead.NumberOfVariables = ns; nelderMead.DiameterTolerance = psi; ret = nelderMead.Minimize(Value); fdiff = nelderMead.Difference; Value = nelderMead.Value; if (fdiff > fdiff_max) { fdiff_max = fdiff; } Trace.WriteLine(String.Format("sbplx: {0} NM iterations for ({1},{2}) subspace", this.stop.Evaluations - nevals, sindex, ns)); for (int i = sindex; i < p.Length; i++) { x[p[i]] = nelderMead.Solution[i - sindex]; } if (ret == NelderMeadStatus.Failure) { return(NelderMeadStatus.SolutionToleranceReached); } if (ret != NelderMeadStatus.SolutionToleranceReached) { return(ret); } // termination tests: if (NelderMead.nlopt_stop_ftol(stop, Value, Value + fdiff_max)) { return(NelderMeadStatus.FunctionToleranceReached); } if (NelderMead.nlopt_stop_xtol(stop, x, xprev, n)) { int j; // as explained in Rowan's thesis, it is important // to check |xstep| as well as |x-xprev|, since if // the step size is too large (in early iterations), // the inner Nelder-Mead may not make much progress // for (j = 0; j < xstep.Length; j++) { if (Math.Abs(xstep[j]) * psi > stop.AbsoluteParameterTolerance[j] && Math.Abs(xstep[j]) * psi > stop.RelativeParameterTolerance * Math.Abs(x[j])) { break; } } if (j == n) { return(NelderMeadStatus.SolutionToleranceReached); } } // compute change in optimal point for (int i = 0; i < x.Length; i++) { dx[i] = x[i] - xprev[i]; } // setting step sizes { double scale; if (nsubs == 1) { scale = psi; } else { double stepnorm = 0, dxnorm = 0; for (int i = 0; i < dx.Length; i++) { stepnorm += Math.Abs(xstep[i]); dxnorm += Math.Abs(dx[i]); } scale = dxnorm / stepnorm; if (scale < omega) { scale = omega; } if (scale > 1 / omega) { scale = 1 / omega; } } Trace.WriteLine("sbplx: stepsize scale factor = " + scale); for (int i = 0; i < xstep.Length; i++) { xstep[i] = (dx[i] == 0) ? -(xstep[i] * scale) : Special.Sign(xstep[i] * scale, dx[i]); } } } }