bool PreconditionedDownhillType::improve_energy(bool verbose) { iter++; const double old_energy = energy(); const VectorXd g = pgrad(); // Let's immediately free the cached gradient stored internally! invalidate_cache(); // We waste some memory storing newx (besides *x itself), but this // avoids roundoff weirdness of trying to add nu*g back to *x, which // won't always get us back to the same value. Grid newx(gd, *x - nu*g); double newE = f.integral(kT, newx); int num_tries = 0; while (better(old_energy,newE)) { nu *= 0.5; newx = *x - nu*g; newE = f.integral(kT, newx); if (num_tries++ > 40) { printf("PreconditionedDownhill giving up after %d tries...\n", num_tries); return false; // It looks like we can't do any better with this algorithm. } } *x = newx; invalidate_cache(); nu *= 1.1; if (verbose) { //lm->print_info(); print_info(); } return true; }
boost::tuple< fit_tuple_t, fit_tuple_t > find_grad( const fitness_f &f, const fit_tuple_t ¤t, const double x2, const double delta ) { // Declare our first and 2nd derivatives int psize = current.get<0>().size(); int nsize = current.get<1>().size(); vector_t pgrad( psize ); vector_t ngrad( nsize ); vector_t plapl( psize ); vector_t nlapl( nsize ); // Protons for ( int i = 0; i < psize; ++i ) { fit_tuple_t plus( current ); fit_tuple_t minus( current ); plus.get<0>()[i] += delta; minus.get<0>()[i] -= delta; double x2plus = f( plus ); double x2minus = f( minus ); pgrad[i] = ( x2plus - x2minus ) / ( 2 * delta ); plapl[i] = ( x2plus + x2minus - 2 * x2 ) / bm::pow<2>(delta); } // Neutrons for ( int i = 0; i < nsize; ++i ) { fit_tuple_t plus( current ); fit_tuple_t minus( current ); plus.get<1>()[i] += delta; minus.get<1>()[i] -= delta; double x2plus = f( plus ); double x2minus = f( minus ); ngrad[i] = ( x2plus - x2minus ) / ( 2 * delta ); nlapl[i] = ( x2plus + x2minus - 2 * x2 ) / bm::pow<2>(delta); } return boost::make_tuple( fit_tuple_t( pgrad, ngrad ), fit_tuple_t( plapl, nlapl ) ); }
bool PreconditionedConjugateGradientType::improve_energy(bool verbose) { iter++; //printf("I am running ConjugateGradient::improve_energy\n"); const double E0 = energy(); if (E0 != E0) { // There is no point continuing, since we're starting with a NaN! // So we may as well quit here. if (verbose) { printf("The initial energy is a NaN, so I'm quitting early.\n"); f.print_summary("has nan:", E0); fflush(stdout); } return false; } double beta; { // Note: my notation vaguely follows that of // [wikipedia](http://en.wikipedia.org/wiki/Nonlinear_conjugate_gradient_method). // I use the Polak-Ribiere method, with automatic direction reset. // Note that we could save some memory by using Fletcher-Reeves, and // it seems worth implementing that as an option for // memory-constrained problems (then we wouldn't need to store oldgrad). pgrad(); // compute pgrad first, since that computes both. beta = -pgrad().dot(-grad() - oldgrad)/oldgradsqr; oldgrad = -grad(); if (beta < 0 || beta != beta || oldgradsqr == 0) beta = 0; if (verbose) printf("beta = %g\n", beta); oldgradsqr = -pgrad().dot(oldgrad); direction = -pgrad() + beta*direction; // Let's immediately free the cached gradient stored internally! invalidate_cache(); } // free g and pg! const double gdotd = oldgrad.dot(direction); Minimizer lm = linmin(f, gd, kT, x, direction, -gdotd, &step); for (int i=0; i<100 && lm.improve_energy(verbose); i++) { if (verbose) lm.print_info("\t"); } if (verbose) { //lm->print_info(); print_info(); printf("grad*dir/oldgrad*dir = %g\n", grad().dot(direction)/gdotd); } return (energy() < E0 || beta != 0); }