00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "QMCWolfeStepLengthSelector.h"
00014
00015 double QMCWolfeStepLengthSelector::stepLength(
00016 QMCObjectiveFunction *function, Array1D<double> & position,
00017 Array1D<double> & searchDirection, Array1D<double> & gradient,
00018 Array2D<double> & unused,
00019 double functionValue)
00020
00021 {
00022 OF = function;
00023
00024 double alpha_guess = 2.0;
00025
00026 return wolfeStepLength(alpha_guess,position,searchDirection,gradient,
00027 functionValue);
00028 }
00029
00030 double QMCWolfeStepLengthSelector::calculateLineSearchObjectiveFunction(
00031 Array1D<double> & params,
00032 Array1D<double> & searchDirection,
00033 double stepLength)
00034 {
00035 Array1D<double> p;
00036
00037 p = params + (searchDirection*stepLength);
00038
00039 return OF->evaluate(p).getScore();
00040 }
00041
00042 double QMCWolfeStepLengthSelector::calculateLineSearchObjectiveFunctionDerivative(
00043 Array1D<double> & params,
00044 Array1D<double> & searchDirection,
00045 double stepLength)
00046 {
00047 const double epsilon = 1.0e-4;
00048
00049 double phi = calculateLineSearchObjectiveFunction(params,searchDirection,
00050 stepLength);
00051 double phi_epsilon = calculateLineSearchObjectiveFunction(params,
00052 searchDirection,
00053 stepLength+epsilon);
00054
00055 return (phi_epsilon-phi)/epsilon;
00056 }
00057
00058 double QMCWolfeStepLengthSelector::cubicInterpolateStep(double a_lo,
00059 double a_hi,
00060 double phi_0,
00061 double phi_a_lo,
00062 double phi_a_hi,
00063 double phi_prime_0)
00064 {
00065
00066
00067
00068
00069 if( fabs(a_lo) < 1e-8 ) a_lo = 1e-8;
00070 if( fabs(a_hi) < 1e-8 ) a_hi = 1e-8;
00071 if( fabs(a_lo - a_hi) < 1e-8) return (a_lo+a_hi)/2.0;
00072
00073 Array2D<double> M(2,2);
00074
00075 M(0,0) = a_lo * a_lo;
00076 M(0,1) = -a_hi * a_hi;
00077 M(1,0) = -a_lo * a_lo * a_lo;
00078 M(1,1) = a_hi * a_hi * a_hi;
00079
00080 Array1D<double> v(2);
00081
00082 v(0) = phi_a_hi - phi_0 - a_hi * phi_prime_0;
00083 v(1) = phi_a_lo - phi_0 - a_lo * phi_prime_0;
00084
00085 double factor = a_lo * a_lo * a_hi * a_hi * ( a_hi - a_lo );
00086
00087 Array1D<double> ab(2);
00088
00089 for(int i=0; i<2; i++)
00090 {
00091 ab(i) = 0.0;
00092
00093 for(int j=0; j<2; j++)
00094 {
00095 ab(i) = M(i,j) * v(j);
00096 }
00097 }
00098
00099 ab /= factor;
00100
00101 double desc = ab(1)*ab(1)-3.0*ab(0)*phi_prime_0;
00102
00103 if( desc < 0 ) return (a_hi+a_lo)/2.0;
00104
00105
00106 double a_new = (-ab(1)+sqrt(desc))/3.0/ab(0);
00107
00108
00109 if( a_new < a_lo ) a_new = (a_lo + a_hi)/2.0;
00110 if( a_new > a_hi ) a_new = (a_lo + a_hi)/2.0;
00111
00112
00113 double interptol = 1e-6;
00114
00115 if( fabs(a_new-a_lo) < interptol * fabs(a_hi-a_lo) )
00116 {
00117 a_new = a_lo + interptol;
00118 }
00119
00120 if( fabs(a_new-a_hi) < interptol * fabs(a_hi-a_lo) )
00121 {
00122 a_new = a_hi - interptol;
00123 }
00124
00125 return a_new;
00126 }
00127
00128
00129 double QMCWolfeStepLengthSelector::zoom(double a_lo, double a_hi,
00130 double phi_0,
00131 double phi_a_lo, double phi_a_hi,
00132 double phi_prime_0,
00133 Array1D<double> & params,
00134 Array1D<double> & searchDirection)
00135 {
00136 const double zoomTol = 1e-7;
00137 const int maxZoomSteps = 1000;
00138 const double c1 = 1.0e-4;
00139 const double c2 = 0.1;
00140
00141 double a;
00142
00143 for(int i=0; i<maxZoomSteps; i++)
00144 {
00145
00146 if( fabs(a_lo-a_hi) < zoomTol ) return (a_lo+a_hi)/2.0;
00147
00148
00149 a = cubicInterpolateStep( a_lo, a_hi, phi_0, phi_a_lo,
00150 phi_a_hi, phi_prime_0);
00151
00152
00153 double phi_a =
00154 calculateLineSearchObjectiveFunction(params,searchDirection,a);
00155
00156 if( phi_a > phi_0 + c1 * a * phi_prime_0 || phi_a >= phi_a_lo )
00157 {
00158 a_hi = a;
00159 phi_a_hi = phi_a;
00160 }
00161 else
00162 {
00163 double phi_prime_a =
00164 calculateLineSearchObjectiveFunctionDerivative(params,
00165 searchDirection,a);
00166
00167 if( fabs(phi_prime_a) <= -c2 * phi_prime_0 )
00168 {
00169 return a;
00170 }
00171 else if( phi_prime_a * (a_hi - a_lo) >= 0 )
00172 {
00173 a_hi = a_lo;
00174 phi_a_hi = phi_a_lo;
00175 }
00176
00177 a_lo = a;
00178 phi_a_lo = phi_a;
00179 }
00180 }
00181
00182 cerr << "WARNING: zoom(...) in QMCWolfeStepLengthSelector did not converge!" << endl;
00183
00184 return a;
00185 }
00186
00187
00188 double QMCWolfeStepLengthSelector::wolfeStepLength(double alpha_guess,
00189 Array1D<double> & params,
00190 Array1D<double> & searchDirection,
00191 Array1D<double> & gradient,
00192 double functionValue)
00193 {
00194 const double alpha_max = 2.0;
00195 const int MaxWolfeSteps = 1000;
00196 const double c1 = 1.0e-4;
00197 const double c2 = 0.1;
00198
00199
00200
00201
00202
00203 double a_max = alpha_max;
00204 double phi_max =
00205 calculateLineSearchObjectiveFunction(params,searchDirection,alpha_max);
00206
00207 double a_0 = 0.0;
00208 double a_1 = alpha_guess;
00209
00210 double phi_0 = functionValue;
00211 double phi_prime_0 = gradient*searchDirection;
00212
00213 double phi_a_0 = phi_0;
00214 double phi_a_1;
00215 double phi_prime_a_1;
00216
00217 for( int i=0; i<MaxWolfeSteps; i++ )
00218 {
00219 phi_a_1 =
00220 calculateLineSearchObjectiveFunction(params,searchDirection,a_1);
00221
00222
00223 if( phi_a_1 > phi_0 + c1 * a_1 * phi_prime_0 ||
00224 ( phi_a_1 >= phi_a_0 && i>0 ) )
00225 {
00226 return zoom(a_0,a_1,phi_0,phi_a_0,phi_a_1,phi_prime_0,params,
00227 searchDirection);
00228 }
00229
00230
00231 phi_prime_a_1 =
00232 calculateLineSearchObjectiveFunctionDerivative(params,
00233 searchDirection,a_1);
00234
00235
00236 if( fabs(phi_prime_a_1) <= -c2 * phi_prime_0 )
00237 {
00238 return a_1;
00239 }
00240
00241 if( phi_prime_a_1 >= 0 )
00242 {
00243 return zoom(a_1,a_0,phi_0,phi_a_1,phi_a_0,phi_prime_0,params,
00244 searchDirection);
00245 }
00246
00247
00248 a_0 = a_1;
00249 phi_a_0 = phi_a_1;
00250
00251
00252 a_1 = cubicInterpolateStep(a_0,a_max,phi_0,phi_a_0,phi_max,phi_prime_0);
00253 }
00254
00255 cerr << "WARNING: wolfeStepLength(...) in QMCWolfeStepLengthSelector did "
00256 << "not converge!" << endl;
00257
00258 return a_1;
00259 }
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269