Esempio n. 1
0
        protected DoubleRefObject AddParameter(double value)
        {
            var result = new DoubleRefObject(value);

            Parameters.Add(result);
            return(result);
        }
        public static int Solve(List <DoubleRefObject> originalData, ConstraintContainer cons, double isFine)
        {
            var xLength = originalData.Count;

            //Save the original parameters for later.
            var origSolution1 = new List <DoubleRefObject>();

            foreach (var element in originalData)
            {
                var auxVal = new DoubleRefObject(element.Value);
                origSolution1.Add(auxVal);
            }

            var convergence = isFine > 0 ? XconvergenceFine : XconvergenceRough;
            //integer to keep track of how many times calc is called
            var ftimes = 0;
            //Calculate Function at the starting point:
            var f0 = cons.Calc();

            if (f0 < SmallF)
            {
                return(0);
            }

            ftimes++;
            //Calculate the gradient at the starting point:

            //Calculate the gradient
            //gradF=x;
            var    grad = BuildSizedList <double>(xLength); //The gradient vector (1xn)
            double first, second, temper;                   //The norm of the gradient vector
            double f1;
            double norm = 0;
            var    pert = f0 * PertMag;

            for (var j = 0; j < xLength; j++)
            {
                temper = originalData[j].Value;
                originalData[j].Value = temper - pert;
                first = cons.Calc();
                originalData[j].Value = temper + pert;
                second  = cons.Calc();
                grad[j] = .5 * (second - first) / pert;
                ftimes++;

                originalData[j].Value = temper;
                norm = norm + (grad[j] * grad[j]);
            }
            norm = Math.Sqrt(norm);
            //Estimate the norm of N

            //Initialize N and calculate s
            var s = BuildSizedList <double>(xLength); //The current search direction
            var n = BuildSizedList <List <double> >(xLength);

            for (var i = 0; i < xLength; i++)
            {
                n[i] = BuildSizedList <double>(xLength);
            }
            for (var i = 0; i < xLength; i++)
            {
                for (var j = 0; j < xLength; j++)
                {
                    if (i == j)
                    {
                        //N[i][j]=norm; //Calculate a scaled identity matrix as a Hessian inverse estimate
                        //N[i][j]=grad[i]/(norm+.001);
                        n[i][j] = 1;
                        s[i]    = -grad[i]; //Calculate the initial search vector
                    }
                    else
                    {
                        n[i][j] = 0;
                    }
                }
            }
            var    fnew  = f0 + 1;
            double alpha = 1;                        //Initial search vector multiplier

            var xold = new List <DoubleRefObject>(); //Storage for the previous design variables

            foreach (var element in originalData)
            {
                var auxValue = new DoubleRefObject(element.Value);
                xold.Add(auxValue);
            }

            ///////////////////////////////////////////////////////
            //  Start of line search
            ///////////////////////////////////////////////////////

            //Make the initial position alpha1
            double alpha1 = 0;

            f1 = f0;

            //Take a step of alpha=1 as alpha2
            double alpha2 = 1;

            for (int i = 0; i < xLength; i++)
            {
                originalData[i].Value = xold[i].Value + alpha2 * s[i];//calculate the new x
            }
            var f2 = cons.Calc();

            ftimes++;

            //Take a step of alpha 3 that is 2*alpha2
            var alpha3 = alpha * 2;

            for (var i = 0; i < xLength; i++)
            {
                originalData[i].Value = xold[i].Value + alpha3 * s[i];//calculate the new x
            }
            var f3 = cons.Calc();

            ftimes++;

            //Now reduce or lengthen alpha2 and alpha3 until the minimum is
            //Bracketed by the triplet f1>f2<f3
            while (f2 > f1 || f2 > f3)
            {
                if (f2 > f1)
                {
                    //If f2 is greater than f1 then we shorten alpha2 and alpha3 closer to f1
                    //Effectively both are shortened by a factor of two.
                    alpha3 = alpha2;
                    f3     = f2;
                    alpha2 = alpha2 / 2;
                    for (var i = 0; i < xLength; i++)
                    {
                        originalData[i].Value = xold[i].Value + alpha2 * s[i];//calculate the new x
                    }
                    f2 = cons.Calc();
                    ftimes++;
                }

                else if (f2 > f3)
                {
                    //If f2 is greater than f3 then we length alpah2 and alpha3 closer to f1
                    //Effectively both are lengthened by a factor of two.
                    alpha2 = alpha3;
                    f2     = f3;
                    alpha3 = alpha3 * 2;
                    for (var i = 0; i < xLength; i++)
                    {
                        originalData[i].Value = xold[i].Value + alpha3 * s[i];//calculate the new x
                    }
                    f3 = cons.Calc();
                    ftimes++;
                }
            }
            // get the alpha for the minimum f of the quadratic approximation
            var alphaStar = alpha2 + ((alpha2 - alpha1) * (f1 - f3)) / (3 * (f1 - 2 * f2 + f3));

            //Guarantee that the new alphaStar is within the bracket
            if (alphaStar > alpha3 || alphaStar < alpha1)
            {
                alphaStar = alpha2;
            }

            // Set the values to alphaStar
            for (var i = 0; i < xLength; i++)
            {
                originalData[i].Value = xold[i].Value + alphaStar * s[i];//calculate the new x
            }
            fnew = cons.Calc();
            ftimes++;
            var fold = fnew;

            /////////////////////////////////////
            // end of line search
            /////////////////////////////////////



            var deltaX              = BuildSizedList <double>(xLength);
            var gradnew             = BuildSizedList <double>(xLength);
            var gamma               = BuildSizedList <double>(xLength);
            var gammatDotN          = BuildSizedList <double>(xLength);
            var firstSecond         = BuildSizedList <List <double> >(xLength);
            var deltaXDotGammatDotN = BuildSizedList <List <double> >(xLength);;
            var gammatDotDeltaXt    = BuildSizedList <List <double> >(xLength);
            var nDotGammaDotDeltaXt = BuildSizedList <List <double> >(xLength);

            for (var i = 0; i < xLength; i++)
            {
                firstSecond[i]         = BuildSizedList <double>(xLength);
                deltaXDotGammatDotN[i] = BuildSizedList <double>(xLength);
                gammatDotDeltaXt[i]    = BuildSizedList <double>(xLength);
                nDotGammaDotDeltaXt[i] = BuildSizedList <double>(xLength);
            }
            double deltaXnorm = 1;

            var iterations = 1;

            //Calculate deltaX
            for (var i = 0; i < xLength; i++)
            {
                deltaX[i] = originalData[i].Value - xold[i].Value;//Calculate the difference in x for the Hessian update
            }
            double maxIterNumber = MaxIterations * xLength;

            while (deltaXnorm > convergence && fnew > SmallF && iterations < maxIterNumber)
            {
                /////////////////////////////////////////////////////////////////////
                //Start of main loop!!!!
                /////////////////////////////////////////////////////////////////////
                double bottom          = 0;
                double deltaXtDotGamma = 0;
                pert = fnew * PertMag;
                if (pert < PertMin)
                {
                    pert = PertMin;
                }
                for (var i = 0; i < xLength; i++)
                {
                    //Calculate the new gradient vector
                    temper = originalData[i].Value;
                    originalData[i].Value = temper - pert;
                    first = cons.Calc();
                    originalData[i].Value = temper + pert;
                    second     = cons.Calc();
                    gradnew[i] = .5 * (second - first) / pert;
                    ftimes++;
                    originalData[i].Value = temper;
                    //Calculate the change in the gradient
                    gamma[i] = gradnew[i] - grad[i];
                    bottom  += deltaX[i] * gamma[i];

                    deltaXtDotGamma += deltaX[i] * gamma[i];
                }

                //make sure that bottom is never 0
                if (bottom == 0)
                {
                    bottom = 1e-9;
                }

                //calculate all (1xn).(nxn)

                for (var i = 0; i < xLength; i++)
                {
                    gammatDotN[i] = 0;
                    for (var j = 0; j < xLength; j++)
                    {
                        gammatDotN[i] += gamma[j] * n[i][j]; //This is gammatDotN transpose
                    }
                }
                //calculate all (1xn).(nx1)

                double gammatDotNDotGamma = 0;
                for (var i = 0; i < xLength; i++)
                {
                    gammatDotNDotGamma += gammatDotN[i] * gamma[i];
                }

                //Calculate the first term

                var firstTerm = 1 + gammatDotNDotGamma / bottom;

                //Calculate all (nx1).(1xn) matrices
                for (var i = 0; i < xLength; i++)
                {
                    for (var j = 0; j < xLength; j++)
                    {
                        firstSecond[i][j]         = ((deltaX[j] * deltaX[i]) / bottom) * firstTerm;
                        deltaXDotGammatDotN[i][j] = deltaX[i] * gammatDotN[j];
                        gammatDotDeltaXt[i][j]    = gamma[i] * deltaX[j];
                    }
                }

                //Calculate all (nxn).(nxn) matrices

                for (var i = 0; i < xLength; i++)
                {
                    for (var j = 0; j < xLength; j++)
                    {
                        nDotGammaDotDeltaXt[i][j] = 0;
                        for (var k = 0; k < xLength; k++)
                        {
                            nDotGammaDotDeltaXt[i][j] += n[i][k] * gammatDotDeltaXt[k][j];
                        }
                    }
                }
                //Now calculate the BFGS update on N
                //cout<<"N:"<<endl;
                for (var i = 0; i < xLength; i++)
                {
                    for (var j = 0; j < xLength; j++)
                    {
                        n[i][j] = n[i][j] + firstSecond[i][j] -
                                  (deltaXDotGammatDotN[i][j] + nDotGammaDotDeltaXt[i][j]) / bottom;
                    }
                }

                //Calculate s
                for (var i = 0; i < xLength; i++)
                {
                    s[i] = 0;
                    for (var j = 0; j < xLength; j++)
                    {
                        s[i] += -n[i][j] * gradnew[j];
                    }
                }

                alpha = 1; //Initial search vector multiplier


                //copy newest values to the xold
                xold.Clear();
                foreach (var element in originalData)
                {
                    var auxValue = new DoubleRefObject(element.Value);
                    xold.Add(auxValue);//Copy last values to xold
                }

                ///////////////////////////////////////////////////////
                //  Start of line search
                ///////////////////////////////////////////////////////

                //Make the initial position alpha1
                alpha1 = 0;
                f1     = fnew;

                //Take a step of alpha=1 as alpha2
                alpha2 = 1;
                for (var i = 0; i < xLength; i++)
                {
                    originalData[i].Value = xold[i].Value + alpha2 * s[i];//calculate the new x
                }
                f2 = cons.Calc();
                ftimes++;

                //Take a step of alpha 3 that is 2*alpha2
                alpha3 = alpha2 * 2;
                for (int i = 0; i < xLength; i++)
                {
                    originalData[i].Value = xold[i].Value + alpha3 * s[i];//calculate the new x
                }
                f3 = cons.Calc();
                ftimes++;

                //Now reduce or lengthen alpha2 and alpha3 until the minimum is
                //Bracketed by the triplet f1>f2<f3
                var steps = 0;
                while (f2 > f1 || f2 > f3)
                {
                    if (f2 > f1)
                    {
                        //If f2 is greater than f1 then we shorten alpha2 and alpha3 closer to f1
                        //Effectively both are shortened by a factor of two.
                        alpha3 = alpha2;
                        f3     = f2;
                        alpha2 = alpha2 / 2;
                        for (int i = 0; i < xLength; i++)
                        {
                            originalData[i].Value = xold[i].Value + alpha2 * s[i];//calculate the new x
                        }
                        f2 = cons.Calc();
                        ftimes++;
                    }

                    else if (f2 > f3)
                    {
                        //If f2 is greater than f3 then we length alpah2 and alpha3 closer to f1
                        //Effectively both are lengthened by a factor of two.
                        alpha2 = alpha3;
                        f2     = f3;
                        alpha3 = alpha3 * 2;
                        for (int i = 0; i < xLength; i++)
                        {
                            originalData[i].Value = xold[i].Value + alpha3 * s[i];//calculate the new x
                        }
                        f3 = cons.Calc();
                        ftimes++;
                    }
                    steps = steps + 1;
                }

                // get the alpha for the minimum f of the quadratic approximation
                alphaStar = alpha2 + ((alpha2 - alpha1) * (f1 - f3)) / (3 * (f1 - 2 * f2 + f3));


                //Guarantee that the new alphaStar is within the bracket
                if (alphaStar >= alpha3 || alphaStar <= alpha1)
                {
                    alphaStar = alpha2;
                }

                // Set the values to alphaStar
                for (var i = 0; i < xLength; i++)
                {
                    originalData[i].Value = xold[i].Value + alphaStar * s[i];//calculate the new x
                }
                fnew = cons.Calc();
                ftimes++;


                /////////////////////////////////////
                // end of line search
                ////////////////////////////////////

                deltaXnorm = 0;
                for (int i = 0; i < xLength; i++)
                {
                    deltaX[i]   = originalData[i].Value - xold[i].Value;//Calculate the difference in x for the hessian update
                    deltaXnorm += deltaX[i] * deltaX[i];
                    grad[i]     = gradnew[i];
                }
                deltaXnorm = Math.Sqrt(deltaXnorm);
                iterations++;
                /////////////////////////////////////////////////////////////
                // End of Main loop
                /////////////////////////////////////////////////////////////
            }

            // End of function
            double validSolution;

            if (isFine == 1)
            {
                validSolution = ValidSolutionFine;
            }
            else
            {
                validSolution = ValidSoltuionRough;
            }
            if (fnew < validSolution)
            {
                return(0);
            }
            //Replace the bad numbers with the last result
            for (var i = 0; i < xLength; i++)
            {
                originalData[i] = origSolution1[i];
            }
            return(1);
        }