Exemplo n.º 1
0
    }    // newton complex

    public static (vector, int) newton(
        Func <vector, vector> f, // func takes vector(x1,...,xn) returns vector(f1(..),..,fn(..))
        vector x,                // starting values of vector(x1,...,xn)
        double eps = 1e-3,       // accuracy goal ||f(x)||<eps
        double dx  = 1e-7        // finite difference used in numerical eval of jacobian
        )
    {                            // overload that implements a multiple-dimensional newton rootfinder for real functions of real variables
        int    n      = x.size;
        int    nsteps = 0;
        vector fx     = f(x);
        double lam;

        do
        {
            nsteps++;
            // create jacobian
            matrix J = jacobian(f, x, fx, dx);

            // find jacobian inverse by QR-decomposition
            qr_decomp_GS qrd   = new qr_decomp_GS(J);
            matrix       J_inv = qrd.inverse();

            // solve J*Dx = - fx for newton stepsize Dx
            vector Dx = -J_inv * fx;

            // lambda factor
            lam = 1.0;

            // backtracking linesearch algorithm (first failing is good, second is step out try again)
            while (f(x + lam * Dx).norm2() > fx.norm2() * (1 - lam / 2) & lam > 1.0 / 64)
            {
                lam /= 2;
            }
            // norm2 is an euclidean vector norm by its definition, with over/underflow potential
            // Update values
            x  = x + lam * Dx;
            fx = f(x);
        }while (fx.norm2() > eps);
        Error.WriteLine($"rootf.newton returning x, a condition is satisfied");
        Error.WriteLine($"f(x).norm2()          {fx.norm2()}");
        Error.WriteLine($"eps                   {eps}");
        Error.WriteLine($"lam                   {lam}");
        Error.WriteLine($"dx                    {dx}\n");
        return(x, nsteps);
    }    // qnewton real vector
Exemplo n.º 2
0
    public static (vector, int) qnewton(
        Func <vector, double> f,                // Function to evaluate
        vector x,                               // starting point
        double acc    = 1e-3,                   // accuracy goal, |gradient|<acc on exit
        double alpha  = 1e-4,                   // alpha param for Armijo condition
        double dx     = 1e-7,                   // dx used in gradient calculation
        double minlam = 1e-7,                   // minimum lambda value before reset
        int limit     = 999,                    // limit on recursion steps
        double eps    = 1.0 / 4194304
        )
    {    // Quasi-newton minimization method for multivariable function
        int n = x.size;
        // Approximate inverse Hessian matrix B with identity matrix
        matrix B = new matrix(n, n);

        B.set_identity();

        // Gradient of f(x)
        vector gradx = gradient(f, x, dx: dx);
        vector Dx;
        // Precalc fx
        double fx = f(x);

        int nsteps = 0;

        do
        {
            nsteps++;
            // Calculate Newton step
            Dx = -B * gradx;
            // Lambda factor
            double lam = 1.0;

            // Armijo condition step check (Bracktracking line-search)
            while (f(x + lam * Dx) > fx + alpha * lam * Dx.dot(gradx))
            {
                // Check if B needs to be reset and begrudgingly accept
                if (lam < minlam)
                {
                    B.set_identity(); break;
                }
                // else update lambda
                lam /= 2;
            }

            // Calc new point z and gradz
            vector z     = x + lam * Dx;
            vector gradz = gradient(f, z, dx: dx);
            // Calc u and <u, y>
            vector y   = gradz - gradx;
            vector s   = lam * Dx;
            vector u   = s - B * y;
            double uTy = u.dot(y);
            // Do SR1 update of B if uTy numerically safe
            if (Abs(uTy) > 1e-6)
            {
                B.update(u, u, 1 / uTy);
            }
            // Update x, gradx, fx
            x     = z;
            gradx = gradz;
            fx    = f(x);
        }while (gradx.norm2() > acc & nsteps <limit& Dx.norm2()> eps * x.norm2());
        Error.WriteLine($"\nminimization.qnewton returning (x, nsteps)");
        Error.WriteLine($"gradx.norm2()		{gradx.norm2()}");
        Error.WriteLine($"acc			{acc}");
        Error.WriteLine($"nsteps / limit		{nsteps} / {limit}");
        Error.WriteLine($"Dx.norm2()		{Dx.norm2()}");
        Error.WriteLine($"eps*x.norm2()		{eps*x.norm2()}\n");
        return(x, nsteps);
    }     // end qnewton