Exemplo n.º 1
0
        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;
            }
        }
Exemplo n.º 2
0
        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]);
                    }
                }
            }
        }