//////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2011 The Regents of the University of California // // This file is part of Qbox // // Qbox is distributed under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 2 of // the License, or (at your option) any later version. // See the file COPYING in the root directory of this distribution // or . // //////////////////////////////////////////////////////////////////////////////// // // LineMinimizer.C // //////////////////////////////////////////////////////////////////////////////// #include "LineMinimizer.h" #include #include #include using namespace std; //////////////////////////////////////////////////////////////////////////////// double LineMinimizer::interpolate(void) { const double dalpha = alpha_high - alpha_low; // use psi'(alpha_low), psi(alpha_low_), psi(alpha_high) double new_alpha; if ( use_psi ) { // use psi double psip_low = psip(fp_low); double psi_low = psi(alpha_low,f_low); double psi_high = psi(alpha_high,f_high); new_alpha = alpha_low - 0.5 * ( psip_low * dalpha * dalpha ) / ( psi_high - psi_low - psip_low * dalpha ); } else { // use f // quadratic interpolation using f_low, fp_low, f_high // new_alpha = alpha_low - 0.5 * ( fp_low * dalpha * dalpha ) / // ( f_high - f_low - fp_low * dalpha ); if ( fp_low*fp_high < 0 ) { // secant new_alpha = alpha_low - fp_low * ( (alpha_high-alpha_low)/(fp_high-fp_low) ); } else { // midpoint new_alpha = 0.5 * (alpha_low+alpha_high); } } if ( debug_print ) { cout << "LineMinimizer: interpolate: [alpha_low,alpha_high] = [" << alpha_low << "," << alpha_high << "]" << endl; cout << "LineMinimizer: interpolate: f_low, f_high: " << f_low << " " << f_high << endl; cout << "LineMinimizer: interpolate: fp_low, fp_high: " << fp_low << " " << fp_high << endl; cout << "LineMinimizer: interpolate: new_alpha: " << new_alpha << endl; } if ( alpha_low < alpha_high ) { assert ( new_alpha >= alpha_low && new_alpha <= alpha_high ); } else { assert ( new_alpha <= alpha_low && new_alpha >= alpha_high ); } return new_alpha; } //////////////////////////////////////////////////////////////////////////////// double LineMinimizer::next_alpha(double alpha, double f, double fp) { if ( done_ || fail_ ) return alpha; if ( first_use ) { first_use = false; f0 = f; fp0 = fp; alpha_low = 0; f_low = f0; fp_low = fp0; alpha_high = alpha_max_; assert(alpha_max_ > alpha_start_); if ( debug_print ) cout << "LineMinimizer: first use: f0, fp0: " << f0 << " " << fp0 << endl; return alpha_start_; } if ( debug_print ) cout << "LineMinimizer: next_alpha(" << alpha << "," << f << "," << fp << ")" << endl; bool wolfe1 = f < f0 + sigma1_ * alpha * fp0; bool wolfe2 = fabs(fp) < sigma2_ * fabs(fp0); if ( debug_print ) { cout << "LineMinimizer: wolfe1: f = " << f << endl; cout << "LineMinimizer: wolfe1: f0 + sigma1_ * alpha * fp0 = " << f0 + sigma1_ * alpha * fp0 << endl; cout << "LineMinimizer: wolfe1/wolfe2: " << wolfe1 << "/" << wolfe2 << endl; } // check if alpha satisfies both wolfe1 and wolfe2 and return if ( wolfe1 && wolfe2 ) { done_ = true; return alpha; } if ( !bracketing ) { // we have not entered the bracketing phase yet // Enter bracketing mode if condition U1 holds: psi(alpha) > psi(alpha_low) // Note: U1 is equivalent to wolfe1(alpha) == false if ( psi(alpha,f) > psi(alpha_low,f_low) ) { // wolfe1(alpha) == false // we can enter the bracketing phase // enter the bracketing phase with alpha_low = 0, alpha_high = alpha if ( debug_print ) { cout << "LineMinimizer: entering bracketing: wolfe1==false" << endl; cout << "LineMinimizer: psi(alpha), psip(alpha):" << psi(alpha,f) << " " << psip(fp) << endl; cout << "LineMinimizer: psi(alpha_low, psi(alpha_high):" << psi(alpha_low,f_low) << " " << psi(alpha_high,f_high) << endl; cout << "LineMinimizer: psip(alpha_low, psip(alpha_high):" << psip(fp_low) << " " << psip(fp_high) << endl; } bracketing = true; use_psi = true; alpha_high = alpha; f_high = f; fp_high = fp; assert(psi(alpha_low,f_low)<=0); assert(psip(fp_low)*(alpha_high-alpha_low)<=0); assert(psi(alpha_low,f_low)<=psi(alpha_high,f_high)); return interpolate(); } // check if wolfe1 is ok and f'(alpha)(alpha-alpha_low) > 0 // Need to test only the second inequality at this point if ( fp*(alpha-alpha_low) > 0 ) { // enter bracketing mode with alpha_high = alpha_low, alpha_low = alpha if ( debug_print ) cout << "LineMinimizer: entering bracketing: case U3" << endl; bracketing = true; use_psi = false; alpha_high = alpha_low; f_high = f_low; fp_high = fp_low; alpha_low = alpha; f_low = f; fp_low = fp; assert(psi(alpha_low,f_low)<=0); assert(psip(fp_low)*(alpha_high-alpha_low)<=0); assert(psi(alpha_low,f_low)<=psi(alpha_high,f_high)); return interpolate(); } // Condition U2 holds // increase alpha if ( debug_print ) cout << "LineMinimizer: U2, increase alpha" << endl; const double delta = 1.1; double new_alpha = std::min(alpha+delta*(alpha-alpha_low), alpha_max_); if ( new_alpha == alpha_max_ ) done_ = true; return new_alpha; } else { // we are already in bracketing mode nstep_++; if ( nstep_ > nstep_max_ ) { if ( debug_print ) cout << "LineMinimizer: fail, nstep_max" << endl; fail_ = true; return alpha; } if ( debug_print ) { cout << "LineMinimizer: bracketing mode: [alpha_low,alpha_high] = [" << alpha_low << "," << alpha_high << "]" << endl; cout << "LineMinimizer: bracketing mode: f_low, f_high: " << f_low << " " << f_high << endl; cout << "LineMinimizer: bracketing mode: fp_low, fp_high: " << fp_low << " " << fp_high << endl; cout << "LineMinimizer: bracketing mode: psi(alpha), psip(alpha):" << psi(alpha,f) << " " << psip(fp) << endl; cout << "LineMinimizer: bracketing mode: psi(alpha_low, psi(alpha_high):" << psi(alpha_low,f_low) << " " << psi(alpha_high,f_high) << endl; cout << "LineMinimizer: bracketing mode: psip(alpha_low, psip(alpha_high):" << psip(fp_low) << " " << psip(fp_high) << endl; } // check U1: psi(alpha) > psi(alpha_low) if ( psi(alpha,f) > psi(alpha_low,f_low) ) { if ( debug_print ) cout << "LineMinimizer: bracketing, U1" << endl; alpha_high = alpha; f_high = f; fp_high = fp; assert(psi(alpha_low,f_low)<=0); assert(psip(fp_low)*(alpha_high-alpha_low)<=0); assert(psi(alpha_low,f_low)<=psi(alpha_high,f_high)); return interpolate(); } else { // at this point psi(alpha) <= psi(alpha_low) // test condition U2: psi'(alpha)*(alpha_low-alpha) > 0 if ( psip(fp)*(alpha_low-alpha) > 0 ) { if ( debug_print ) cout << "LineMinimizer: bracketing, U2" << endl; alpha_low = alpha; f_low = f; fp_low = fp; assert(psi(alpha_low,f_low)<=0); assert(psip(fp_low)*(alpha_high-alpha_low)<=0); assert(psi(alpha_low,f_low)<=psi(alpha_high,f_high)); return interpolate(); } else { if ( debug_print ) cout << "LineMinimizer: bracketing, U3" << endl; alpha_high = alpha_low; f_high = f_low; fp_high = fp_low; alpha_low = alpha; f_low = f; fp_low = fp; assert(psi(alpha_low,f_low)<=0); assert(psip(fp_low)*(alpha_high-alpha_low)<=0); assert(psi(alpha_low,f_low)<=psi(alpha_high,f_high)); use_psi = false; return interpolate(); } } } }