/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package hh.moea; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Vector; import org.moeaframework.core.FastNondominatedSorting; import org.moeaframework.core.Population; import org.moeaframework.core.Solution; /** * Fast Nondominated sorting for steady state evolutionary algorithms. * Implements Efficient Non-domination Level Update (ENLU) from Li, Ke, * Kalyanmoy Deb, Qingfu Zhang, Senior Member, and Qiang Zhang. 2015. “Efficient * Non-Domination Level Update Method for Steady-State Evolutionary * Multi-Objective Optimization.” COIN Report Number 2015022 * * @author nozomihitomi */ public class SteadyStateFastNonDominatedSorting extends FastNondominatedSorting { private int[][] rankIdx_; private int numRanks; private HashSet<Integer> lastFront; private HashSet<Integer> paretoFront; public SteadyStateFastNonDominatedSorting() { super(); } /** * update the non-domination level when adding a solution. Modified code * obtained from https://github.com/JerryI00/publication_codes.git * * @param individual individual to add to population * @param population population to add individual to */ public void addSolution(Solution individual, Population population) { //Compute the new domination levels numRanks = add(individual, population); population.add(individual); lastFront = new HashSet<>(); paretoFront = new HashSet<>(); for(int i=0; i< rankIdx_[numRanks-1].length; i++){ if(rankIdx_[numRanks-1][i]==1) lastFront.add(i); if(rankIdx_[0][i]==1) paretoFront.add(i); } //also check the new offspring if((int)individual.getAttribute(RANK_ATTRIBUTE)==numRanks-1) lastFront.add(population.size()-1); if((int)individual.getAttribute(RANK_ATTRIBUTE)==0) paretoFront.add(population.size()-1); } /** * Returns the indices of the solutions in the last front * @return the indices of the solutions in the last front */ public Collection<Integer> getLastFront(){ return lastFront; } /** * Returns the indices of the solutions in the pareto front * @return the indices of the solutions in the pareto front */ public Collection<Integer> getParetoFront(){ return paretoFront; } /** * * @param individual individual to add to population * @param population population to add individual to * @return the number of domination levels */ private int add(Solution individual, Population population) { int flag = 0; int flag1, flag2, flag3; rankIdx_ = new int[population.size()][population.size()]; for (int i = 0; i < population.size(); i++) { Arrays.fill(rankIdx_[i], 0); } // count the number of non-domination levels HashMap<Integer, Integer> frontSize = new HashMap(); for (int i = 0; i < population.size(); i++) { int rank = (int) population.get(i).getAttribute(RANK_ATTRIBUTE); if (frontSize.containsKey(rank)) { frontSize.put(rank, frontSize.get(rank) + 1); } else { frontSize.put(rank, 1); } rankIdx_[rank][i] = 1; } int num_ranks = frontSize.keySet().size(); Vector<Integer> dominateList = new Vector<>(); // used to keep the solutions dominated by 'individual' int level = 0; for (int i = 0; i < num_ranks; i++) { level = i; if (flag == 1) { // 'individual' is non-dominated with all solutions in the ith non-domination level, then 'individual' belongs to the ith level individual.setAttribute(RANK_ATTRIBUTE, i - 1); return num_ranks; } else if (flag == 2) { // 'individual' dominates some solutions in the ith level, but is non-dominated with some others, then 'individual' belongs to the ith level, and move the dominated solutions to the next level individual.setAttribute(RANK_ATTRIBUTE, i - 1); int prevRank = i - 1; // process the solutions belong to 'prevRank'th level and are dominated by 'individual' ==> move them to 'prevRank+1'th level and find the solutions dominated by them int curIdx; int newRank = prevRank + 1; int curListSize = dominateList.size(); for (int j = 0; j < curListSize; j++) { curIdx = dominateList.get(j); rankIdx_[prevRank][curIdx] = 0; rankIdx_[newRank][curIdx] = 1; population.get(curIdx).setAttribute(RANK_ATTRIBUTE,newRank); } //finds which solutions from prevRank + 1 are dominated by solutions that were just moved to prevRank + 1 from prevRank for (int j = 0; j < population.size(); j++) { if (rankIdx_[newRank][j] == 1) { for (int k = 0; k < curListSize; k++) { curIdx = dominateList.get(k); if (getComparator().compare(population.get(j),population.get(curIdx)) == 1) { dominateList.addElement(j); break; } } } } //removes all the solutions that we just moved from prevRank to prevRank + 1 for (int j = 0; j < curListSize; j++) { dominateList.remove(0); } // if there are still some other solutions moved to the next level, check their domination situation in their new level prevRank = newRank; newRank = newRank + 1; curListSize = dominateList.size(); if (curListSize == 0) { return num_ranks; } else { int allFlag = 0; do { for (int j = 0; j < curListSize; j++) { curIdx = dominateList.get(j); rankIdx_[prevRank][curIdx] = 0; rankIdx_[newRank][curIdx] = 1; population.get(curIdx).setAttribute(RANK_ATTRIBUTE,newRank); } for (int j = 0; j < population.size(); j++) { if (rankIdx_[newRank][j] == 1) { for (int k = 0; k < curListSize; k++) { curIdx = dominateList.get(k); if (getComparator().compare(population.get(j),population.get(curIdx)) == 1) { dominateList.addElement(j); break; } } } } for (int j = 0; j < curListSize; j++) { dominateList.remove(0); } curListSize = dominateList.size(); if (curListSize != 0) { prevRank = newRank; newRank = newRank + 1; if (curListSize == frontSize.get(prevRank)) { // if all solutions in the 'prevRank'th level are dominated by the newly added solution, move them all to the next level allFlag = 1; break; } } } while (curListSize != 0); if (allFlag == 1) { // move the solutions after the 'prevRank'th level to their next levels int remainSize = num_ranks - prevRank; int[][] tempRecord = new int[remainSize][population.size()]; int tempIdx = 0; for (int j = 0; j < dominateList.size(); j++) { tempRecord[0][tempIdx] = dominateList.get(j); tempIdx++; } int k = 1; int curRank = prevRank + 1; while (curRank < num_ranks) { tempIdx = 0; for (int j = 0; j < population.size(); j++) { if (rankIdx_[curRank][j] == 1) { tempRecord[k][tempIdx] = j; tempIdx++; } } curRank++; k++; } k = 0; curRank = prevRank; while (curRank < num_ranks) { int level_size = frontSize.get(curRank); int tempRank; for (int j = 0; j < level_size; j++) { curIdx = tempRecord[k][j]; tempRank = (int)population.get(curIdx).getAttribute(RANK_ATTRIBUTE); newRank = tempRank + 1; population.get(curIdx).setAttribute(RANK_ATTRIBUTE,newRank); rankIdx_[tempRank][curIdx] = 0; rankIdx_[newRank][curIdx] = 1; } curRank++; k++; } num_ranks++; } if (newRank == num_ranks) { num_ranks++; } return num_ranks; } } else if (flag == 3 || flag == 0) { // if 'individual' is dominated by some solutions in the ith level, skip it, and term to the next level flag1 = flag2 = flag3 = 0; for (int j = 0; j < population.size(); j++) { if (rankIdx_[i][j] == 1) { switch (getComparator().compare(population.get(j),individual)) { case 1: { flag1 = 1; dominateList.addElement(j); break; } case 0: { flag2 = 1; break; } case -1: { flag3 = 1; break; } } if (flag3 == 1) { flag = 3; break; } else if (flag1 == 0 && flag2 == 1) { flag = 1; } else if (flag1 == 1 && flag2 == 1) { flag = 2; } else if (flag1 == 1 && flag2 == 0) { flag = 4; } else { continue; } } } } else { // (flag == 4) if 'indiv' dominates all solutions in the ith level, solutions in the current level and beyond move their current next levels individual.setAttribute(RANK_ATTRIBUTE,i - 1); i = i - 1; int remainSize = num_ranks - i; int[][] tempRecord = new int[remainSize][population.size()]; int k = 0; while (i < num_ranks) { int tempIdx = 0; for (int j = 0; j < population.size(); j++) { if (rankIdx_[i][j] == 1) { tempRecord[k][tempIdx] = j; tempIdx++; } } i++; k++; } k = 0; i = (int)individual.getAttribute(RANK_ATTRIBUTE); while (i < num_ranks) { int level_size = frontSize.get(i); int curIdx; int curRank, newRank; for (int j = 0; j < level_size; j++) { curIdx = tempRecord[k][j]; curRank = (int)population.get(curIdx).getAttribute(RANK_ATTRIBUTE); newRank = curRank + 1; population.get(curIdx).setAttribute(RANK_ATTRIBUTE,newRank); rankIdx_[curRank][curIdx] = 0; rankIdx_[newRank][curIdx] = 1; } i++; k++; } num_ranks++; return num_ranks; } } // if flag is still 3 after the for-loop, it means that 'indiv' is in the current last level if (flag == 1) { individual.setAttribute(RANK_ATTRIBUTE,level); } else if (flag == 2) { individual.setAttribute(RANK_ATTRIBUTE,level); int curIdx; int tempSize = dominateList.size(); for (int i = 0; i < tempSize; i++) { curIdx = dominateList.get(i); population.get(curIdx).setAttribute(RANK_ATTRIBUTE,level + 1); rankIdx_[level][curIdx] = 0; rankIdx_[level + 1][curIdx] = 1; } num_ranks++; } else if (flag == 3) { individual.setAttribute(RANK_ATTRIBUTE,level + 1); num_ranks++; } else { individual.setAttribute(RANK_ATTRIBUTE,level); for (int i = 0; i < population.size(); i++) { if (rankIdx_[level][i] == 1) { population.get(i).setAttribute(RANK_ATTRIBUTE,level + 1); rankIdx_[level][i] = 0; rankIdx_[level + 1][i] = 1; } } num_ranks++; } return num_ranks; } }