// DifferentialEvolutionCrossover.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.ArrayRealSolutionType; import jmetal.encodings.solutionType.RealSolutionType; import jmetal.util.Configuration; import jmetal.util.JMException; import jmetal.util.PseudoRandom; import jmetal.util.wrapper.XReal; import java.util.Arrays; import java.util.HashMap; import java.util.List; /** * Differential evolution crossover operators * Comments: * - The operator receives two parameters: the current individual and an array * of three parent individuals * - The best and rand variants depends on the third parent, according whether * it represents the current of the "best" individual or a randon one. * The implementation of both variants are the same, due to that the parent * selection is external to the crossover operator. * - Implemented variants: * - rand/1/bin (best/1/bin) * - rand/1/exp (best/1/exp) * - current-to-rand/1 (current-to-best/1) * - current-to-rand/1/bin (current-to-best/1/bin) * - current-to-rand/1/exp (current-to-best/1/exp) */ public class DifferentialEvolutionCrossover extends Crossover { /** * DEFAULT_CR defines a default CR (crossover operation control) value */ private static final double DEFAULT_CR = 0.5; /** * DEFAULT_F defines the default F (Scaling factor for mutation) value */ private static final double DEFAULT_F = 0.5; /** * DEFAULT_K defines a default K value used in variants current-to-rand/1 * and current-to-best/1 */ private static final double DEFAULT_K = 0.5; /** * DEFAULT_VARIANT defines the default DE variant */ private static final String DEFAULT_DE_VARIANT = "rand/1/bin"; /** * Valid solution types to apply this operator */ private static final List VALID_TYPES = Arrays.asList(RealSolutionType.class, ArrayRealSolutionType.class) ; private double CR_ ; private double F_ ; private double K_ ; private String DE_Variant_ ; // DE variant (rand/1/bin, rand/1/exp, etc.) /** * Constructor */ public DifferentialEvolutionCrossover(HashMap<String, Object> parameters) { super(parameters) ; CR_ = DEFAULT_CR ; F_ = DEFAULT_F ; K_ = DEFAULT_K ; DE_Variant_ = DEFAULT_DE_VARIANT ; if (parameters.get("CR") != null) CR_ = (Double) parameters.get("CR") ; if (parameters.get("F") != null) F_ = (Double) parameters.get("F") ; if (parameters.get("K") != null) K_ = (Double) parameters.get("K") ; if (parameters.get("DE_VARIANT") != null) DE_Variant_ = (String) parameters.get("DE_VARIANT") ; } // Constructor /** * Constructor */ //public DifferentialEvolutionCrossover(Properties properties) { // this(); // CR_ = (new Double((String)properties.getProperty("CR_"))); // F_ = (new Double((String)properties.getProperty("F_"))); // K_ = (new Double((String)properties.getProperty("K_"))); // DE_Variant_ = properties.getProperty("DE_Variant_") ; //} // Constructor /** * Executes the operation * @param object An object containing an array of three parents * @return An object containing the offSprings */ public Object execute(Object object) throws JMException { Object[] parameters = (Object[])object ; Solution current = (Solution) parameters[0]; Solution [] parent = (Solution [])parameters[1]; Solution child ; if (!(VALID_TYPES.contains(parent[0].getType().getClass()) && VALID_TYPES.contains(parent[1].getType().getClass()) && VALID_TYPES.contains(parent[2].getType().getClass())) ) { Configuration.logger_.severe("DifferentialEvolutionCrossover.execute: " + " the solutions " + "are not of the right type. The type should be 'Real' or 'ArrayReal', but " + parent[0].getType() + " and " + parent[1].getType() + " and " + parent[2].getType() + " are obtained"); Class cls = java.lang.String.class; String name = cls.getName(); throw new JMException("Exception in " + name + ".execute()") ; } int jrand ; child = new Solution(current) ; XReal xParent0 = new XReal(parent[0]) ; XReal xParent1 = new XReal(parent[1]) ; XReal xParent2 = new XReal(parent[2]) ; XReal xCurrent = new XReal(current) ; XReal xChild = new XReal(child) ; int numberOfVariables = xParent0.getNumberOfDecisionVariables() ; jrand = PseudoRandom.randInt(0, numberOfVariables - 1); // STEP 4. Checking the DE variant if ((DE_Variant_.compareTo("rand/1/bin") == 0) || (DE_Variant_.compareTo("best/1/bin") == 0)) { for (int j=0; j < numberOfVariables; j++) { if (PseudoRandom.randDouble(0, 1) < CR_ || j == jrand) { double value ; value = xParent2.getValue(j) + F_ * (xParent0.getValue(j) - xParent1.getValue(j)) ; if (value < xChild.getLowerBound(j)) value = xChild.getLowerBound(j) ; if (value > xChild.getUpperBound(j)) value = xChild.getUpperBound(j) ; /* if (value < xChild.getLowerBound(j)) { double rnd = PseudoRandom.randDouble(0, 1) ; value = xChild.getLowerBound(j) + rnd *(xParent2.getValue(j) - xChild.getLowerBound(j)) ; } if (value > xChild.getUpperBound(j)) { double rnd = PseudoRandom.randDouble(0, 1) ; value = xChild.getUpperBound(j) - rnd*(xChild.getUpperBound(j)-xParent2.getValue(j)) ; } */ xChild.setValue(j, value) ; } else { double value ; value = xCurrent.getValue(j); xChild.setValue(j, value) ; } // else } // for } // if else if ((DE_Variant_.compareTo("rand/1/exp") == 0) || (DE_Variant_.compareTo("best/1/exp") == 0)) { for (int j=0; j < numberOfVariables; j++) { if (PseudoRandom.randDouble(0, 1) < CR_ || j == jrand) { double value ; value = xParent2.getValue(j) + F_ * (xParent0.getValue(j) - xParent1.getValue(j)) ; if (value < xChild.getLowerBound(j)) value = xChild.getLowerBound(j) ; if (value > xChild.getUpperBound(j)) value = xChild.getUpperBound(j) ; xChild.setValue(j, value) ; } else { CR_ = 0.0 ; double value ; value = xCurrent.getValue(j); xChild.setValue(j, value) ; } // else } // for } // if else if ((DE_Variant_.compareTo("current-to-rand/1") == 0) || (DE_Variant_.compareTo("current-to-best/1") == 0)) { for (int j=0; j < numberOfVariables; j++) { double value ; value = xCurrent.getValue(j) + K_ * (xParent2.getValue(j) - xCurrent.getValue(j)) + F_ * (xParent0.getValue(j) - xParent1.getValue(j)) ; if (value < xChild.getLowerBound(j)) value = xChild.getLowerBound(j) ; if (value > xChild.getUpperBound(j)) value = xChild.getUpperBound(j) ; xChild.setValue(j, value) ; } // for } // if else if ((DE_Variant_.compareTo("current-to-rand/1/bin") == 0) || (DE_Variant_.compareTo("current-to-best/1/bin") == 0)) { for (int j=0; j < numberOfVariables; j++) { if (PseudoRandom.randDouble(0, 1) < CR_ || j == jrand) { double value ; value = xCurrent.getValue(j) + K_ * (xParent2.getValue(j) - xCurrent.getValue(j)) + F_ * (xParent0.getValue(j) - xParent1.getValue(j)) ; if (value < xChild.getLowerBound(j)) value = xChild.getLowerBound(j) ; if (value > xChild.getUpperBound(j)) value = xChild.getUpperBound(j) ; xChild.setValue(j, value) ; } else { double value ; value = xCurrent.getValue(j); xChild.setValue(j, value) ; } // else } // for } // if else if ((DE_Variant_.compareTo("current-to-rand/1/exp") == 0) || (DE_Variant_.compareTo("current-to-best/1/exp") == 0)) { for (int j=0; j < numberOfVariables; j++) { if (PseudoRandom.randDouble(0, 1) < CR_ || j == jrand) { double value ; value = xCurrent.getValue(j) + K_ * (xParent2.getValue(j) - xCurrent.getValue(j)) + F_ * (xParent0.getValue(j) - xParent1.getValue(j)) ; if (value < xChild.getLowerBound(j)) value = xChild.getLowerBound(j) ; if (value > xChild.getUpperBound(j)) value = xChild.getUpperBound(j) ; xChild.setValue(j, value) ; } else { CR_ = 0.0 ; double value ; value = xCurrent.getValue(j); xChild.setValue(j, value) ; } // else } // for } // if else { Configuration.logger_.severe("DifferentialEvolutionCrossover.execute: " + " unknown DE variant (" + DE_Variant_ + ")"); Class<String> cls = java.lang.String.class; String name = cls.getName(); throw new JMException("Exception in " + name + ".execute()") ; } // else return child ; } } // DifferentialEvolutionCrossover