예제 #1
0
        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;
            }
        }
예제 #2
0
        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]);
                    }
                }
            }
        }