private void init(int n) { this.n = n; Convergence = new GeneralConvergence(n); nelderMead = new NelderMead(nsmax, subspace_func); nelderMead.Convergence = Convergence; xstep = new double[n]; StepSize = new double[n]; for (var i = 0; i < StepSize.Length; i++) { StepSize[i] = 1e-5; } p = new int[n]; dx = new double[n]; xprev = new double[n]; absdx = new double[n]; LowerBounds = new double[n]; for (var i = 0; i < LowerBounds.Length; i++) { LowerBounds[i] = double.NegativeInfinity; } UpperBounds = new double[n]; for (var i = 0; i < UpperBounds.Length; i++) { UpperBounds[i] = double.PositiveInfinity; } }
private NelderMeadStatus sbplx_minimize() { var ret = NelderMeadStatus.Success; var x = Solution; Value = Function(x); Convergence.Evaluations++; if (NelderMead.nlopt_stop_forced(Convergence)) { return(NelderMeadStatus.ForcedStop); } if (Value < MaximumValue) { return(NelderMeadStatus.MinimumAllowedValueReached); } if (NelderMead.nlopt_stop_evals(Convergence)) { return(NelderMeadStatus.MaximumEvaluationsReached); } if (NelderMead.nlopt_stop_time(Convergence)) { return(NelderMeadStatus.MaximumTimeReached); } Array.Copy(StepSize, xstep, xstep.Length); while (true) { double normi = 0; double normdx = 0; int ns, nsubs = 0; var nevals = Convergence.Evaluations; double fdiff, fdiff_max = 0; Array.Copy(x, xprev, x.Length); var fprev = Value; // sort indices into the progress vector dx // by decreasing order of magnitude abs(dx) // for (var i = 0; i < p.Length; i++) { p[i] = i; } for (var 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 (var i = 0; i < absdx.Length; i++) { normdx += absdx[i]; // L1 norm } var last = 0; for (var i = 0; i + nsmin < n; i += ns) { last = i; // find subspace starting at index i var ns_goodness = -double.MaxValue; var norm = normi; var nk = i + nsmax > n ? n : i + nsmax; // max k for this subspace for (var k = i; k < i + nsmin - 1; k++) { norm += absdx[p[k]]; } ns = nsmin; for (var 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 (var k = i; k < i + ns; ++k) { normi += absdx[p[k]]; } // do nelder-mead on subspace of dimension ns starting w/i sindex = i; for (var k = i; k < i + ns; ++k) { nelderMead.Solution[k - i] = x[p[k]]; nelderMead.StepSize[k - i] = xstep[p[k]]; nelderMead.LowerBounds[k - i] = LowerBounds[p[k]]; nelderMead.UpperBounds[k - i] = UpperBounds[p[k]]; } nsubs++; nevals = Convergence.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", Convergence.Evaluations - nevals, sindex, ns)); for (var 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 (var i = last; i < n; i++) { nelderMead.Solution[i - sindex] = x[p[i]]; nelderMead.StepSize[i - sindex] = xstep[p[i]]; nelderMead.LowerBounds[i - sindex] = LowerBounds[p[i]]; nelderMead.UpperBounds[i - sindex] = UpperBounds[p[i]]; } nsubs++; nevals = Convergence.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", Convergence.Evaluations - nevals, sindex, ns)); for (var 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(Convergence, Value, Value + fdiff_max)) { return(NelderMeadStatus.FunctionToleranceReached); } if (NelderMead.nlopt_stop_xtol(Convergence, 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 > Convergence.AbsoluteParameterTolerance[j] && Math.Abs(xstep[j]) * psi > Convergence.RelativeParameterTolerance * Math.Abs(x[j])) { break; } } if (j == n) { return(NelderMeadStatus.SolutionToleranceReached); } } // compute change in optimal point for (var 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 (var 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 (var i = 0; i < xstep.Length; i++) { xstep[i] = dx[i] == 0 ? -(xstep[i] * scale) : Special.Sign(xstep[i] * scale, dx[i]); } } } }