Accord.Math.Optimization.NonlinearConjugateGradient.Optimize C# (CSharp) Method

Optimize() protected method

Implements the actual optimization algorithm. This method should try to minimize the objective function.
protected Optimize ( ) : bool
return bool
        protected override bool Optimize()
        {
            Evaluations = 0;
            Iterations = 0;

            int length = MaxIterations;
            double[] X = base.Solution;
            double M = 0.0;
            int iteration = 0;
            int Linessearch_isfailed = 0;


            // get first function eval
            double f1 = Function(X);

            // get first grad eval
            df1 = Gradient(X);

            Evaluations++;

            if (length < 0)
                iteration++;

            // this is the steepest search directions 
            for (int i = 0; i < df1.Length; i++)
                s[i] = -df1[i];

            // this is the slope of the line in negative direction
            double d1 = 0.0;
            for (int j = 0; j < s.Length; j++)
                d1 += -s[j] * s[j];

            // initial step is red(red/|s|+1)
            double z1 = Red / (1 - d1);

            double[] X0 = new double[X.Length];
            double[] DF0 = new double[X.Length];

            while (iteration < Math.Abs(length))
            {
                if (Token.IsCancellationRequested)
                    break;

                if (length > 0)
                    iteration++; // count epoch(iter)

                Iterations = iteration;

                // make copy of current values
                for (int j = 0; j < X0.Length; j++)
                    X0[j] = X[j];

                for (int j = 0; j < DF0.Length; j++)
                    DF0[j] = df1[j];

                double F0 = f1;

                // begin line search
                for (int j = 0; j < X.Length; j++)
                    X[j] += s[j] * z1;

                // evaluate cost - and gradient function with new params
                double f2 = Function(X);
                double[] df2 = Gradient(X);

                Evaluations++;

                if (length < 0)
                    iteration++;

                double d2 = 0;
                for (int i = 0; i < df2.Length; i++)
                    d2 += df2[i] * s[i];

                // initialize point 3 equal to point 1
                double f3 = f1, d3 = d1, z3 = -z1;

                if (length > 0)
                {
                    M = MAX;
                }
                else
                {
                    M = Math.Min(MAX, -length - iteration);
                }


                // initialize quantities
                double succes = 0.0;
                double limit = -1.0;

                while (true)
                {
                    //f2 = 0.70; 
                    while (((f2 > f1 + z1 * RHO * d1) || (d2 > -SIG * d1)) && (M > 0))
                    {
                        limit = z1; // tighten bracket

                        // values for cubic or quadratic fit
                        double A = 0.0d;
                        double B = 0.0d;
                        double z2 = 0.0d;

                        if (f2 > f1)
                        {
                            // quadratic fit 
                            z2 = z3 - ((0.5 * d3 * z3 * z3) / (d3 * z3 + f2 - f3));
                        }
                        else
                        {
                            // cubic fit
                            A = (6 * (f2 - f3)) / (z3 + (3 * (d2 + d3)));
                            B = (3 * (f3 - f2) - (z3 * ((d3 + 2) * d2)));

                            // numerical error possible - ok!
                            z2 = Math.Sqrt(((B * B) - (A * d2 * z3)) - B) / A;
                        }
                        if (Double.IsNaN(z2) || Double.IsInfinity(z2) || Double.IsNegativeInfinity(z2))
                        {
                            z2 = z3 / 2.0;
                        }

                        // don't accept too close to limit
                        z2 = Math.Max(Math.Min(z2, INT * z3), (1 - INT) * z3);

                        z1 = z1 + z2; // update this step 
                        for (int j = 0; j < X.Length; j++)
                            X[j] += s[j] * z2;

                        f2 = Function(X);
                        df2 = Gradient(X);
                        Evaluations++;

                        M = M - 1;

                        // count epochs 
                        if (length < 0)
                            iteration++;

                        // new slope
                        d2 = 0.0;
                        for (int i = 0; i < df2.Length; i++)
                            d2 += df2[i] * s[i];

                        // z3 is now relative to the location of z2
                        z3 = z3 - z2;

                    }

                    if (f2 > (f1 + z1 * RHO * d1) || d2 > (-SIG * d1))
                    {
                        // this is a failure
                        break;
                    }
                    else if (d2 > (SIG * d1))
                    {
                        succes = 1.0;
                        break; // success
                    }
                    else if (M == 0)
                    {
                        break; // failure
                    }

                    // Make cubic extrapolation 
                    var A1 = 6 * (f2 - f3) / z3 + 3 * (d2 + d3);
                    var B1 = 3 * (f3 - f2) - z3 * (d3 + 2 * d2);
                    var z21 = -d2 * z3 * z3 / (B1 + Math.Sqrt(B1 * B1 - A1 * d2 * z3 * z3));

                    if (z21 < 0)
                    {
                        z21 = z21 * -1;
                    }

                    // num prop or wrong sign  ? 
                    if (double.IsNaN(z21) || double.IsInfinity(z21) || z21 < 0)
                    {
                        if (limit < -0.5) // no upper limit
                        {
                            z21 = z1 * (EXT - 1);
                        }
                        else
                        {
                            z21 = (limit - z1) / 2;
                        }
                    }
                    else if (limit > -0.5 && (z21 + z1 > limit))
                    {
                        z21 = (limit - z1) / 2;
                    }

                    else if (limit < -0.5 && (z21 + z1 > z1 * EXT))
                    {
                        z21 = z1 * (EXT - 1.0);
                    }

                    else if (z21 < -z3 * INT)
                    {
                        z21 = -z3 * INT;
                    }

                    else if ((limit > -0.5) && (z21 < (limit - z1) * (1.0 - INT)))
                    {
                        z21 = (limit - z1) * (1.0 - INT);
                    }

                    // set point 3 equal to point 2
                    f3 = f2;
                    d3 = d2;
                    z3 = -z21;
                    z1 = z1 + z21;

                    // update current estimate
                    for (int j = 0; j < X.Length; j++)
                        X[j] += s[j] * z21;

                    // evaluate functions
                    df2 = Gradient(X);
                    f2 = Function(X);

                    M = M - 1;
                    iteration = iteration + (length < 0 ? 1 : 0); // count epochs

                    d2 = 0;
                    for (int i = 0; i < df2.Length; i++)
                        d2 += df2[i] * s[i];

                }// end of line search


                if (succes == 1.0) // if line searched succeded 
                {
                    f1 = f2;

                    // Polack- Ribiere direction
                    var ptemp1 = df2.Dot(df2) - df1.Dot(df2);
                    var ptemp2 = df1.Dot(df1);
                    var ptemp3 = ptemp1 / ptemp2;

                    for (int j = 0; j < s.Length; j++)
                        s[j] = s[j] * ptemp3 - df2[j];


                    // swap derivatives
                    var tmp = df1;
                    df1 = df2;
                    df2 = tmp;

                    // get slope
                    d2 = 0;
                    for (int i = 0; i < df1.Length; i++)
                        d2 += df1[i] * s[i];

                    // new slope must be negative 
                    if (d2 > 0)
                    {
                        // use steepest direction
                        for (int i = 0; i < s.Length; i++)
                            s[i] = -df1[i];

                        d2 = 0;
                        for (int i = 0; i < df1.Length; i++)
                            d2 -= s[i] * s[i];
                    }

                    // slope ration but max ratio
                    z1 = z1 * Math.Min(RATIO, (d1 / (d2 - 2.2251e-308)));
                    d1 = d2;
                    Linessearch_isfailed = 0; // this linesearch did not fail
                }
                else
                {
                    // restore point from before failed line search
                    f1 = F0;

                    for (int j = 0; j < X.Length; j++)
                        X[j] = X0[j];

                    for (int j = 0; j < df1.Length; j++)
                        df1[j] = DF0[j];

                    // line search twice in a row
                    if (Linessearch_isfailed == 1 || iteration > Math.Abs(length))
                    {
                        break; // or we ran out of time , so we give up
                    }

                    var tmp = df1;
                    df1 = df2;
                    df2 = tmp; // swap derivatives

                    for (int i = 0; i < df1.Length; i++)
                        s[i] = -df1[i];

                    d1 = 0;
                    for (int i = 0; i < s.Length; i++)
                        d1 -= s[i] * s[i];

                    z1 = 1d / (1d - d1);

                    Linessearch_isfailed = 1; // this line search failed
                }
            }

            Value = f1;
            return true;
        }
    }