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