#include #include #include #include #include "tron.h" #ifndef min template static inline T min(T x,T y) { return (x static inline T max(T x,T y) { return (x>y)?x:y; } #endif #ifdef __cplusplus extern "C" { #endif extern double dnrm2_(int *, double *, int *); extern double ddot_(int *, double *, int *, double *, int *); extern int daxpy_(int *, double *, double *, int *, double *, int *); extern int dscal_(int *, double *, double *, int *); #ifdef __cplusplus } #endif static void default_print(const char *buf) { fputs(buf,stdout); fflush(stdout); } static double uTMv(int n, double *u, double *M, double *v) { const int m = n-4; double res = 0; int i; for (i=0; ifun_obj=const_cast(fun_obj); this->eps=eps; this->eps_cg=eps_cg; this->max_iter=max_iter; tron_print_string = default_print; } TRON::~TRON() { } void TRON::tron(double *w) { // Parameters for updating the iterates. double eta0 = 1e-4, eta1 = 0.25, eta2 = 0.75; // Parameters for updating the trust region size delta. double sigma1 = 0.25, sigma2 = 0.5, sigma3 = 4; int n = fun_obj->get_nr_variable(); int i, cg_iter; double delta=0, sMnorm, one=1.0; double alpha, f, fnew, prered, actred, gs; int search = 1, iter = 1, inc = 1; double *s = new double[n]; double *r = new double[n]; double *g = new double[n]; const double alpha_pcg = 0.01; double *M = new double[n]; // calculate gradient norm at w=0 for stopping condition. double *w0 = new double[n]; for (i=0; ifun(w0); fun_obj->grad(w0, g); double gnorm0 = dnrm2_(&n, g, &inc); delete [] w0; f = fun_obj->fun(w); fun_obj->grad(w, g); double gnorm = dnrm2_(&n, g, &inc); if (gnorm <= eps*gnorm0) search = 0; fun_obj->get_diagH(M); for(i=0; ifun(w_new); // Compute the actual reduction. actred = f - fnew; // On the first iteration, adjust the initial step bound. sMnorm = sqrt(uTMv(n, s, M, s)); if (iter == 1 && !delta_adjusted) { delta = min(delta, sMnorm); delta_adjusted = true; } // Compute prediction alpha*sMnorm of the step. if (fnew - f - gs <= 0) alpha = sigma3; else alpha = max(sigma1, -0.5*(gs/(fnew - f - gs))); // Update the trust region bound according to the ratio of actual to predicted reduction. if (actred < eta0*prered) delta = min(alpha*sMnorm, sigma2*delta); else if (actred < eta1*prered) delta = max(sigma1*delta, min(alpha*sMnorm, sigma2*delta)); else if (actred < eta2*prered) delta = max(sigma1*delta, min(alpha*sMnorm, sigma3*delta)); else { if (reach_boundary) delta = sigma3*delta; else delta = max(delta, min(alpha*sMnorm, sigma3*delta)); } info("iter %2d act %5.3e pre %5.3e delta %5.3e f %5.3e |g| %5.3e CG %3d\n", iter, actred, prered, delta, f, gnorm, cg_iter); if (actred > eta0*prered) { iter++; memcpy(w, w_new, sizeof(double)*n); f = fnew; fun_obj->grad(w, g); fun_obj->get_diagH(M); for(i=0; iget_nr_variable(); double one = 1; double *d = new double[n]; double *Hd = new double[n]; double zTr, znewTrnew, alpha, beta, cgtol; double *z = new double[n]; *reach_boundary = false; for (i=0; iHv(d, Hd); alpha = zTr/ddot_(&n, d, &inc, Hd, &inc); daxpy_(&n, &alpha, d, &inc, s, &inc); double sMnorm = sqrt(uTMv(n, s, M, s)); if (sMnorm > delta) { info("cg reaches trust region boundary\n"); *reach_boundary = true; alpha = -alpha; daxpy_(&n, &alpha, d, &inc, s, &inc); double sTMd = uTMv(n, s, M, d); double sTMs = uTMv(n, s, M, s); double dTMd = uTMv(n, d, M, d); double dsq = delta*delta; double rad = sqrt(sTMd*sTMd + dTMd*(dsq-sTMs)); if (sTMd >= 0) alpha = (dsq - sTMs)/(sTMd + rad); else alpha = (rad - sTMd)/dTMd; daxpy_(&n, &alpha, d, &inc, s, &inc); alpha = -alpha; daxpy_(&n, &alpha, Hd, &inc, r, &inc); break; } alpha = -alpha; daxpy_(&n, &alpha, Hd, &inc, r, &inc); for (i=0; i= dmax) dmax = fabs(x[i]); return(dmax); } void TRON::set_print_string(void (*print_string) (const char *buf)) { tron_print_string = print_string; }