// PMXCrossover.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.operators.crossover; import jmetal.core.Solution; import jmetal.encodings.solutionType.PermutationSolutionType; import jmetal.encodings.solutionType.ZeroPermutationSolutionType; import jmetal.encodings.variable.Permutation; import jmetal.util.Configuration; import jmetal.util.JMException; import jmetal.util.PseudoRandom; import java.util.Arrays; import java.util.HashMap; import java.util.List; /** * This class allows to apply a PMX crossover operator using two parent * solutions. * NOTE: the operator is applied to the first encodings.variable of the solutions, and * the type of those variables must be VariableType_.Permutation. */ public class ZeroPMXCrossover extends Crossover { /** * Valid solution types to apply this operator */ private static final List VALID_TYPES = Arrays.asList(ZeroPermutationSolutionType.class); private Double crossoverProbability_ = null; /** * Constructor */ public ZeroPMXCrossover(HashMap<String, Object> parameters) { super(parameters); if (parameters.get("probability") != null) crossoverProbability_ = (Double) parameters.get("probability"); } // PMXCrossover /** * Perform the crossover operation * * @param probability Crossover probability * @param parent1 The first parent * @param parent2 The second parent * @return An array containig the two offsprings * @throws JMException */ public Solution[] doCrossover(double probability, Solution parent1, Solution parent2) { Solution[] offspring = new Solution[2]; offspring[0] = new Solution(parent1); offspring[1] = new Solution(parent2); int permutationLength; permutationLength = ((Permutation) parent1.getDecisionVariables()[0]).getLength(); int parent1Vector[] = ((Permutation) parent1.getDecisionVariables()[0]).vector_; int parent2Vector[] = ((Permutation) parent2.getDecisionVariables()[0]).vector_; int offspring1Vector[] = ((Permutation) offspring[0].getDecisionVariables()[0]).vector_; int offspring2Vector[] = ((Permutation) offspring[1].getDecisionVariables()[0]).vector_; if (PseudoRandom.randDouble() < probability) { int cuttingPoint1; int cuttingPoint2; int maxVal = Math.max(parent1.getProblem().getLength(1)+1, permutationLength); // STEP 1: Get two cutting points cuttingPoint1 = PseudoRandom.randInt(0, permutationLength - 1); cuttingPoint2 = PseudoRandom.randInt(0, permutationLength - 1); while (cuttingPoint2 == cuttingPoint1) cuttingPoint2 = PseudoRandom.randInt(0, permutationLength - 1); if (cuttingPoint1 > cuttingPoint2) { int swap; swap = cuttingPoint1; cuttingPoint1 = cuttingPoint2; cuttingPoint2 = swap; } // if // STEP 2: Get the subchains to interchange int replacement1[] = new int[maxVal]; int replacement2[] = new int[maxVal]; for (int i = 0; i < maxVal; i++) replacement1[i] = replacement2[i] = -1; // STEP 3: Interchange for (int i = cuttingPoint1; i <= cuttingPoint2; i++) { offspring1Vector[i] = parent2Vector[i]; offspring2Vector[i] = parent1Vector[i]; if(parent2Vector[i] != 0) { replacement1[parent2Vector[i]] = parent1Vector[i]; } if(parent1Vector[i] != 0) { replacement2[parent1Vector[i]] = parent2Vector[i]; } } // for // STEP 4: Repair offsprings for (int i = 0; i < permutationLength; i++) { if ((i >= cuttingPoint1) && (i <= cuttingPoint2)) continue; int n1 = parent1Vector[i]; int m1 = replacement1[n1]; int n2 = parent2Vector[i]; int m2 = replacement2[n2]; while (m1 != -1) { n1 = m1; m1 = replacement1[m1]; } // while while (m2 != -1) { n2 = m2; m2 = replacement2[m2]; } // while offspring1Vector[i] = n1; offspring2Vector[i] = n2; } // for } // if return offspring; } // doCrossover /** * Executes the operation * * @param object An object containing an array of two solutions * @throws JMException */ public Object execute(Object object) throws JMException { Solution[] parents = (Solution[]) object; Double crossoverProbability = null; if (!(VALID_TYPES.contains(parents[0].getType().getClass()) && VALID_TYPES.contains(parents[1].getType().getClass()))) { Configuration.logger_.severe("PMCCrossover.execute: the solutions " + "are not of the right type. The type should be 'ZeroPermutation', but " + parents[0].getType() + " and " + parents[1].getType() + " are obtained"); } //crossoverProbability = (Double)parameters_.get("probability"); crossoverProbability = (Double) getParameter("probability"); if (parents.length < 2) { Configuration.logger_.severe("PMXCrossover.execute: operator needs two " + "parents"); Class cls = String.class; String name = cls.getName(); throw new JMException("Exception in " + name + ".execute()"); } Solution[] offspring = doCrossover(crossoverProbability.doubleValue(), parents[0], parents[1]); return offspring; } // execute } // PMXCrossover