static PyObject* selNSGA2(PyObject *self, PyObject *args){ /* Args[0] : Individual list * Args[1] : Number of individuals wanted in output * Return : k selected individuals from input individual list */ PyObject *lListIndv = PyTuple_GetItem(args, 0); #ifdef PY3K unsigned long k = (unsigned long)PyLong_AS_LONG(PyTuple_GetItem(args, 1)); #else unsigned int k = (unsigned int)PyInt_AS_LONG(PyTuple_GetItem(args, 1)); #endif PyObject *lListSelect = PyList_New(0); unsigned int lLenListIndv = (unsigned int)PyList_Size(lListIndv); unsigned int lNbrObjectives = (unsigned int)PyTuple_Size(PyObject_GetAttrString(PyObject_GetAttrString(PyList_GetItem(lListIndv,0), "fitness"), "values")); if(k == 0) return lListSelect; // First : copy fitness values into an std::vector<std::vector<double> > // First vector index is used to identify individuals // Second vector index represents an objective std::vector<std::vector<double> > lPopFit(lLenListIndv, std::vector<double>(lNbrObjectives,0.)); for(unsigned int i = 0; i < lLenListIndv; i++){ for(unsigned int j = 0; j < lNbrObjectives; j++) lPopFit[i][j] = PyFloat_AS_DOUBLE(PyTuple_GetItem(PyObject_GetAttrString(PyObject_GetAttrString(PyList_GetItem(lListIndv,i), "fitness"), "wvalues"), j)); } unsigned int lParetoSorted = 0; unsigned int lFrontIndex = 0; std::vector<std::vector<unsigned int> > lParetoFront(1, std::vector<unsigned int>(0)); std::vector<unsigned int> lDominating(lLenListIndv, 0); std::vector<std::vector<unsigned int> > lDominatedInds(lLenListIndv, std::vector<unsigned int>(0)); // Rank first pareto front for(unsigned int i = 0; i < lLenListIndv; i++){ for(unsigned int j = i+1; j < lLenListIndv; j++){ if(isDominated(lPopFit[j], lPopFit[i])){ lDominating[j]++; lDominatedInds[i].push_back(j); } else if(isDominated(lPopFit[i], lPopFit[j])){ lDominating[i]++; lDominatedInds[j].push_back(i); } } if(lDominating[i] == 0){ lParetoFront[lFrontIndex].push_back(i); lParetoSorted++; } } // Rank other pareto fronts, until we reach the *k* limit while(lParetoSorted < k && lParetoSorted < lLenListIndv){ lFrontIndex++; lParetoFront.push_back(std::vector<unsigned int>(0)); for(unsigned int i = 0; i < lParetoFront[lFrontIndex-1].size(); i++){ unsigned int lIndiceP = lParetoFront[lFrontIndex-1][i]; for(unsigned int j = 0; j < lDominatedInds[lIndiceP].size(); j++){ unsigned int lIndiceD = lDominatedInds[lIndiceP][j]; if(--lDominating[lIndiceD] == 0){ lParetoFront[lFrontIndex].push_back(lIndiceD); lParetoSorted++; } } } } // Append individuals from pareto ranking until we reach the limit for(unsigned int i = 0; i < lParetoFront.size(); i++){ if(PyList_Size(lListSelect)+lParetoFront[i].size() <= k){ for(unsigned int j = 0; j < lParetoFront[i].size(); j++) PyList_Append(lListSelect, PyList_GetItem(lListIndv,lParetoFront[i][j])); } else{ break; } } // Crowding distance on the last front if(PyList_Size(lListSelect) == k) return lListSelect; FitComp lCmpIndvObj; std::vector<unsigned int> lLastParetoFront = lParetoFront.back(); std::vector<std::pair<double, unsigned int> > lDistances(0); std::vector<std::pair<std::vector<double>, unsigned int> > lCrowdingList(0); double lInfinity = std::numeric_limits<double>::infinity(); // Reserve sufficient memory for the subsequent push_back lDistances.reserve(lLastParetoFront.size()); lCrowdingList.reserve(lLastParetoFront.size()); for(unsigned int i = 0; i < lLastParetoFront.size(); i++){ // Push initial distance (0.0) and individual index in lPopFit and lListIndv for each individual lDistances.push_back(std::pair<double, unsigned int>(0., lLastParetoFront[i])); // Push fitness and individual index in lDistances for each individual lCrowdingList.push_back(std::pair<std::vector<double>, unsigned int>(lPopFit[lLastParetoFront[i]],i)); } for(unsigned int i = 0; i < lNbrObjectives; i++){ // For each objective // Set the current objective in the comparison class lCmpIndvObj.mCompIndex = i; // Sort (stable, in order to keep the same order for equal fitness values) stable_sort(lCrowdingList.begin(), lCrowdingList.end(), lCmpIndvObj); // Set an infinite distance to the extremums lDistances[lCrowdingList[0].second].first = lInfinity; lDistances[lCrowdingList.back().second].first = lInfinity; for(unsigned int j = 1; j < lCrowdingList.size()-1; j++){ if(lDistances[lCrowdingList[j].second].first < lInfinity) lDistances[lCrowdingList[j].second].first += lCrowdingList[j+1].first[i]-lCrowdingList[j-1].first[i]; } } // Final sorting (again, must be stable) stable_sort(lDistances.begin(), lDistances.end(), crowdDistComp); // Pick the last individuals (with the higher crowding distance) first for(unsigned int i = lDistances.size()-1; i >= 0; i--){ if(PyList_Size(lListSelect) >= k) break; // While the size of the return list is lesser than *k*, append the next individual PyList_Append(lListSelect, PyList_GetItem(lListIndv,lDistances[i].second)); } return lListSelect; }
//------------------------------------------------------------------------------ BranchInst *findOutermostBranch(BranchSet &branches, const DominatorTree *dt) { for (auto branch : branches) if (!isDominated(branch, branches, dt)) return branch; return nullptr; }