00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "QMCEigenSearch.h"
00014 #include "QMCInput.h"
00015 #include <iomanip>
00016 #include <sstream>
00017 #include "CubicSpline.h"
00018 #include "IeeeMath.h"
00019 #include "svdcmp.h"
00020
00021 bool QMCEigenSearch::currentlyHalf = true;
00022 int QMCEigenSearch::orig_steps = 0;
00023 Array1D<double> QMCEigenSearch::orig_params;
00024 vector<double> QMCEigenSearch::adiag_tests;
00025 Array2D<double> QMCEigenSearch::hamiltonian;
00026 Array2D<double> QMCEigenSearch::overlap;
00027
00028 vector<double> QMCEigenSearch::f;
00029 vector<double> QMCEigenSearch::variance;
00030 vector< Array1D<double> > QMCEigenSearch::x;
00031
00032 QMCEigenSearch::QMCEigenSearch(QMCObjectiveFunction *function,
00033 QMCLineSearchStepLengthSelectionAlgorithm * stepAlg,
00034 int MaxSteps,
00035 double tol)
00036 {
00037 dim = 0;
00038 OF = function;
00039 stepLengthAlg = stepAlg;
00040 maximumSteps = MaxSteps;
00041 epsilon = tol;
00042 }
00043
00044 double QMCEigenSearch::get_a_diag(QMCDerivativeProperties & dp, double a_diag_factor)
00045 {
00046 static double a_diag = globalInput.flags.a_diag;
00047
00048 if(globalInput.flags.a_diag > 0)
00049 {
00050 if(globalInput.flags.optimize_Psi_method == "automatic" &&
00051 fabs(a_diag_factor - 1.0) < 1e-10)
00052 if(optStep == 6)
00053 {
00054 a_diag *= 1e-1;
00055 } else if(optStep == 12)
00056 {
00057 a_diag *= 1e-2;
00058 } else if(optStep == 23)
00059 {
00060 a_diag *= 1e-5;
00061 }
00062
00063 double cutoff = 1.0e-10;
00064 if( fabs(a_diag) < cutoff )
00065 a_diag = cutoff;
00066
00067 return a_diag * a_diag_factor;
00068 }
00069
00070 Array1D<double> samplesE = dp.getCorrelatedSamples(0);
00071 Array1D<double> samplesV = dp.getCorrelatedSamples(1);
00072
00073 if(samplesV.dim1() == 0)
00074 {
00075
00076 return a_diag;
00077 }
00078
00079 Array1D<double> xvals(adiag_tests.size());
00080 Array1D<double> yvals(adiag_tests.size());
00081 xvals = 0.0;
00082 yvals = 0.0;
00083
00084 double eng_frac = 0.95;
00085 double var_frac = 1.0 - eng_frac;
00086 printf(" %3s %10s %20s %20s %20s %20s %g%% * OE + %g%% * OV\n","CS","a_diag","Energy","Sample Variance","Objective Energy","Objective Variance",100*eng_frac,100*var_frac);
00087
00088 double best = -99;
00089 int best_idx = -1;
00090 for(int cs=0; cs<xvals.dim1(); cs++)
00091 {
00092 int si = cs+1;
00093 double objv = (samplesV(si) - samplesV(0))/samplesV(0);
00094 double obje = (samplesE(si) - samplesE(0));
00095 double obj = eng_frac * obje + var_frac * objv;
00096
00097 xvals(cs) = log(adiag_tests[cs]);
00098 yvals(cs) = obj;
00099
00100 if(!IeeeMath::isNaN(obj))
00101 if(obj < best || best_idx < 0)
00102 {
00103 best_idx = cs;
00104 best = obj;
00105 a_diag = adiag_tests[cs];
00106 }
00107
00108 printf(" %3i %10.5g %20.10e %20.10e %20.10e %20.10e %20.10e\n",
00109 cs, adiag_tests[cs], samplesE(si), samplesV(si), obje, objv, obj);
00110 }
00111 printf(" %3s %10s %20.10e %20.10e\n","","guide", samplesE(0), samplesV(0));
00112
00113 cout << "Best correlated sample used a_diag = " << a_diag
00114 << " with objective value " << best << " idx = " << best_idx << endl;
00115
00116
00117 CubicSpline findmin;
00118 findmin.initializeWithFunctionValues(xvals,yvals,0,0);
00119
00120 cout << "CubicSpline data:" << endl;
00121 for(int i=0; i<xvals.dim1(); i++)
00122 printf("%20.10e %20.10e\n",xvals(i),yvals(i));
00123
00124
00125
00126
00127
00128
00129 double min1, min2, min3;
00130 double fmin1, fmin2, fmin3;
00131
00132 if(best_idx-1 >= 0)
00133 min1 = findmin.minimum(xvals(best_idx-1),xvals(best_idx));
00134 else
00135 min1 = xvals(best_idx);
00136
00137 if(best_idx+1 < xvals.dim1())
00138 min2 = findmin.minimum(xvals(best_idx),xvals(best_idx+1));
00139 else
00140 min2 = xvals(best_idx);
00141
00142 min3 = findmin.minimum(xvals(0),xvals(xvals.size()-1));
00143
00144 fmin1 = findmin.function(min1);
00145 fmin2 = findmin.function(min2);
00146 fmin3 = findmin.function(min3);
00147
00148 double min, fmin;
00149 min = fmin1 < fmin2 ? min1 : min2;
00150 fmin = findmin.function(min);
00151 min = fmin < fmin3 ? min : min3;
00152 fmin = findmin.function(min);
00153 min = fmin < best ? min : xvals(best_idx);
00154 fmin = findmin.function(min);
00155
00156 printf("min1 = %20.10e fmin1 = %20.10e\n",min1,fmin1);
00157 printf("min2 = %20.10e fmin2 = %20.10e\n",min2,fmin2);
00158 printf("min3 = %20.10e fmin3 = %20.10e\n",min3,fmin3);
00159 printf("min = %20.10e fmin = %20.10e\n",min,fmin);
00160
00161
00162 cout << "Fitted a_diag = " << exp(min) << endl;
00163 cout << "Best a_diag = " << a_diag << " with objective value " << fmin << endl;
00164
00165 return a_diag;
00166 }
00167
00168 Array1D<double> QMCEigenSearch::optimize(Array1D<double> & CurrentParams,
00169 QMCDerivativeProperties & dp,
00170 double a_diag_factor,
00171 int step)
00172 {
00173 bool verbose = false;
00174 optStep = step;
00175 stepinfo.clear();
00176 stepinfo << "(Step = " << setw(3) << optStep << "):";
00177 stepinfo.precision(12);
00178
00179 cout.setf(ios::scientific);
00180 cout << endl;
00181
00182 dim = CurrentParams.dim1();
00183
00184 x.push_back(CurrentParams);
00185 f.push_back(dp.getParameterValue());
00186 variance.push_back(dp.getSampleVariance());
00187
00188 if(globalInput.flags.a_diag > 0)
00189 {
00190 currentlyHalf = false;
00191 hamiltonian = dp.getParameterHamiltonian();
00192 overlap = dp.getParameterOverlap();
00193 orig_params = CurrentParams;
00194 orig_steps = globalInput.flags.max_time_steps;
00195 }
00196
00197 cout << "Beginning Generalized Eigenvector Optimization ";
00198 cout << (currentlyHalf ? "half" : "full");
00199 cout << " step " << optStep << " for " << dim
00200 << " parameters: " << endl;
00201
00202 if(verbose){
00203
00204 globalInput.printAIParameters(cout,"Parameters",20,CurrentParams,false);
00205 }
00206
00207 Array1D<double> gradient = dp.getParameterGradient();
00208 globalInput.printAIParameters(cout,"Gradient",20,gradient,true);
00209
00210 Array1D<double> params;
00211 if(currentlyHalf)
00212 {
00213 orig_params = CurrentParams;
00214 orig_steps = globalInput.flags.max_time_steps;
00215 hamiltonian = dp.getParameterHamiltonian();
00216 overlap = dp.getParameterOverlap();
00217 adiag_tests.clear();
00218
00219 if(false)
00220 {
00221 double fac = sqrt(10.0);
00222 adiag_tests.push_back(0.0);
00223 adiag_tests.push_back(1e-15);
00224 adiag_tests.push_back(1e-12);
00225 adiag_tests.push_back(1e-10);
00226 adiag_tests.push_back(1.0e-8);
00227 while(adiag_tests[adiag_tests.size()-1] < 1000)
00228 adiag_tests.push_back(fac * adiag_tests[adiag_tests.size()-1]);
00229 } else {
00230 adiag_tests.push_back(1.0e-7);
00231 adiag_tests.push_back(1.0e-5);
00232 adiag_tests.push_back(1.0e-3);
00233 adiag_tests.push_back(1.0e-1);
00234 adiag_tests.push_back(1.0e0);
00235 adiag_tests.push_back(1.0e1);
00236 adiag_tests.push_back(1.0e2);
00237 adiag_tests.push_back(1.0e3);
00238 }
00239
00240 int numTests = adiag_tests.size();
00241 globalInput.cs_Parameters.allocate(adiag_tests.size()+1);
00242 for(int cs=0; cs<numTests; cs++)
00243 {
00244 Array1D<double> aParams = getParameters(dp,adiag_tests[cs],verbose);
00245 globalInput.cs_Parameters(cs+1) = aParams;
00246
00247 stepinfo << endl;
00248 stringstream temp;
00249 temp.setf(ios::scientific);
00250 temp << "CS " << adiag_tests[cs];
00251
00252
00253 }
00254
00255 globalInput.cs_Parameters(0) = CurrentParams;
00256
00257
00258
00259 params = globalInput.cs_Parameters(0);
00260 if(orig_steps < 10000)
00261 {
00262 globalInput.flags.max_time_steps = min(2000,orig_steps);
00263 }
00264 else
00265 {
00266 globalInput.flags.max_time_steps = min(20000,(int)(0.2*orig_steps));
00267 }
00268 globalInput.flags.max_time_steps += globalInput.flags.equilibration_steps;
00269 globalInput.flags.calculate_Derivatives = 0;
00270 }
00271 else
00272 {
00273 globalInput.cs_Parameters.deallocate();
00274 double a_diag = get_a_diag(dp,a_diag_factor);
00275 params = getParameters(dp,a_diag,true);
00276 globalInput.flags.calculate_Derivatives = 1;
00277
00278 clog << "(Step = " << setw(3) << optStep << "): Best Objective adiag ";
00279 clog.precision(12);
00280 clog.width(10);
00281 clog.unsetf(ios::scientific);
00282 clog.unsetf(ios::fixed);
00283 clog << a_diag;
00284 clog << " (" << dim;
00285 if(globalInput.flags.optimize_L)
00286 clog << "+L";
00287 else
00288 clog << "-L";
00289 clog << " params)";
00290
00291 printf("\nstep-4 f+v %20.10g f=%20.10g v=%20.10e\n",f[optStep-4] + variance[optStep-4],f[optStep-4], variance[optStep-4]);
00292 printf("step-2 f= %20.10g v=%20.10e steps increase %20.10f\n",f[optStep-2],variance[optStep-2],variance[optStep-2]/variance[optStep-4]);
00293
00294 if(optStep >= 4 &&
00295 f[optStep-2] > (f[optStep-4] + variance[optStep-4]) &&
00296 f[optStep-2] < globalInput.flags.energy_trial)
00297 {
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 double frac = 2.0;
00308 globalInput.flags.max_time_steps = (long)(orig_steps * frac);
00309
00310
00311 unsigned long cutoff = 500*1000;
00312 if(globalInput.flags.max_time_steps > cutoff)
00313 globalInput.flags.max_time_steps = cutoff;
00314
00315 clog << " new steps = " << globalInput.flags.max_time_steps << endl;
00316 } else {
00317
00318
00319
00320
00321 globalInput.flags.max_time_steps = orig_steps;
00322 }
00323
00324 clog << endl;
00325 }
00326
00327 currentlyHalf = !currentlyHalf;
00328 cout << endl << "Ending Generalized Eigenvector Search Optimization... " << endl << endl;
00329 cout << stepinfo.str() << endl;
00330 return params;
00331 }
00332
00333 Array1D<double> QMCEigenSearch::getParameters(QMCDerivativeProperties & dp, double a_diag, bool verbose)
00334 {
00335 Array2D<double> ham = hamiltonian;
00336 Array2D<double> olap = overlap;
00337
00338 if( fabs(a_diag) > 0.0)
00339 {
00340 for(int d=1; d<dim+1; d++)
00341 ham(d,d) = ham(d,d) + a_diag;
00342
00343 stepinfo << " a_diag = " << setw(20) << setprecision(10) << a_diag;
00344 }
00345
00346 int largestPrintableMatrix = 10;
00347 if(verbose)
00348 {
00349 if(ham.dim1() <= largestPrintableMatrix)
00350 {
00351 cout << "Hamiltonian:" << endl;
00352 ham.printArray2D(cout,12,7,-1,',',true);
00353 cout << "Overlap:\n" << endl;
00354 olap.printArray2D(cout,12,7,-1,',',true);
00355 } else if(ham.dim1() < 20) {
00356 cout << "Hamiltonian:" << endl;
00357 ham.printArray2D(cout,2,7,-1,',',true);
00358 cout << "Overlap:\n" << endl;
00359 olap.printArray2D(cout,2,7,-1,',',true);
00360 }
00361 }
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390 Array2D<double> eigvec;
00391 Array1D<Complex> eigval;
00392
00393
00394 eigvec.generalizedEigenvectors(ham,
00395 olap,
00396 eigval);
00397
00398 if(verbose)
00399 {
00400 if(eigvec.dim1() <= largestPrintableMatrix)
00401 {
00402 cout << "Eigenvectors:" << endl;
00403 eigvec.printArray2D(cout,12,7,-1,',',true);
00404 } else if(ham.dim1() < 20) {
00405 cout << "Eigenvectors:" << endl;
00406 eigvec.printArray2D(cout,2,7,-1,' ',true);
00407 }
00408 }
00409
00410 int best_idx = 0;
00411 double best_val = 0.0;
00412 cout.precision(12);
00413 for(int i=0; i<dim+1; i++)
00414 {
00415
00416 if(verbose){
00417 stringstream eigvalSS;
00418 eigvalSS << eigval(i);
00419 if(i%5 == 0){
00420 cout << endl << "Eigenvalue(" << setw(3) << i << "): " << setw(20) << eigvalSS.str();
00421 } else {
00422 cout << setw(20) << eigvalSS.str();
00423 }
00424 }
00425 double val = eigval(i).real();
00426 if( fabs(eigval(i).imaginary()) < 1e-50 &&
00427 val < best_val &&
00428 !IeeeMath::isNaN(val) &&
00429 fabs(val) < 1.0e5)
00430 {
00431 best_val = eigval(i).real();
00432 best_idx = i;
00433 }
00434 }
00435
00436 if(verbose){
00437 cout << endl;
00438 cout << "Lowest Eigenvalue(" << setw(3) << best_idx << "): " << best_val << endl;
00439 cout << endl;
00440 }
00441
00442 stepinfo << " lowest eigenvalue = " << setw(20) << best_val;
00443
00444 Array1D<double> delta_x(dim);
00445 for(int i=0; i<delta_x.dim1(); i++)
00446 delta_x(i) = eigvec[best_idx][i+1];
00447
00448 delta_x /= eigvec[best_idx][0];
00449
00450
00451
00452
00453
00454
00455
00456
00457 double rescale = 1.0;
00458 if(stepLengthAlg != 0)
00459 {
00460 Array2D<double> fresh_overlap = overlap;
00461 double ksi = globalInput.flags.ksi;
00462 stepinfo << " ksi = " << setw(5) << ksi;
00463 rescale = stepLengthAlg->stepLength(OF,
00464 delta_x,
00465 delta_x,
00466 delta_x,
00467 fresh_overlap,
00468 ksi);
00469 }
00470 stepinfo << " rescaling factor = " << setw(20) << rescale;
00471
00472 Array1D<double> x_new = orig_params;
00473
00474 if(IeeeMath::isNaN(rescale) || rescale < 0.05)
00475 {
00476 cout << "Warning: invalid rescale = " << setw(20) << rescale
00477 << " for a_diag = " << a_diag << endl;
00478
00479 if(IeeeMath::isNaN(rescale))
00480 {
00481 x_new = 0.0;
00482 return x_new;
00483 }
00484 } else {
00485
00486 }
00487
00488 delta_x *= rescale;
00489
00490 if(verbose)
00491 globalInput.printAIParameters(cout,"Delta params",20,delta_x,true);
00492
00493 for(int j=0; j<dim; j++)
00494 x_new(j) += delta_x(j);
00495
00496 return x_new;
00497 }
00498
00499 QMCObjectiveFunction * QMCEigenSearch::getObjectiveFunction()
00500 {
00501 return OF;
00502 }