// MOEAD_DRA.java // // Author: // Antonio J. Nebro <antonio@lcc.uma.es> // Juan J. Durillo <durillo@lcc.uma.es> // // Copyright (c) 2011 Antonio J. Nebro, Juan J. Durillo // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. package jmetal.metaheuristics.moead; import jmetal.core.*; import jmetal.util.Distance; import jmetal.util.JMException; import jmetal.util.PseudoRandom; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.*; /** * Reference: Q. Zhang, W. Liu, and H Li, The Performance of a New Version of * MOEA/D on CEC09 Unconstrained MOP Test Instances, Working Report CES-491, * School of CS & EE, University of Essex, 02/2009 */ public class MOEAD_DRA extends Algorithm { private int populationSize_; /** * Stores the population */ private SolutionSet population_; /** * Stores the values of the individuals */ private Solution [] savedValues_; private double [] utility_; private int [] frequency_; /** * Z vector (ideal point) */ double[] z_; /** * Lambda vectors */ //Vector<Vector<Double>> lambda_ ; double[][] lambda_; /** * T: neighbour size */ int T_; /** * Neighborhood */ int[][] neighborhood_; /** * delta: probability that parent solutions are selected from neighbourhood */ double delta_; /** * nr: maximal number of solutions replaced by each child solution */ int nr_; Solution[] indArray_; String functionType_; int evaluations_; /** * Operators */ Operator crossover_; Operator mutation_; String dataDirectory_; /** * Constructor * @param problem Problem to solve */ public MOEAD_DRA(Problem problem) { super (problem) ; functionType_ = "_TCHE1"; } // DMOEA public SolutionSet execute() throws JMException, ClassNotFoundException { int maxEvaluations; evaluations_ = 0; maxEvaluations = ((Integer) this.getInputParameter("maxEvaluations")).intValue(); populationSize_ = ((Integer) this.getInputParameter("populationSize")).intValue(); dataDirectory_ = this.getInputParameter("dataDirectory").toString(); population_ = new SolutionSet(populationSize_); savedValues_ = new Solution[populationSize_]; utility_ = new double[populationSize_]; frequency_ = new int[populationSize_]; for (int i = 0; i < utility_.length; i++) { utility_[i] = 1.0; frequency_[i] = 0; } indArray_ = new Solution[problem_.getNumberOfObjectives()]; //T_ = 20; //delta_ = 0.9; //nr_ = 2; //T_ = (int) (0.1 * populationSize_); //delta_ = 0.9; //nr_ = (int) (0.01 * populationSize_); T_ = ((Integer) this.getInputParameter("T")).intValue(); nr_ = ((Integer) this.getInputParameter("nr")).intValue(); delta_ = ((Double) this.getInputParameter("delta")).doubleValue(); neighborhood_ = new int[populationSize_][T_]; z_ = new double[problem_.getNumberOfObjectives()]; //lambda_ = new Vector(problem_.getNumberOfObjectives()) ; lambda_ = new double[populationSize_][problem_.getNumberOfObjectives()]; crossover_ = operators_.get("crossover"); // default: DE crossover mutation_ = operators_.get("mutation"); // default: polynomial mutation // STEP 1. Initialization // STEP 1.1. Compute euclidean distances between weight vectors and find T initUniformWeight(); initNeighborhood(); // STEP 1.2. Initialize population initPopulation(); // STEP 1.3. Initialize z_ initIdealPoint(); int gen = 0; // STEP 2. Update do { int[] permutation = new int[populationSize_]; Utils.randomPermutation(permutation, populationSize_); List<Integer> order = tour_selection(10); for (int i = 0; i < order.size(); i++) { //int n = permutation[i]; // or int n = i; int n = order.get(i) ; // or int n = i; frequency_[n]++; int type; double rnd = PseudoRandom.randDouble(); // STEP 2.1. Mating selection based on probability if (rnd < delta_) // if (rnd < realb) { type = 1; // neighborhood } else { type = 2; // whole population } Vector<Integer> p = new Vector<Integer>(); matingSelection(p, n, 2, type); // STEP 2.2. Reproduction Solution child; Solution[] parents = new Solution[3]; parents[0] = population_.get(p.get(0)); parents[1] = population_.get(p.get(1)); parents[2] = population_.get(n); // Apply DE crossover child = (Solution) crossover_.execute(new Object[]{population_.get(n), parents}); // Apply mutation mutation_.execute(child); // Evaluation problem_.evaluate(child); evaluations_++; // STEP 2.3. Repair. Not necessary // STEP 2.4. Update z_ updateReference(child); // STEP 2.5. Update of solutions updateProblem(child, n, type); } // for gen++; if(gen%30==0) { comp_utility(); } } while (evaluations_ < maxEvaluations); int final_size = populationSize_; try { final_size= (Integer) (getInputParameter("finalSize")); System.out.println("FINAL SOZE: " + final_size) ; } catch (Exception e) { // if there is an exception indicate it! System.err.println("The final size paramater has been ignored"); System.err.println("The number of solutions is " + population_.size()); return population_; } return finalSelection(final_size); } /** * initUniformWeight */ public void initUniformWeight() { if ((problem_.getNumberOfObjectives() == 2) && (populationSize_ <= 100)) { for (int n = 0; n < populationSize_; n++) { double a = 1.0 * n / (populationSize_ - 1); lambda_[n][0] = a; lambda_[n][1] = 1 - a; // System.out.println(lambda_[n][0]); // System.out.println(lambda_[n][1]); } // for } // if else { String dataFileName; dataFileName = "W" + problem_.getNumberOfObjectives() + "D_" + populationSize_ + ".dat"; // System.out.println(dataDirectory_); // System.out.println(dataDirectory_ + "/" + dataFileName); try { // Open the file FileInputStream fis = new FileInputStream(dataDirectory_ + "/" + dataFileName); InputStreamReader isr = new InputStreamReader(fis); BufferedReader br = new BufferedReader(isr); int numberOfObjectives = 0; int i = 0; int j = 0; String aux = br.readLine(); while (aux != null) { StringTokenizer st = new StringTokenizer(aux); j = 0; numberOfObjectives = st.countTokens(); while (st.hasMoreTokens()) { double value = (new Double(st.nextToken())).doubleValue(); lambda_[i][j] = value; //System.out.println("lambda["+i+","+j+"] = " + value) ; j++; } aux = br.readLine(); i++; } br.close(); } catch (Exception e) { System.err.println("initUniformWeight: failed when reading for file: " + dataDirectory_ + "/" + dataFileName); e.printStackTrace(); } } // else //System.exit(0) ; } // initUniformWeight public void comp_utility() { double f1, f2, uti, delta; for(int n=0; n<populationSize_; n++) { f1 = fitnessFunction(population_.get(n), lambda_[n]); f2 = fitnessFunction(savedValues_[n], lambda_[n]); delta = f2 - f1; if(delta>0.001) utility_[n] = 1.0; else{ // uti = 0.95*(1.0+delta/0.001)*utility_[n]; uti = (0.95 + (0.05 * delta/0.001)) * utility_[n]; utility_[n] = uti<1.0?uti:1.0; } savedValues_[n] = new Solution(population_.get(n)); } } /** * */ public void initNeighborhood() { double[] x = new double[populationSize_]; int[] idx = new int[populationSize_]; for (int i = 0; i < populationSize_; i++) { // calculate the distances based on weight vectors for (int j = 0; j < populationSize_; j++) { x[j] = Utils.distVector(lambda_[i], lambda_[j]); //x[j] = dist_vector(population[i].namda,population[j].namda); idx[j] = j; //System.out.println("x["+j+"]: "+x[j]+ ". idx["+j+"]: "+idx[j]) ; } // for // find 'niche' nearest neighboring subproblems Utils.minFastSort(x, idx, populationSize_, T_); //minfastsort(x,idx,population.size(),niche); System.arraycopy(idx, 0, neighborhood_[i], 0, T_); } // for } // initNeighborhood /** * */ public void initPopulation() throws JMException, ClassNotFoundException { for (int i = 0; i < populationSize_; i++) { Solution newSolution = new Solution(problem_); problem_.evaluate(newSolution); evaluations_++; population_.add(newSolution) ; savedValues_[i] = new Solution(newSolution); } // for } // initPopulation /** * */ void initIdealPoint() throws JMException, ClassNotFoundException { for (int i = 0; i < problem_.getNumberOfObjectives(); i++) { z_[i] = 1.0e+30; indArray_[i] = new Solution(problem_); problem_.evaluate(indArray_[i]); evaluations_++; } // for for (int i = 0; i < populationSize_; i++) { updateReference(population_.get(i)); } // for } // initIdealPoint /** * */ public void matingSelection(Vector<Integer> list, int cid, int size, int type) { // list : the set of the indexes of selected mating parents // cid : the id of current subproblem // size : the number of selected mating parents // type : 1 - neighborhood; otherwise - whole population int ss; int r; int p; ss = neighborhood_[cid].length; while (list.size() < size) { if (type == 1) { r = PseudoRandom.randInt(0, ss - 1); p = neighborhood_[cid][r]; //p = population[cid].table[r]; } else { p = PseudoRandom.randInt(0, populationSize_ - 1); } boolean flag = true; for (int i = 0; i < list.size(); i++) { if (list.get(i) == p) // p is in the list { flag = false; break; } } //if (flag) list.push_back(p); if (flag) { list.addElement(p); } } } // matingSelection public List<Integer> tour_selection(int depth) { // selection based on utility List<Integer> selected = new ArrayList<Integer>(); List<Integer> candidate = new ArrayList<Integer>(); for(int k=0; k<problem_.getNumberOfObjectives(); k++) selected.add(k); // WARNING! HERE YOU HAVE TO USE THE WEIGHT PROVIDED BY QINGFU (NOT SORTED!!!!) for(int n=problem_.getNumberOfObjectives(); n<populationSize_; n++) candidate.add(n); // set of unselected weights while(selected.size()<(int)(populationSize_/5.0)) { //int best_idd = (int) (rnd_uni(&rnd_uni_init)*candidate.size()), i2; int best_idd = (int) (PseudoRandom.randDouble()*candidate.size()); //System.out.println(best_idd); int i2; int best_sub = candidate.get(best_idd); int s2; for(int i=1; i<depth; i++) { i2 = (int) (PseudoRandom.randDouble()*candidate.size()); s2 = candidate.get(i2); //System.out.println("Candidate: "+i2); if(utility_[s2]>utility_[best_sub]) { best_idd = i2; best_sub = s2; } } selected.add(best_sub); candidate.remove(best_idd); } return selected; } /** * * @param individual */ void updateReference(Solution individual) { for (int n = 0; n < problem_.getNumberOfObjectives(); n++) { if (individual.getObjective(n) < z_[n]) { z_[n] = individual.getObjective(n); indArray_[n] = individual; } } } // updateReference /** * @param individual * @param id * @param type */ void updateProblem(Solution indiv, int id, int type) { // indiv: child solution // id: the id of current subproblem // type: update solutions in - neighborhood (1) or whole population (otherwise) int size; int time; time = 0; if (type == 1) { size = neighborhood_[id].length; } else { size = population_.size(); } int[] perm = new int[size]; Utils.randomPermutation(perm, size); for (int i = 0; i < size; i++) { int k; if (type == 1) { k = neighborhood_[id][perm[i]]; } else { k = perm[i]; // calculate the values of objective function regarding the current subproblem } double f1, f2; f1 = fitnessFunction(population_.get(k), lambda_[k]); f2 = fitnessFunction(indiv, lambda_[k]); if (f2 < f1) { population_.replace(k, new Solution(indiv)); //population[k].indiv = indiv; time++; } // the maximal number of solutions updated is not allowed to exceed 'limit' if (time >= nr_) { return; } } } // updateProblem double fitnessFunction(Solution individual, double[] lambda) { double fitness; fitness = 0.0; if (functionType_.equals("_TCHE1")) { double maxFun = -1.0e+30; for (int n = 0; n < problem_.getNumberOfObjectives(); n++) { double diff = Math.abs(individual.getObjective(n) - z_[n]); double feval; if (lambda[n] == 0) { feval = 0.0001 * diff; } else { feval = diff * lambda[n]; } if (feval > maxFun) { maxFun = feval; } } // for fitness = maxFun; } // if else { System.err.println("MOEAD.fitnessFunction: unknown type " + functionType_); System.exit(-1); } return fitness; } // fitnessEvaluation /** @author Juanjo * This method selects N solutions from a set M, where N <= M * using the same method proposed by Qingfu Zhang, W. Liu, and Hui Li in * the paper describing MOEA/D-DRA (CEC 09 COMPTETITION) * An example is giving in that paper for two objectives. * If N = 100, then the best solutions attenting to the weights (0,1), * (1/99,98/99), ...,(98/99,1/99), (1,0) are selected. * * Using this method result in 101 solutions instead of 100. We will just * compute 100 even distributed weights and used them. The result is the same * * In case of more than two objectives the procedure is: * 1- Select a solution at random * 2- Select the solution from the population which have maximum distance to * it (whithout considering the already included) * * * * @param n: The number of solutions to return * @return A solution set containing those elements * */ SolutionSet finalSelection(int n) throws JMException { SolutionSet res = new SolutionSet(n); if (problem_.getNumberOfObjectives() == 2) { // subcase 1 double [][] intern_lambda = new double[n][2]; for (int i = 0; i < n; i++) { double a = 1.0 * i / (n - 1); intern_lambda[i][0] = a; intern_lambda[i][1] = 1 - a; } // for // we have now the weights, now select the best solution for each of them for (int i = 0; i < n; i++) { Solution current_best = population_.get(0); int index = 0; double value = fitnessFunction(current_best, intern_lambda[i]); for (int j = 1; j < n; j++) { double aux = fitnessFunction(population_.get(j),intern_lambda[i]); // we are looking the best for the weight i if (aux < value) { // solution in position j is better! value = aux; current_best = population_.get(j); } } res.add(new Solution(current_best)); } } else { // general case (more than two objectives) Distance distance_utility = new Distance(); int random_index = PseudoRandom.randInt(0, population_.size()-1); // create a list containing all the solutions but the selected one (only references to them) List<Solution> candidate = new LinkedList<Solution>(); candidate.add(population_.get(random_index)); for (int i = 0; i< population_.size(); i++) { if (i != random_index) candidate.add(population_.get(i)); } // for while (res.size() < n) { int index = 0; Solution selected = candidate.get(0); // it should be a next! (n <= population size!) double distance_value = distance_utility.distanceToSolutionSetInObjectiveSpace(selected, res); int i = 1; while (i < candidate.size()) { Solution next_candidate = candidate.get(i); double aux = distance_value = distance_utility.distanceToSolutionSetInObjectiveSpace(next_candidate, res); if (aux > distance_value) { distance_value = aux; index = i; } i++; } // add the selected to res and remove from candidate list res.add(new Solution(candidate.remove(index))); } // } return res; } } // MOEAD_DRA