private static double LineSearch(ConstraintRefContainer cons, Vector xold, Vector s, double f1, double alpha2, double alpha1)
        {
            //  //Take a step of alpha=1 as alpha2
            var originalData = xold + alpha2 * s;
            var f2           = cons.Calc(originalData);

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

            originalData = xold + alpha3 * s;
            var f3 = cons.Calc(originalData);

            //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;

                    originalData = xold + alpha2 * s;
                    f2           = cons.Calc(originalData);
                }

                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;

                    originalData = xold + alpha3 * s;
                    f3           = cons.Calc(originalData);
                }
            }

            // get the alpha for the minimum f of the quadratic approximation
            var denominator = f1 - 2 * f2 + f3;

            denominator = denominator < 1e-13 ? 1e-13 : denominator;
            var alphaStar = alpha2 + ((alpha2 - alpha1) * (f1 - f3)) / (3 * denominator);

            //Guarantee that the new alphaStar is within the bracket
            if (alphaStar > alpha3 || alphaStar < alpha1)
            {
                alphaStar = alpha2;
            }
            return(alphaStar);
        }
        public int SolveRef(ref Vector originalData, int freeValuesCount, ConstraintRefContainer cons, double isFine)
        {
            var xLength = originalData.Count;

            //Save the original parameters for later.
            var origSolution1 = new Vector(originalData);

            var convergence = isFine > 0.1 ? XconvergenceFine : XconvergenceRough;
            //Calculate Function at the starting point:
            var f0 = cons.Calc(originalData);

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

            //Calculate the gradient at the starting point:

            var grad = new Vector(xLength); //The gradient vector (1xn)

            for (var j = 0; j < freeValuesCount; j++)
            {
                grad[j] = cons.Grad(originalData, j);
            }

            //Initialize N and calculate s
            var n = Matrix.Identity(xLength, xLength);

            var s    = -grad;
            var fnew = f0 + 1;

            var xold = new Vector(originalData); //Storage for the previous design variables

            /////////////////////////////////////////////////////////
            ////  Calculate first step
            /////////////////////////////////////////////////////////

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

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

            double f1        = fnew;
            var    alphaStar = LineSearch(cons, xold, s, f1, alpha2, alpha1);

            originalData = xold + alphaStar * s;

            fnew = cons.Calc(originalData);

            /////////////////////////////////////
            // end of first step
            /////////////////////////////////////

            var deltaX  = new Vector(xLength);
            var gradnew = new Vector(xLength);

            double deltaXnorm = 1;

            var iterations = 1;

            deltaX = originalData - xold;
            while (deltaXnorm > convergence && fnew > SmallF && iterations < MaxIterations * xold.Count)
            {
                n = CalculateUpdate(freeValuesCount, xLength, originalData, cons, n, grad, deltaX);
                ////// line search + next steps /////
                for (var i = 0; i < freeValuesCount; i++)
                {
                    gradnew[i] = cons.Grad(originalData, i);
                }
                s = n * (-gradnew);

                //copy newest values to the xold
                xold      = originalData;
                f1        = fnew;
                alphaStar = LineSearch(cons, xold, s, f1, alpha2, alpha1);

                originalData = xold + alphaStar * s;
                fnew         = cons.Calc(originalData);

                deltaX     = originalData - xold;
                grad       = new Vector(gradnew);
                deltaXnorm = deltaX.Norm();
                iterations++;
            }

            // End of function
            double validSolution = isFine < 0.1 ? ValidSolutionFine : ValidSoltuionRough;

            if (fnew < validSolution)
            {
                return(0);
            }

            originalData = origSolution1;
            return(1);
        }