Exemplo n.º 1
0
Arquivo: BFGS.cs Projeto: 0xCM/arrows
        /// <summary>
        /// Run an unconstrained minimization using BFGS
        /// </summary>
        /// <param name="x0">Starting step</param>
        /// <param name="normOfFirstStep">Norm of first step</param>
        /// <param name="func">Multivariate function and derivative evaluator</param>
        /// <returns>The local minimum point</returns>
        public virtual Vector Run(Vector x0, double normOfFirstStep, FunctionEval func)
        {
            dimension = x0.Count;
            currentX  = Vector.Copy(x0);

            if (func == null)
            {
                throw new ArgumentException("Null function");
            }

            cancel = false;

            // Initialize all the fields needed for optimisation
            feval        = new FunctionEval(func);
            searchDir    = Vector.Zero(dimension);
            currentDeriv = Vector.Zero(dimension);

            // Following vectors are the components of the
            // inverse Hessian update
            Vector S                 = Vector.Zero(dimension);
            Vector Y                 = Vector.Zero(dimension);
            Vector minusRhoS         = Vector.Zero(dimension);
            Matrix EyeMinusSYt       = new Matrix(dimension, dimension);
            Vector prevDeriv         = Vector.Zero(dimension);
            PositiveDefiniteMatrix H = new PositiveDefiniteMatrix(dimension, dimension);

            H.SetToIdentity();
            Matrix HWork = new Matrix(dimension, dimension);

            // Get the derivatives
            currentObj = feval(currentX, ref currentDeriv);
            double prevObj = currentObj;
            double rho;
            double step             = 0.0;
            double step0            = initialStep;
            double convergenceCheck = double.MaxValue;
            double invDim           = 1.0 / dimension;

            iter = 0;
            while (convergenceCheck > this.epsilon && !cancel)
            {
                prevDeriv.SetTo(currentDeriv);

                // Compute search direction
                searchDir.SetToProduct(H, currentDeriv);

                // Negate
                for (int i = 0; i < dimension; i++)
                {
                    searchDir[i] = -searchDir[i];
                }

                if (iter == 0)
                {
                    double sdNorm = System.Math.Sqrt(searchDir.Inner(searchDir));
                    double sdMult = normOfFirstStep / sdNorm;
                    searchDir.SetToProduct(searchDir, sdMult);
                    for (int i = 0; i < dimension; i++)
                    {
                        H[i, i] = sdMult;
                    }
                }

                //------------------------------------------------------
                // Line search enforces strong Wolfe conditions
                // so curvature condition is guaranteed
                //------------------------------------------------------
                step = TryLineSearch(step0, stepMax, currentDeriv.Inner(searchDir));

                // Get the delta between the old and new point
                S.SetToProduct(searchDir, step);

                // Update the current point
                currentX.SetToSum(currentX, S);

                // Calculate the objective and the derivative at the new point
                //double objVal = feval(currentX, ref currentDeriv);

                // If the step is 0, break now, once we have re-evaluated the function and derivs.
                if (step == 0.0)
                {
                    break;
                }

                // Difference of derivs
                Y.SetToDifference(currentDeriv, prevDeriv);

                // BFGS update
                rho = 1.0 / (S.Inner(Y));
                if (iter == 0)
                {
                    // Modify the Hessian to yTs/yTy times Identity
                    double beta = S.Inner(S) * rho;
                    for (int i = 0; i < dimension; i++)
                    {
                        H[i, i] = beta;
                    }
                }


                EyeMinusSYt.SetToIdentity();
                EyeMinusSYt.SetToSumWithOuter(EyeMinusSYt, -rho, S, Y);
                HWork.SetToProduct(EyeMinusSYt, H);
                H.SetToProduct(HWork, EyeMinusSYt.Transpose());
                H.SetToSumWithOuter(H, rho, S, S);

                switch (convergenceCriteria)
                {
                case ConvergenceCriteria.Gradient:
                    convergenceCheck = System.Math.Sqrt(invDim * currentDeriv.Inner(currentDeriv));
                    break;

                case ConvergenceCriteria.Objective:
                    convergenceCheck = System.Math.Abs(prevObj - currentObj) / System.Math.Max(1, System.Math.Max(prevObj, currentObj));
                    break;
                }
                prevObj = currentObj;
                // Let anyone who's interested know that we have completed an iteration
                RaiseIterationEvent(iter, currentObj, convergenceCheck);

                if (++iter > maxIterations)
                {
                    break;
                }
            }
            return(currentX);
        }