00001 #include "NelderMeadSimplexMinimizer.h"
00002
00003 CNelderMeadSimplexMinimizer::CNelderMeadSimplexMinimizer()
00004 {
00005 }
00006
00007 CNelderMeadSimplexMinimizer::CNelderMeadSimplexMinimizer(CParameterFilter *pFilter, int nIterations, double lambda, double tol)
00008 {
00009 m_pFilter = pFilter;
00010 m_dLambda = 1.0;
00011 m_dTol = 1.0e-06;
00012 m_pMO = new CMatrixOperations();
00013 m_iNIterations = nIterations;
00014 }
00015
00016 CNelderMeadSimplexMinimizer::~CNelderMeadSimplexMinimizer(void)
00017 {
00018 }
00019
00020 void CNelderMeadSimplexMinimizer::InitializeSimplex(double *parameters)
00021 {
00022 int i;
00023 m_pFilter->ForwardTransformation(parameters,nParameters);
00024
00025 m_pMO->ElementCopy(parameters,m_vpdSimplex[0],nParameters);
00026
00027 for(i = 1; i < m_vpdSimplex.size(); i++)
00028 {
00029 m_pMO->ElementCopy(parameters,m_vpdSimplex[i],nParameters);
00030 m_vpdSimplex[i][i-1] += m_dLambda;
00031 }
00032 m_pFilter->BackwardTransformation(parameters,nParameters);
00033 }
00034
00035 void CNelderMeadSimplexMinimizer::EvaluateSimplex()
00036 {
00037 int i;
00038 for(i = 0; i < m_vpdSimplex.size(); i++)
00039 {
00040 m_pFilter->BackwardTransformation(m_vpdSimplex[i],nParameters);
00041 m_pdSimplexCosts[i] = m_pMinimizable->ObjectiveFunction(m_vpdSimplex[i]);
00042 m_pFilter->ForwardTransformation(m_vpdSimplex[i],nParameters);
00043 }
00044 }
00045
00046 void CNelderMeadSimplexMinimizer::ComputePointSum()
00047 {
00048 int i,j;
00049
00050 for(j = 0; j < nParameters; j++)
00051 {
00052 double sum = 0.0;
00053 for(i = 0; i < m_vpdSimplex.size(); i++)
00054 {
00055 sum += m_vpdSimplex[i][j];
00056 }
00057 m_pdPointSum[j] = sum;
00058 }
00059 }
00060
00061 double CNelderMeadSimplexMinimizer::TryPoint(double exfac)
00062 {
00063 int i,j;
00064 double *pTrial = new double[nParameters];
00065 double fac1 = (1.0 - exfac)/nParameters;
00066 double fac2 = fac1 - exfac;
00067 for(j = 0; j < nParameters; j++)
00068 {
00069
00070 pTrial[j] = m_pdPointSum[j]*fac1 - m_vpdSimplex[m_iHi][j]*fac2;
00071 }
00072
00073 m_pFilter->BackwardTransformation(pTrial,nParameters);
00074 double costTrial = m_pMinimizable->ObjectiveFunction(pTrial);
00075 m_pFilter->ForwardTransformation(pTrial,nParameters);
00076
00077 if(costTrial < m_pdSimplexCosts[m_iHi])
00078 {
00079 m_pdSimplexCosts[m_iHi] = costTrial;
00080 for(j = 0; j < nParameters; j++)
00081 {
00082 m_pdPointSum[j] += pTrial[j] - m_vpdSimplex[m_iHi][j];
00083 m_vpdSimplex[m_iHi][j] = pTrial[j];
00084 }
00085 }
00086 delete [] pTrial;
00087
00088 return costTrial;
00089 }
00090
00091 double CNelderMeadSimplexMinimizer::Minimize(double *parameters, Minimizable *minimizable)
00092 {
00093 int i,j,iteration;
00094 double cTry;
00095 double cBest;
00096 bool restartFlag = false;
00097 m_pMinimizable = minimizable;
00098 nParameters = m_pMinimizable->GetNParameters();
00099
00100
00101
00102 for(i = 0; i < nParameters + 1; i++)
00103 {
00104 m_vpdSimplex.push_back(new double[nParameters]);
00105 }
00106 m_pdSimplexCosts = new double[nParameters + 1];
00107 m_pdPointSum = new double[nParameters];
00108
00109
00110 this->InitializeSimplex(parameters);
00111
00112 this->EvaluateSimplex();
00113
00114 this->ComputePointSum();
00115
00116 iteration = 0;
00117
00118 while(iteration < m_iNIterations)
00119 {
00120
00121 m_iLo = 0;
00122 if(m_pdSimplexCosts[1] > m_pdSimplexCosts[0])
00123 {
00124 m_iHi = 1;
00125 m_iNextHi = 0;
00126 }
00127 else
00128 {
00129 m_iHi = 0;
00130 m_iNextHi = 1;
00131 }
00132 for(i = 0; i < nParameters + 1; i++)
00133 {
00134 if(m_pdSimplexCosts[i] <= m_pdSimplexCosts[m_iLo]) {m_iLo = i;}
00135 if(m_pdSimplexCosts[i] > m_pdSimplexCosts[m_iHi])
00136 {
00137 m_iNextHi = m_iHi;
00138 m_iHi = i;
00139 }
00140 else if((m_pdSimplexCosts[i] > m_pdSimplexCosts[m_iNextHi]) && (i != m_iHi))
00141 {
00142 m_iHi = i;
00143 }
00144 }
00145
00146 cout << "Best cost after iteration " << iteration << " : " << m_pdSimplexCosts[m_iLo] << endl;
00147
00148
00149
00150 if(CheckFuncTol())
00151 {
00152 if(restartFlag == true)
00153 {
00154 cout << "Relative Function Tolerance Achieved, Terminating . . ." << endl;
00155 break;
00156 }
00157 else
00158 {
00159 cout << "Minimum suspected, restarting . . ." << endl;
00160 m_pFilter->BackwardTransformation(m_vpdSimplex[m_iLo],nParameters);
00161 this->InitializeSimplex(m_vpdSimplex[m_iLo]);
00162 this->EvaluateSimplex();
00163 this->ComputePointSum();
00164 restartFlag = true;
00165 continue;
00166 }
00167 }
00168
00169 cTry = TryPoint(-1.0);
00170 if(cTry <= m_pdSimplexCosts[m_iLo])
00171 {
00172
00173 cout << "\tTrying additional extrapolation . . . " << endl;
00174
00175 cTry = TryPoint(2.0);
00176 }
00177 else if(cTry >= m_pdSimplexCosts[m_iNextHi])
00178 {
00179
00180 double cSave = m_pdSimplexCosts[m_iHi];
00181 cout << "\tTrying intermediate extrapolation . . ." << endl;
00182 cTry = TryPoint(0.5);
00183 if(cTry >= cSave)
00184 {
00185 cout << "\tContracting around lowest point . . ." << endl;
00186
00187 for(i = 0; i < m_vpdSimplex.size(); i++)
00188 {
00189 if(i != m_iLo)
00190 {
00191 for(j = 0; j < nParameters; j++)
00192 {
00193 double Q = 0.5*(m_vpdSimplex[i][j] + m_vpdSimplex[m_iLo][j]);
00194 m_vpdSimplex[i][j] = Q;
00195 m_pdPointSum[j] = Q;
00196 }
00197 m_pFilter->BackwardTransformation(m_pdPointSum,nParameters);
00198 cTry = m_pMinimizable->ObjectiveFunction(m_pdPointSum);
00199 m_pFilter->ForwardTransformation(m_pdPointSum,nParameters);
00200 }
00201 }
00202
00203
00204 this->ComputePointSum();
00205 }
00206 }
00207
00208 iteration++;
00209
00210 if((iteration % 20) == 0)
00211 {
00212
00213 cout << "Writing parameters to file . . ." << endl;
00214
00215 fstream *pftemp = new fstream("nmtemp.par",ios::out);
00216 *pftemp << "##################################################################" << endl;
00217 *pftemp << "# BEST PARAMETERS" << endl;
00218 *pftemp << "# COST : " << m_pdSimplexCosts[m_iLo] << endl;
00219 *pftemp << "##################################################################" << endl;
00220 int pcount;
00221 for(pcount = 0; pcount < nParameters; pcount++)
00222 {
00223 *pftemp << setprecision(10) << m_pFilter->OperatorInverse(m_vpdSimplex[m_iLo][pcount]) << endl;
00224 }
00225 delete pftemp;
00226 }
00227 }
00228
00229
00230 for(j = 0; j < nParameters; j++)
00231 {
00232 parameters[j] = m_pFilter->OperatorInverse(m_vpdSimplex[m_iLo][j]);
00233 }
00234 cBest = m_pdSimplexCosts[m_iLo];
00235
00236 delete [] m_pdPointSum;
00237 delete [] m_pdSimplexCosts;
00238 for(i = 0; i < m_vpdSimplex.size(); i++)
00239 {
00240 delete [] m_vpdSimplex[i];
00241 }
00242
00243 return cBest;
00244 }
00245
00246 bool CNelderMeadSimplexMinimizer::CheckFuncTol()
00247 {
00248 double num = 2.0*(fabs(m_pdSimplexCosts[m_iHi] - m_pdSimplexCosts[m_iLo]));
00249 double den = fabs(m_pdSimplexCosts[m_iHi]) + fabs(m_pdSimplexCosts[m_iLo]) + 1.0e-10;
00250 double fracTol = num/den;
00251
00252 if(fracTol < m_dTol)
00253 {
00254 return true;
00255 }
00256 return false;
00257 }