00001
00002
00004
00005 #include "PositiveDefiniteLevenbergMarquardtMinimizer.h"
00006
00008
00010
00011 CPositiveDefiniteLevenbergMarquardtMinimizer::CPositiveDefiniteLevenbergMarquardtMinimizer()
00012 {
00013 m_dMarquardt = 0.00001;
00014 m_dChiSqTol = 0.001;
00015 m_dGradTol = 0.001;
00016 m_iNIterations = 1000;
00017
00018 }
00019
00020 CPositiveDefiniteLevenbergMarquardtMinimizer::CPositiveDefiniteLevenbergMarquardtMinimizer(CParameterFilter *pFilter, double marquardt, double chiTol, double gradTol, int nIterations)
00021 {
00022 m_dMarquardt = marquardt;
00023 m_dChiSqTol = chiTol;
00024 m_dGradTol = gradTol;
00025 m_iNIterations = nIterations;
00026 m_pFilter = pFilter;
00027 }
00028
00029 CPositiveDefiniteLevenbergMarquardtMinimizer::~CPositiveDefiniteLevenbergMarquardtMinimizer()
00030 {
00031
00032 }
00033
00034 double CPositiveDefiniteLevenbergMarquardtMinimizer::Minimize(double *parameters, Minimizable *minimizable)
00035 {
00036 int i;
00037
00038 bool computeFlag = true;
00039 m_bBreakFlag = false;
00040 m_bReconditionFlag = true;
00041
00042
00043 NLLSMinimizable *nlls = dynamic_cast<NLLSMinimizable *>(minimizable);
00044 if(0 == nlls)
00045 {
00046 throw std::runtime_error("Minimizable is not a sum of squares!");
00047 }
00048
00049
00050 nParameters = nlls->GetNParameters();
00051 m_iNResiduals = nlls->GetNResiduals();
00052
00053 m_pdAlpha = new double *[nParameters];
00054 m_pdAlpha[0] = new double[nParameters*nParameters];
00055 for(int nPar = 1; nPar < nParameters; nPar++)
00056 {
00057 m_pdAlpha[nPar] = &(m_pdAlpha[0][nPar*nParameters]);
00058 }
00059 m_pdBeta = new double[nParameters];
00060 m_pdUpperBounds = new double[nParameters];
00061 m_pdLowerBounds = new double[nParameters];
00062
00063 this->SetBounds(parameters);
00064
00065
00066 double *deltaP = new double[nParameters];
00067 double *trialP = new double[nParameters];
00068
00069
00070 double chiSqOld = nlls->ObjectiveFunction(parameters);
00071 cout << "Starting cost of " << chiSqOld << endl;
00072 double chiSqNew = chiSqOld;
00073
00074 int nIterations = 0;
00075 while( (nIterations < m_iNIterations) && (!m_bBreakFlag))
00076 {
00077
00078 if(computeFlag){ComputeDerivativeInformation(parameters,nlls);}
00079
00080
00081
00082 for(i = 0; i < nParameters; i++)
00083 {
00084 m_pdAlpha[i][i] = (1.0 + m_dMarquardt)*m_pdAlpha[i][i];
00085 }
00086
00087 SVDSolveMarquardtSystem(deltaP);
00088
00089
00090
00091 for(i = 0; i < nParameters; i++)
00092 {
00093 m_pdAlpha[i][i] = m_pdAlpha[i][i]/(1.0 + m_dMarquardt);
00094 }
00095
00096
00097 m_pFilter->ForwardTransformation(parameters,nParameters);
00098 for(int j = 0; j < nParameters; j++)
00099 {
00100 trialP[j] = parameters[j] + deltaP[j];
00101 }
00102
00103 m_pFilter->BackwardTransformation(parameters,nParameters);
00104 m_pFilter->BackwardTransformation(trialP,nParameters);
00105
00106
00107 chiSqNew = nlls->ObjectiveFunction(trialP);
00108
00109
00110
00111
00112
00113
00114
00115
00116 if((chiSqNew >= chiSqOld) || (chiSqNew < 0.0))
00117 {
00118 m_dMarquardt = 10*m_dMarquardt;
00119 computeFlag = false;
00120 }
00121 else
00122 {
00123 cout << "Move accepted, new cost is " << chiSqNew << endl;
00124 double fracTol = (chiSqNew - chiSqOld)/chiSqOld;
00125
00126 for(i = 0; i < nParameters; i++)
00127 {
00128 parameters[i] = trialP[i];
00129 }
00130 chiSqOld = chiSqNew;
00131
00132
00133
00134 fstream *pftemp = new fstream("martemp.par",ios::out);
00135 *pftemp << "##################################################################" << endl;
00136 *pftemp << "# BEST PARAMETERS" << endl;
00137 *pftemp << "# COST : " << chiSqNew << endl;
00138 *pftemp << "##################################################################" << endl;
00139 for(i = 0; i < nParameters; i++)
00140 {
00141 *pftemp << parameters[i] << endl;
00142 }
00143 delete pftemp;
00144
00145
00146
00147 m_dMarquardt = 0.1*m_dMarquardt;
00148 computeFlag = true;
00149
00150 this->SetBounds(parameters);
00151
00152
00153 if(fabs(fracTol) < m_dChiSqTol)
00154 {
00155 cout << "Convergence on Chi-Squared criterion." << endl;
00156 m_bBreakFlag = true;
00157 }
00158 }
00159
00160 nIterations++;
00161 }
00162
00163
00164 delete [] deltaP;
00165 delete [] trialP;
00166 delete [] m_pdBeta;
00167 delete [] m_pdAlpha[0];
00168 delete [] m_pdAlpha;
00169
00170 return chiSqOld;
00171 }
00172
00174
00175
00176
00178
00179 void CPositiveDefiniteLevenbergMarquardtMinimizer::ComputeDerivativeInformation(double *parameters, NLLSMinimizable *nlls)
00180 {
00181 int i;
00182 double transparameter = 0.0;
00183 double saveparameter = 0.0;
00184 double gradNorm = 0.0;
00185 double *fxPlus = new double[m_iNResiduals];
00186 double *fx = new double[m_iNResiduals];
00187 double **jacobian = new double *[m_iNResiduals];
00188 jacobian[0] = new double[m_iNResiduals*nParameters];
00189 for(int nR = 1; nR < m_iNResiduals; nR++)
00190 {
00191 jacobian[nR] = &(jacobian[0][nR*nParameters]);
00192 }
00193
00194 double chiSq = nlls->ObjectiveFunction(parameters);
00195 for(int k = 0; k < m_iNResiduals; k++)
00196 {
00197 fx[k] = (nlls->GetResiduals())[k];
00198 }
00199
00200
00201 for(i = 0; i < nParameters; i++)
00202 {
00203
00204 saveparameter = parameters[i];
00205 transparameter = m_pFilter->Operator(parameters[i]);
00206
00207
00208
00209 double h = 1.0e-08;
00210 if(transparameter > 0.0)
00211 {
00212 h = pow(DBL_EPSILON,0.333333)*transparameter;
00213
00214 }
00215
00216
00217 parameters[i] = m_pFilter->OperatorInverse(transparameter + h);
00218 double chiSqPlus = nlls->ObjectiveFunction(parameters);
00219 for(int k = 0; k < m_iNResiduals; k++)
00220 {
00221 fxPlus[k] = (nlls->GetResiduals())[k];
00222 }
00223
00224
00225
00226 m_pdBeta[i] = -0.5*((chiSqPlus - chiSq)/h);
00227 gradNorm += m_pdBeta[i]*m_pdBeta[i];
00228
00229 parameters[i] = saveparameter;
00230
00231
00232 for(int j = 0; j < m_iNResiduals; j++)
00233 {
00234 double delta = (fxPlus[j] - fx[j])/h;
00235 jacobian[j][i] = -1*delta;
00236 }
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 gradNorm = sqrt(gradNorm);
00252 if(gradNorm < m_dGradTol)
00253 {
00254 cout << "Convergence on ||grad|| criterion." << endl;
00255 m_bBreakFlag = true;
00256 }
00257
00258
00259 for(i = 0; i < nParameters; i++)
00260 {
00261 for(int k = i; k < nParameters; k++)
00262 {
00263 m_pdAlpha[i][k] = 0.0;
00264 for(int j = 0; j < m_iNResiduals; j++)
00265 {
00266 m_pdAlpha[i][k] += jacobian[j][i]*jacobian[j][k];
00267 }
00268 m_pdAlpha[k][i] = m_pdAlpha[i][k];
00269 }
00270 }
00271
00272 delete [] fxPlus;
00273 delete [] fx;
00274 delete [] jacobian[0];
00275 delete [] jacobian;
00276
00277 cout << "Hessian calculated . . ." << endl;
00278
00279 return;
00280 }
00281
00283
00284
00285
00286
00288
00289
00290 void CPositiveDefiniteLevenbergMarquardtMinimizer::SVDSolveMarquardtSystem(double *deltaP)
00291 {
00292 int l,i;
00293
00294 char JOBU = 'A';
00295 char JOBVT = 'A';
00296 int M = nParameters;
00297 int N = nParameters;
00298
00299
00300 double *A = new double[nParameters*nParameters];
00301 int counter = 0;
00302 for(int j = 0; j < nParameters; j++)
00303 {
00304 deltaP[j] = 0.0;
00305 for(int i = 0; i < nParameters; i++)
00306 {
00307 A[counter] = m_pdAlpha[i][j];
00308 counter++;
00309 }
00310 }
00311
00312 double *D = new double[nParameters];
00313 double *E = new double[nParameters];
00314 double *TAUQ = new double[nParameters];
00315 double *TAUP = new double[nParameters];
00316
00317 double *PT = new double[nParameters*nParameters];
00318 double *Q = new double[nParameters*nParameters];
00319 double *ATEMP = new double[nParameters*nParameters];
00320
00321 int LDA = nParameters;
00322 double *S = new double[nParameters];
00323 int LDU = nParameters;
00324 int LDVT = nParameters;
00325 int LWORK = 5*M;
00326 double *WORK = new double[LWORK];
00327 int INFO = 0;
00328
00329
00330 DGEBRD(&M,&N,A,&LDA,D,E,TAUQ,TAUP,WORK,&LWORK,&INFO);
00331
00332
00333
00334 for(l = 0; l < nParameters*nParameters; l++)
00335 {
00336 ATEMP[l] = A[l];
00337 }
00338 char VECT = 'Q';
00339 int K = M;
00340 DORGBR(&VECT,&M,&N,&K,ATEMP,&LDA,TAUQ,WORK,&LWORK,&INFO);
00341
00342 for(l = 0; l < nParameters*nParameters; l++)
00343 {
00344 Q[l] = ATEMP[l];
00345 }
00346
00347 for(l = 0; l < nParameters*nParameters; l++)
00348 {
00349 ATEMP[l] = A[l];
00350 }
00351 VECT = 'P';
00352 DORGBR(&VECT,&M,&N,&K,ATEMP,&LDA,TAUP,WORK,&LWORK,&INFO);
00353
00354 for(l = 0; l < nParameters*nParameters; l++)
00355 {
00356 PT[l] = ATEMP[l];
00357 }
00358
00359
00360 char UPLO = 'U';
00361 int NCVT = nParameters;
00362 int NRU = nParameters;
00363 int NCC = 0;
00364 double *C = 0;
00365 int LDC = 1;
00366 DBDSQR(&UPLO,&N,&NCVT,&NRU,&NCC,D,E,PT,&LDVT,Q,&LDU,C,&LDC,WORK,&INFO);
00367 cout << "Matrix decomposed. Condition number of Hessian is " << D[0]/D[nParameters-1] << endl;
00368
00369
00370
00371 double cutoff = 1.0e-06*D[0];
00372 for(i = 0; i < nParameters; i++)
00373 {
00374 if(D[i] < cutoff) {D[i] = 0;}
00375 else {D[i] = 1/D[i];}
00376 }
00377
00378
00379
00380 for(i = 0; i < nParameters; i++)
00381 {
00382 for(int j = 0; j < nParameters; j++)
00383 {
00384 deltaP[i] += Q[i*nParameters + j]*m_pdBeta[j];
00385 }
00386 }
00387
00388 for(i = 0; i < nParameters; i++)
00389 {
00390 deltaP[i] = deltaP[i]*D[i];
00391 }
00392
00393 for(i = 0; i < nParameters; i++)
00394 {
00395 S[i] = 0.0;
00396 for(int j = 0; j < nParameters; j++)
00397 {
00398 S[i] += PT[i*nParameters + j]*deltaP[j];
00399 }
00400 }
00401
00402 for(i = 0; i < nParameters; i++)
00403 {
00404 deltaP[i] = S[i];
00405 }
00406
00407 delete [] A;
00408 delete [] ATEMP;
00409 delete [] TAUQ;
00410 delete [] TAUP;
00411 delete [] Q;
00412 delete [] PT;
00413 delete [] D;
00414 delete [] E;
00415 delete [] S;
00416 delete [] WORK;
00417 }
00418
00419 void CPositiveDefiniteLevenbergMarquardtMinimizer::LUSolveMarquardtSystem(double *deltaP)
00420 {
00421
00422 char UPLO = 'U';
00423 char TRANS = 'N';
00424
00425 int INFO=0;
00426
00427 int N = nParameters;
00428 int M = nParameters;
00429
00430
00431 int LDA = nParameters;
00432 int LDB = nParameters;
00433
00434 int NRHS = 1;
00435
00436
00437 double *B = new double[nParameters];
00438
00439
00440
00441 double *A = new double[nParameters*nParameters];
00442 int *IPIV = new int[nParameters];
00443 int counter = 0;
00444 for(int j = 0; j < nParameters; j++)
00445 {
00446 B[j] = m_pdBeta[j];
00447 for(int i = 0; i < nParameters; i++)
00448 {
00449 A[counter] = m_pdAlpha[i][j];
00450 counter++;
00451 }
00452 }
00453
00454
00455 DGETRF(&M,&N,A,&LDA,IPIV,&INFO);
00456 if(INFO > 0)
00457 {
00458 m_bReconditionFlag = true;
00459 cout << "Matrix singularity suspected, attempting to recondition . . . " << endl;
00460 }
00461 else
00462 {
00463 m_bReconditionFlag = false;
00464
00465 DGETRS(&TRANS,&N,&NRHS,A,&LDA,IPIV,B,&LDB,&INFO);
00466
00467 for(int i = 0; i < nParameters; i++)
00468 {
00469 deltaP[i] = B[i];
00470 }
00471 }
00472
00473
00474 delete [] A;
00475 delete [] B;
00476 delete [] IPIV;
00477 }
00478
00479 void CPositiveDefiniteLevenbergMarquardtMinimizer::SetBounds(double *parameters)
00480 {
00481 for(int i = 0; i < nParameters; i++)
00482 {
00483 m_pdLowerBounds[i] = (1.0/100.0)*parameters[i];
00484 m_pdUpperBounds[i] = 100.0*parameters[i];
00485 }
00486 }
00487
00488 void CPositiveDefiniteLevenbergMarquardtMinimizer::CheckBounds(double *parameters)
00489 {
00490 for(int i = 0; i < nParameters; i++)
00491 {
00492 if(parameters[i] < m_pdLowerBounds[i])
00493 {
00494 parameters[i] = m_pdLowerBounds[i];
00495 }
00496 else if(parameters[i] > m_pdUpperBounds[i])
00497 {
00498 parameters[i] = m_pdUpperBounds[i];
00499 }
00500 }
00501 }