00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "QMCLineSearch.h"
00014 #include "QMCInput.h"
00015 #include <iomanip>
00016
00017 QMCLineSearch::QMCLineSearch(QMCObjectiveFunction *function,
00018 QMCLineSearchStepLengthSelectionAlgorithm * stepAlg,
00019 int MaxSteps,
00020 double tol)
00021 {
00022 dim = 0;
00023 OF = function;
00024 stepLengthAlg = stepAlg;
00025 maximumSteps = MaxSteps;
00026 epsilon = tol;
00027 }
00028
00029 double QMCLineSearch::stepLength(Array1D<double> & x,Array1D<double> & p,
00030 Array1D<double> & g, double f)
00031 {
00032 Array2D<double> temp;
00033 if(stepLengthAlg != 0)
00034 return stepLengthAlg->stepLength(OF,x,p,g,temp,f);
00035 return 1.0;
00036 }
00037
00038 Array1D<double> QMCLineSearch::searchDirection()
00039 {
00040 calculateHessian();
00041
00042
00043
00044 Array1D<double> p_k(dim);
00045
00046 Array2D<double> & invHess = inverseHessian.back();
00047 Array1D<double> & grad = gradient.back();
00048
00049 for(int i=0; i<dim; i++)
00050 {
00051 p_k(i) = 0.0;
00052 for(int j=0; j<dim; j++)
00053 {
00054 p_k(i) -= invHess(i,j) * grad(j);
00055 }
00056 }
00057 return p_k;
00058 }
00059
00060 Array1D<double> QMCLineSearch::optimize(Array1D<double> & InitialGuess,
00061 QMCDerivativeProperties & dp,
00062 double a_diag_factor,
00063 int optStep)
00064
00065 {
00066 cout.setf(ios::scientific);
00067 cout << endl;
00068
00069 dim = InitialGuess.dim1();
00070
00071 double InitialValue = dp.getParameterValue();
00072 Array1D<double> InitialGradient = dp.getParameterGradient();
00073 Array2D<double> InitialHessian = dp.getParameterHessian();
00074
00075 bool useInitialHess = InitialHessian.dim1() == dim && InitialHessian.dim2() == dim;
00076 bool useInitialGrad = InitialGradient.dim1() == dim;
00077
00078 if( (!useInitialGrad && InitialGradient.dim1() > 0) ||
00079 (!useInitialHess && InitialHessian.dim1() > 0))
00080 {
00081 clog << "Warning: were you intending to use InitialGradient/Hessian?" << endl
00082 << " InitialGuess.dim1() == " << dim << endl
00083 << " InitialGradient.dim1() == " << InitialGradient.dim1() << endl
00084 << " InitialHessian.dim1() == " << InitialHessian.dim1() << endl << endl;
00085 }
00086
00087
00088 x.push_back(InitialGuess);
00089
00090 cout << "Beginning Line Search Optimization step " << optStep << " for " << dim
00091 << " parameters, max steps = " << maximumSteps << ", with: " << endl;
00092 cout << " InitialValue = " << InitialValue << endl;
00093 globalInput.printAIParameters(cout,"InitialGuess",20,InitialGuess,false);
00094 if(useInitialGrad)
00095 globalInput.printAIParameters(cout,"InitialGradient",20,InitialGradient,true);
00096
00097 if(useInitialHess)
00098 {
00099 static double a_diag = globalInput.flags.a_diag;
00100
00101 if(globalInput.flags.optimize_Psi_method == "automatic" &&
00102 fabs(a_diag_factor - 1.0) < 1e-10)
00103 if(optStep == 6)
00104 {
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 a_diag *= 1;
00125
00126
00127
00128 } else if(optStep == 12)
00129 {
00130 a_diag *= 0.01;
00131 } else if(optStep == 23)
00132 {
00133 a_diag *= 1e-5;
00134 }
00135
00136 if( fabs(a_diag) > 0.0){
00137 for(int d=0; d<dim; d++)
00138 InitialHessian(d,d) = InitialHessian(d,d) + a_diag * a_diag_factor;
00139
00140 cout << "Notice: Adding a_diag = " << (a_diag * a_diag_factor)
00141 << " to the diagonal elements of the hessian" << endl;
00142 }
00143
00144 Array1D<double> eig = InitialHessian.eigenvaluesRS();
00145 double nsym = InitialHessian.nonSymmetry();
00146 cout << " InitialHessian (non symmetry = " << nsym << ") =" << endl;
00147 if(InitialHessian.dim1() < 20)
00148 InitialHessian.printArray2D(cout,4,7,-1,' ',true);
00149 else
00150 cout << "<too large, not printed>" << endl;
00151 cout << "Eigenvalues of hessian are: " << endl;
00152 for(int ei=0; ei<eig.dim1(); ei++)
00153 cout << " " << eig(ei) << endl;
00154
00155 if(eig.dim1() > 0 && eig(0) < 0.0)
00156 {
00157 for(int d=0; d<dim; d++)
00158 InitialHessian(d,d) = InitialHessian(d,d) - eig(0);
00159
00160 cout << "Notice: Adding eigenvalue = " << ( - eig(0) )
00161 << " to the diagonal elements of the hessian" << endl;
00162 }
00163 }
00164
00165 bool ok = false;
00166 Array2D<double> InitialInverseHessian(dim,dim);
00167 if(useInitialHess)
00168 {
00169 double det = 0.0;
00170 InitialHessian.determinant_and_inverse(InitialInverseHessian,
00171 det, &ok);
00172
00173 if(!ok)
00174 {
00175 cerr << "Error: InitialHessian can't be inverted!";
00176 cerr << " det = " << det << endl;
00177 cerr << " Using identity matrix instead." << endl;
00178 }
00179 }
00180
00181 if(!ok || !useInitialHess)
00182 InitialInverseHessian.setToIdentity();
00183 inverseHessian.push_back(InitialInverseHessian);
00184
00185 if(useInitialGrad)
00186 gradient.push_back(InitialGradient);
00187
00188 cout << endl << endl;
00189 for(int i=0; i<maximumSteps; i++)
00190 {
00191 cout << endl << "\tIteration: " << i << endl;
00192
00193
00194
00195 if(i == 0 && fabs(InitialValue - 99.0) > 1e-10)
00196 f.push_back(InitialValue);
00197 else
00198 f.push_back(OF->evaluate(x[i]).getScore());
00199
00200
00201 if( i>0 && fabs(1.0-f[i]/f[i-1]) < epsilon )
00202 {
00203 cout << "Line Search Optimization Has Converged in "
00204 << i << " Iterations... " << endl;
00205 break;
00206 }
00207
00208 if(i > 0 || !useInitialGrad)
00209 gradient.push_back(getObjectiveFunction()->grad(x[i]));
00210
00211 if(i > 0)
00212 {
00213 Array2D<double> new_inverseHessian(dim,dim);
00214 new_inverseHessian.setToIdentity();
00215 inverseHessian.push_back(new_inverseHessian);
00216 }
00217
00218
00219
00220
00221
00222 Array1D<double> p_k = searchDirection();
00223
00224
00225
00226
00227
00228 double alpha_k = stepLength(x[i],
00229 p_k,
00230 gradient[i],
00231 f[i]);
00232
00233 cout << setw(20) << "Objective Value:";
00234 cout.precision(12);
00235 cout.width(20);
00236 cout << f[i] << endl;
00237 globalInput.printAIParameters(cout,"Parameters:",20,x[i],false);
00238 globalInput.printAIParameters(cout,"Gradient:",20,gradient[i],false);
00239 globalInput.printAIParameters(cout,"Search Direction:",20,p_k,false);
00240 cout << setw(20) << "stepLength:";
00241 cout.precision(12);
00242 cout.width(20);
00243 cout << alpha_k << endl;
00244
00245 if(inverseHessian.back().isIdentity())
00246 {
00247 cout << "\t\tInverseHessian: (identity matrix)\n";
00248 } else {
00249 double nsym = inverseHessian.back().nonSymmetry();
00250 cout << "\t\tInverseHessian (non symmetry = " << nsym << "):" << endl;
00251 if(inverseHessian.back().dim1() < 20)
00252 inverseHessian.back().printArray2D(cout,4,7,-1,' ',true);
00253 else
00254 cout << "<too large, not printed>" << endl;
00255 }
00256
00257
00258 Array1D<double> x_new = x.back();
00259 for(int j=0; j<dim; j++)
00260 {
00261 x_new(j) += alpha_k * p_k(j);
00262 }
00263 x.push_back(x_new);
00264 }
00265
00266 cout << endl << "Ending Line Search Optimization... " << endl;
00267
00268 cout << endl;
00269 return x.back();
00270 }
00271
00272 QMCObjectiveFunction * QMCLineSearch::getObjectiveFunction()
00273 {
00274 return OF;
00275 }