Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

NelderMeadSimplexMinimizer.cpp

Go to the documentation of this file.
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         // fill in the initial point
00025         m_pMO->ElementCopy(parameters,m_vpdSimplex[0],nParameters);
00026         // fill in the rest
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                 // extrapolate
00070                 pTrial[j] = m_pdPointSum[j]*fac1 - m_vpdSimplex[m_iHi][j]*fac2;
00071         }
00072         // try the point
00073         m_pFilter->BackwardTransformation(pTrial,nParameters);
00074         double costTrial = m_pMinimizable->ObjectiveFunction(pTrial);
00075         m_pFilter->ForwardTransformation(pTrial,nParameters);
00076         // if it's less than the highest point, accept the point
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         // allocate memory
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         // initialize simplex
00110         this->InitializeSimplex(parameters);
00111         // evaluate costs
00112         this->EvaluateSimplex();
00113         // compute initial pointsum
00114         this->ComputePointSum();
00115         
00116         iteration = 0;
00117         // loop while not converged (outer loop) and less than max iterations
00118         while(iteration < m_iNIterations)
00119         {
00120                 // find the highest, next highest, and lowest points
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                 } // end hi, lo loop
00145 
00146                 cout << "Best cost after iteration " << iteration << " : " << m_pdSimplexCosts[m_iLo] << endl; 
00147                 
00148                 // check the function tolerance to see if we jump out
00149                 // XXX remember a restart!
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                 // reflect from the high point - this starts a new iteration
00169                 cTry = TryPoint(-1.0);
00170                 if(cTry <= m_pdSimplexCosts[m_iLo])
00171                 {
00172                         // XXX debug
00173                         cout << "\tTrying additional extrapolation . . . " << endl;
00174                         // result is better than the best point, so try an additional extrapolation
00175                         cTry = TryPoint(2.0);
00176                 }
00177                 else if(cTry >= m_pdSimplexCosts[m_iNextHi])
00178                 {
00179                         // point is worse than the second highest, so try to find an intermediate
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                                 // can't get rid of bad point, contract around the lowest point
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                                 // recompute the PointSum
00204                                 this->ComputePointSum();
00205                         }
00206                 }
00207                 
00208                 iteration++;
00209                 // check to see if we should write the best parameters we've found
00210                 if((iteration % 20) == 0)
00211                 {
00212                         // XXX debug
00213                         cout << "Writing parameters to file . . ." << endl;
00214                         // write best parameters
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         }       // end while loop
00228         
00229         // put best parameters, unfiltered, into parameters vector
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         // now clear memory
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 }

Generated on Mon Nov 3 09:38:02 2003 by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002