• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

D:/LIACS/mies/SerialES/NSGA_II.cpp

Go to the documentation of this file.
00001 #include "NSGA_II.h"
00002 
00003 //------------------------------------------------------------------------------
00004 // Class NSGA_II
00005 //-------------------------------------------------
00006 // Public Members
00007 
00008 NSGA_II::NSGA_II(unsigned n_f__) 
00009 { 
00010 #ifdef DEBUG
00011   cout << "NSGA_II::NSGA_II()" << endl;
00012 #endif
00013 
00014   selectDimension = 3;
00015   selectFunction.clear();
00016 
00017   for (unsigned i = 0; i < selectDimension; i++)
00018     selectFunction.push_back(i);
00019 
00020   n_f_ = n_f__;
00021   nadir.resize(n_f_);
00022   ideal.resize(n_f_);
00023 
00024   dpSelection = false;
00025   fixedNadirIdeal = false;
00026 }
00027 
00028 /* Select mu Individuals from O and optionally P to form new population P, 
00029  * using multiobjective selection scheme as proposed for NSGA-II by Deb, 2000
00030  */
00031 void NSGA_II::select(vector<Individual*>& P, vector<Individual*>& O, unsigned mu, unsigned kappa, unsigned lambda, vector<int>& direction, 
00032                       vector<double>& bestF)
00033 {
00034 #ifdef DEBUG
00035   cout << "NSGA_II::select()" << endl;
00036 #endif
00037 
00038   /* Partition population into fronts */
00039   vector<Individual*> Q;
00040   int size = 0;
00041   for (unsigned i = 0; i < lambda; i++)
00042   {
00043     if (O[i] != NULL)     
00044     {
00045       Q.push_back(O[i]);
00046       O[i] = NULL;
00047       size++;
00048     }
00049   }
00050 
00051   /* Select Individuals from parent population P that do not exceed maximum life span */
00052   for (unsigned i = 0; i < mu; i++)
00053   {
00054     if (P[i]->age <= kappa)
00055     {   
00056       Q.push_back(P[i]);
00057       P[i] = NULL;
00058       size++;
00059     } 
00060   }
00061   
00062   /* Cleanup unused Individuals from parent population P */
00063   for (unsigned i = 0; i < mu; i++)
00064   {  
00065     delete P[i];
00066     P[i] = NULL;
00067   }
00068 
00069   vector<vector<int> > front;
00070   fastNondominatedSort(Q, front, direction, bestF); 
00071 
00072   /* Select Individuals to form new population: */
00073   /* 1) try using dominating points selection */
00074   bool ready = false;
00075   if (dpSelection) 
00076   {
00077     vector<int> indices; // Indices of Individuals in Q
00078     for (int i = 0; i < size; i++)
00079       indices.push_back(i);       
00080 
00081     /* Sort indices based on number of dominating Individuals, in descending order */
00082     quickSort(indices, 0, size-1, &Q, -1, NULL);
00083 
00084     /* Determine whether enough Individuals can be discarded using dp selection: */
00085     /* count number of dominated Individuals */
00086     int numDomIndividuals = 0;
00087     for (int i = 0; i < size; i++)
00088     {
00089       /* Stop counting at first non-dominated Individual */
00090       if (Q[indices[i]]->numDominating == 0)
00091         break;
00092       
00093       numDomIndividuals++;
00094     }
00095 
00096     int numToDiscard = size - mu;
00097     if (numDomIndividuals >= numToDiscard)  
00098     {
00099 #ifdef DEBUG
00100   cout << "NSGA_II::select(), using dominating points selection" << endl;
00101 #endif
00102 
00103       /* Copy best Individuals to new population (best are at the back of indices) */
00104       P.clear();            
00105       for (unsigned i = 0; i < mu; i++)
00106       {
00107         P.push_back(Q[indices[size-1 - i]]);         
00108         Q[indices[size-1 - i]] = NULL;
00109       }
00110 
00111       ready = true; 
00112     }   
00113   }
00114   
00115   /* 2) or use selection based on fronts */
00116   if (!ready)
00117   {
00118 #ifdef DEBUG
00119   cout << "NSGA_II::select(), using front based selection" << endl;
00120 #endif
00121 
00122     int PSize, frontSize, remaining, numFronts = front.size();
00123     P.clear();
00124     for (int i = 0; i < numFronts; i++)
00125     {
00126       PSize = P.size();
00127       frontSize = front[i].size();
00128 
00129       if ((unsigned) PSize == mu)
00130         break;
00131 
00132       if ((unsigned) (PSize + frontSize) <= mu) // Entire front still fits in population
00133       {     
00134         remaining = frontSize;
00135       }
00136       else                         // Use a metric to discriminate between Individuals 
00137       {                            // in same front, sort in descending order
00138         remaining = mu - PSize;
00139 
00140         if (selectDimension > 1)
00141           frontSort(front[i], Q, direction);
00142       }
00143 
00144       /* Add Individuals from front[i] to population */
00145       for (int j = 0; j < remaining; j++)
00146       {
00147         P.push_back(Q[front[i][j]]);
00148         Q[front[i][j]] = NULL;
00149       }
00150     }
00151   }
00152 
00153   /* Cleanup unused Individuals */
00154   for (int i = 0; i < size; i++)
00155     delete Q[i];
00156 }
00157 
00158 //------------------------------------------------------------------------------
00159 // Class NSGA_II
00160 //-------------------------------------------------
00161 // Protected Members
00162 
00163 /* Divide Individuals from O and optionally P in fronts based on domination */
00164 void NSGA_II::fastNondominatedSort(vector<Individual*>& Q, vector<vector<int> >& front, vector<int>& direction, vector<double>& bestF)
00165 {
00166 #ifdef DEBUG
00167   cout << "NSGA_II::fastNondominatedSort()" << endl;
00168 #endif
00169 
00170   int size = Q.size();
00171   unsigned tempNumDom;
00172   map<int, vector<int> > dominates; 
00173   map<int, unsigned> numDominating;
00174   vector<int> tempDom, tempFront;
00175   MOComparison result;
00176 
00177   for (int i = 0; i < size; i++)
00178   {
00179     tempDom.clear();
00180     tempNumDom = 0;
00181 
00182     for (int j = 0; j < size; j++)
00183     {
00184       if (i == j)
00185         continue;
00186 
00187       result = compare(Q[i], Q[j], direction, bestF, false, false); 
00188 
00189       if (result == _Dominating)
00190         tempDom.push_back(j); // Add j to Individuals which i dominates
00191       else if (result == _Dominated)
00192         tempNumDom++; // Increment number of Individuals by which i is dominated
00193     }
00194 
00195     /* No Individual dominates i, so add i to first front */
00196     if (tempNumDom == 0)
00197       tempFront.push_back(i);       
00198 
00199     dominates[i] = tempDom; // Individuals which i dominates
00200     numDominating[i] = Q[i]->numDominating = tempNumDom; // Number of Individuals by which i is dominated
00201   }
00202 
00203   front.push_back(tempFront); // Insert first front into vector front
00204 
00205   int k = 0, frontSize = front[0].size();
00206   while (!frontSize == 0)
00207   {
00208     /* Initialize new front */
00209     tempFront.clear();
00210 
00211     /* For each Individual j dominated by Individual i in the current front k: */
00212     for (int i = 0; i < frontSize; i++)
00213     {
00214       size = dominates[front[k][i]].size();         
00215       for (int j = 0; j < size; j++)
00216       {
00217         numDominating[dominates[front[k][i]][j]]--; // Decrease number of Individuals by which j is dominated
00218 
00219         /* If j no longer dominated when not considering the current front: */ 
00220         if (numDominating[dominates[front[k][i]][j]] == 0)
00221           tempFront.push_back(dominates[front[k][i]][j]); // Add j to the new front
00222       }
00223     }
00224 
00225     k++;
00226     front.push_back(tempFront);
00227     frontSize = front[k].size();
00228   }
00229 
00230   front.pop_back(); // Remove empty last front
00231 }
00232 
00233 /* Determine domination relationship between A and B, or 
00234  * determine best or worst values */
00235 MOComparison NSGA_II::compare(Individual* A, Individual* B, vector<int>& direction, vector<double>& bestWorstF, bool determineValues, bool worst)
00236 {
00237   bool better = false,
00238        worse  = false;
00239 
00240   /* Compare all fitness values (i.e., objective values) */
00241   for (unsigned i = 0; i < selectDimension; i++)
00242   {
00243     if (direction[selectFunction[i]] == 1 || (direction[selectFunction[i]] == -1 && worst)) // Objective to be maximized
00244     {
00245       if (A->F[selectFunction[i]] > B->F[selectFunction[i]])
00246       {
00247         better = true;
00248 
00249         if (A->F[selectFunction[i]] > bestWorstF[selectFunction[i]] && (A->feasible || determineValues))
00250           bestWorstF[selectFunction[i]] = A->F[selectFunction[i]];      
00251       }
00252       else if (A->F[selectFunction[i]] < B->F[selectFunction[i]])
00253       {
00254         worse = true;
00255 
00256         if (B->F[selectFunction[i]] > bestWorstF[selectFunction[i]] && (B->feasible || determineValues))
00257           bestWorstF[selectFunction[i]] = B->F[selectFunction[i]];      
00258       }
00259       else
00260       {
00261         if (A->F[selectFunction[i]] > bestWorstF[selectFunction[i]] && (A->feasible || determineValues))
00262           bestWorstF[selectFunction[i]] = A->F[selectFunction[i]];      
00263       }
00264     }
00265     else if (direction[selectFunction[i]] == -1 || (direction[selectFunction[i]] == 1 && worst)) // Objective to be minimized
00266     {
00267       if (A->F[selectFunction[i]] < B->F[selectFunction[i]])
00268       {
00269         better = true;
00270 
00271         if (A->F[selectFunction[i]] < bestWorstF[selectFunction[i]] && (A->feasible || determineValues))
00272           bestWorstF[selectFunction[i]] = A->F[selectFunction[i]];      
00273       }
00274       else if (A->F[selectFunction[i]] > B->F[selectFunction[i]])
00275       {
00276         worse = true;
00277 
00278         if (B->F[selectFunction[i]] < bestWorstF[selectFunction[i]] && (B->feasible || determineValues))
00279           bestWorstF[selectFunction[i]] = B->F[selectFunction[i]];      
00280       }
00281       else
00282       {
00283         if (A->F[selectFunction[i]] < bestWorstF[selectFunction[i]] && (A->feasible || determineValues))
00284           bestWorstF[selectFunction[i]] = A->F[selectFunction[i]];      
00285       }
00286     }
00287 
00288     if (better && worse && !determineValues)
00289       break;
00290   }
00291 
00292   if (worse) 
00293   {
00294     if (better)
00295       return _Nondominated;
00296     else
00297       return _Dominated;
00298   }
00299   else 
00300   {
00301     if (better)
00302       return _Dominating;
00303     else
00304       return _Equals;
00305   }
00306 }
00307 
00308 /* Sort Individuals within same front: nD crowding distance sorting (see NSGA-II by Deb, 2000) */
00309 void NSGA_II::frontSort(vector<int>& currFront, vector<Individual*>& Q, vector<int>& direction)
00310 {
00311 #ifdef DEBUG
00312   cout << "NSGA_II::frontSort(), nD crowding distance sorting" << endl;
00313 #endif
00314 
00315   int frontSize = currFront.size();
00316   map<int, double> distance;
00317   double scale;
00318 
00319   for (int i = 0; i < frontSize; i++)
00320     distance[currFront[i]] = 0;
00321 
00322   /* Sort for each fitness value (i.e., objective value) */
00323   for (unsigned i = 0; i < selectDimension; i++)
00324   {
00325     /* Sort front on objective i, in descending order */
00326     quickSort(currFront, 0, frontSize-1, &Q, selectFunction[i], NULL); 
00327 
00328     /* Boundary points are always kept */
00329     distance[currFront[0]] = DBL_MAX;
00330     distance[currFront[frontSize-1]] = DBL_MAX;
00331 
00332     /* Determine scale for normalizing crowding distance values */
00333     if (fixedNadirIdeal)
00334     { 
00335       // f_max - f_min      
00336       if (direction[selectFunction[i]] == 1)
00337         scale = ideal[selectFunction[i]] - nadir[selectFunction[i]];  
00338       else           
00339         scale = nadir[selectFunction[i]] - ideal[selectFunction[i]];    
00340     }
00341     else
00342       scale = Q[currFront[0]]->F[selectFunction[i]] - Q[currFront[frontSize-1]]->F[selectFunction[i]]; // f_max - f_min, of currFront  
00343     
00344     /* For rest of the points, determine crowding distance contribution based on objective i */
00345     for (int j = 1; j < frontSize-1; j++) 
00346     {
00347       if (scale != 0)       
00348         distance[currFront[j]] += (Q[currFront[j-1]]->F[selectFunction[i]] - Q[currFront[j+1]]->F[selectFunction[i]]) / scale;  // Large neighbour minus small neighbour
00349     }
00350   }
00351 
00352   /* Sort front index currFront on crowding distance, in descending order */
00353   quickSort(currFront, 0, frontSize-1, NULL, -1, &distance);
00354 }
00355 
00356 /* Sort Individuals in front based on objective or number of dominating Individuals or crowding distance, in descending order */
00357 void NSGA_II::quickSort(vector<int>& currFront, int top, int bottom, 
00358                                   vector<Individual*>* Q, int objective, map<int, double>* distance)
00359 {
00360 #ifdef DEBUG
00361   cout << "NSGA_II::quickSort(), sorting on " << ((Q != NULL) ? ((objective >= 0) ? "objective " + itos(objective) : "numDominating") 
00362                                                     : "distance") << endl;
00363 #endif
00364 
00365   /* top = subscript of beginning of vector being considered
00366    * bottom = subscript of end of vector being considered
00367    */
00368   int middle;
00369   if (top < bottom)
00370   {
00371     middle = partition(currFront, top, bottom, Q, objective, distance);
00372     quickSort(currFront, top, middle, Q, objective, distance); // Sort top partition
00373     quickSort(currFront, middle+1, bottom, Q, objective, distance); // Sort bottom partition
00374   }
00375 }
00376 
00377 int NSGA_II::partition(vector<int>& currFront, int top, int bottom, 
00378                                  vector<Individual*>* Q, int objective, map<int, double>* distance)
00379 {
00380 #ifdef DEBUG
00381   cout << "NSGA_II::partition(), top=" << top << ", bottom=" << bottom << endl;
00382 #endif
00383 
00384   int temp, 
00385       i = top - 1, 
00386       j = bottom + 1;
00387 
00388   double x = (Q != NULL) ? ((objective >= 0) ? Q->at(currFront[top])->F[objective] : Q->at(currFront[top])->numDominating) 
00389                : distance->find(currFront[top])->second;
00390 
00391   do
00392   {
00393     do     
00394     {
00395       j--;
00396     } while (x > ((Q != NULL) ? ((objective >= 0) ? Q->at(currFront[j])->F[objective] : Q->at(currFront[j])->numDominating) 
00397                     : distance->find(currFront[j])->second));
00398 
00399     do          
00400     {
00401       i++;
00402     } while (x < ((Q != NULL) ? ((objective >= 0) ? Q->at(currFront[i])->F[objective] : Q->at(currFront[i])->numDominating) 
00403                     : distance->find(currFront[i])->second));
00404 
00405     if (i < j)
00406     {     
00407       /* Switch elements at positions i and j */
00408       temp = currFront[i];    
00409       currFront[i] = currFront[j];
00410       currFront[j] = temp;
00411     }
00412   } while (i < j);    
00413   
00414   /* Return middle index */
00415   return j;           
00416 }
00417 
00418 /* Determine Nadir and Ideal point for Individuals in currFront */
00419 void NSGA_II::determineNadirIdeal(vector<int>& currFront, int frontSize, vector<Individual*>& Q, vector<int>& direction)
00420 {
00421 #ifdef DEBUG
00422   cout << "NSGA_II::determineNadirIdeal()" << endl;
00423 #endif
00424 
00425   if (fixedNadirIdeal)
00426     return;
00427 
00428   /* Reset Ideal and Nadir point */
00429   for (unsigned i = 0; i < selectDimension; i++)
00430   {         
00431     if (direction[selectFunction[i]] == 1)
00432     {
00433       ideal[selectFunction[i]] = 0;
00434       nadir[selectFunction[i]] = DBL_MAX;
00435     }
00436     else
00437     {
00438       ideal[selectFunction[i]] = DBL_MAX;
00439       nadir[selectFunction[i]] = 0;
00440     }
00441   } 
00442 
00443   /* Determine Ideal and Nadir point by comparing all Individuals in currFront and respectively selecting best or worst value occurring per objective */
00444   for (int i = 0; i < frontSize; i++)
00445   {
00446     for (int j = 0; j < frontSize; j++) 
00447     {
00448       if (i == j)
00449         continue;
00450 
00451       compare(Q[currFront[i]], Q[currFront[j]], direction, ideal, true, false);      
00452       compare(Q[currFront[i]], Q[currFront[j]], direction, nadir, true, true);      
00453     }
00454   }
00455 }
00456 

Generated on Tue Oct 4 2011 16:25:19 for WDN by  doxygen 1.7.2