Exemplo n.º 1
0
    public static vector qnewton(
        Func <vector, double> f,        //
        vector xstart,
        double eps,
        ref int steps,
        matrix B = null       // the inverse of the hesse matrix
        )
    {
        steps += 1;
        int n = xstart.size;

        // Initiate the B matrix if it isn't given:
        if (B == null)
        {
            B = new matrix(n, n);
            B.set_identity();
        }

        // 1: calculate grad_f:
        vector grad_f = gradient(f, xstart);
        // 2: Calculate delta_x:
        vector delta_x = -B * grad_f;

        // 3: Do the backtracking to find the actual step s:

        double alpha     = 1e-4;
        int    invlambda = 1;

        while ((invlambda <= 64) && (f(xstart + delta_x / invlambda) >= f(xstart) + alpha * (delta_x / invlambda).dot(grad_f)))
        {
            invlambda *= 2;
        }
        vector s = delta_x / invlambda;

        // If lambda becomes too small, reset B:
        if (invlambda > 64)
        {
            B.set_identity();
        }

        // 4: Calculate the error and compare with the accuracy goal:
        // Notes: err = Abs(grad_phi):

        // first the gradient of the next step:
        vector grad_f_s = gradient(f, xstart + s);

        double err = grad_f_s.simpleNorm();

        if (steps > 999)
        {
            Error.Write($"qnewton: Maximum number of steps reached ({steps} steps), terminating minimization.\n");
            return(xstart + s);
        }
        else if (err < eps)
        {
            return(xstart + s);
        }
        else
        {
            // 5: If the step was not final,
            // Do SR1 update and do another step:
            // Calculate y
            vector y = grad_f_s - grad_f;
            // Calculate u:
            vector u = s - B * y;

            if (Abs(u.dot(y)) < 1e-6)
            {
                return(qnewton(f, xstart + s, eps, ref steps, B));
            }
            else
            {
                // Calculate delta_B:
                matrix delta_B = u.outer(u) / (u.dot(y));
                // Do another step:
                return(qnewton(f, xstart + s, eps, ref steps, B + delta_B));
            }
        }
    }
Exemplo n.º 2
0
    public static vector qnewton(
        Func <vector, double> f,        //
        vector xstart,
        double eps,
        ref int steps,
        matrix B = null       // the inverse of the hesse matrix
        )
    {
        steps += 1;

        Error.Write("\nOne call to qnewton!\n");
        Error.Write($"Used xstart: {xstart}!\n");
        double dx = 1e-8;
        int    n  = xstart.size;

        // Initiate the B matrix if it isn't given:
        if (B == null)
        {
            B = new matrix(n, n);
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (i == j)
                    {
                        B[i, j] = 1;
                    }
                    else
                    {
                        B[i, j] = 0;
                    }
                }
            }
        }

        // 1: calculate grad_f:
        vector grad_f = new vector(n);

        for (int i = 0; i < n; i++)
        {
            vector x = xstart.copy();
            x[i]     += dx;
            grad_f[i] = (f(x) - f(xstart)) / dx;
        }
        Error.Write($"Found grad_f: {grad_f}\n");

        // 2: Calculate delta_x:
        vector delta_x = -B * grad_f;

        Error.Write($"Found delta_x: {delta_x}\n");

        // 3: Do the backtracking to find the actual step s:

        double alpha     = 1e-4;
        int    invlambda = 1;

        // TODO: This seems okay, but im not sure.
        while ((invlambda <= 64) && (f(xstart + delta_x / invlambda) >= f(xstart) + alpha * (delta_x / invlambda).dot(grad_f)))
        {
            invlambda *= 2;
        }
        vector s = delta_x.copy() / invlambda;

        // If lambda becomes too small, reset B:
        if (invlambda > 64)
        {
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (i == j)
                    {
                        B[i, j] = 1;
                    }
                    else
                    {
                        B[i, j] = 0;
                    }
                }
            }
        }


        // 4: Calculate the error and compare with the accuracy goal:
        // Notes: err = Abs(grad_phi):

        // first the gradient of the next step:
        Error.Write($"xstart + s: {xstart+s}\n");
        Error.Write($"dx:         {dx}\n");
        vector grad_f_s = new vector(n);

        for (int i = 0; i < n; i++)
        {
            Error.Write("Is this loop running?\n");
            vector x = xstart.copy() + s.copy();
            x[i] += dx;
            Error.Write($"{1}'th entry: f(x) = {f(x)}, f(xstart+s) = {f(xstart + s)} \n");
            grad_f_s[i] = (f(x) - f(xstart + s)) / dx;
        }
        Error.Write($"Found grad_f_s: {grad_f_s}\n");

        double err = grad_f_s.simpleNorm();

        Error.Write($"Found error: {err}\n");
        Error.Write($"Found s: {s}\n");

        /*
         * Error.Write("ABORTING FOR DEBUGGNING!");
         * return xstart+s;
         */

        if (steps > 999)
        {
            Error.Write($"Maximum steps reached ({steps} steps), terminating minization\n");
            return(xstart + s);
        }
        else if (err < eps)
        {
            return(xstart + s);
        }
        else
        {
            // 5: If the step was not final, update the B matrix and
            // do another step:

            // Calculate y
            vector y = grad_f_s - grad_f;

            // If s.dot(y) is too small, update is dangerous, don't
            // do it:
            if (Abs(s.dot(y)) < 1e-6)
            {
                return(qnewton(f, xstart + s, eps, steps, B));
            }
            else
            {
                // Calculate c:
                vector c = (s - B * y) / (s.dot(y));
                // Calculate delta_B:
                matrix delta_B = c.outer(s);
                // Do another step:
                return(qnewton(f, xstart + s, eps, steps, B + delta_B));
            }
        }
    }