// SBXSinglePointCrossover.java
//
// Author:
// Antonio J. Nebro <antonio@lcc.uma.es>
//
// Copyright (c) 2011 Antonio J. Nebro
//
// 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.ArrayRealAndBinarySolutionType;
import jmetal.encodings.variable.Binary;
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;
public class SBXSinglePointCrossover extends Crossover {
/**
* EPS defines the minimum difference allowed between real values
*/
private static final double EPS= 1.0e-14;
private static final double ETA_C_DEFAULT_ = 20.0;
private Double realCrossoverProbability_ = null;
private Double binaryCrossoverProbability_ = null;
private double distributionIndex_ = ETA_C_DEFAULT_;
/**
* Valid solution types to apply this operator
*/
private static final List VALID_TYPES = Arrays.asList(ArrayRealAndBinarySolutionType.class) ;
/**
* Constructor
*/
public SBXSinglePointCrossover(HashMap<String, Object> parameters) {
super (parameters) ;
if (parameters.get("realCrossoverProbability") != null)
realCrossoverProbability_ = (Double) parameters.get("realCrossoverProbability") ;
if (parameters.get("binaryrossoverProbability") != null)
binaryCrossoverProbability_ = (Double) parameters.get("binaryrossoverProbability") ;
if (parameters.get("distributionIndex") != null)
distributionIndex_ = (Double) parameters.get("distributionIndex") ;
} // Constructor
/**
* Perform the crossover operation.
* @param realProbability Crossover probability
* @param parent1 The first parent
* @param parent2 The second parent
* @return An array containing the two offsprings
*/
public Solution[] doCrossover(Double realProbability,
Double binaryProbability,
Solution parent1,
Solution parent2) throws JMException {
Solution [] offSpring = new Solution[2];
offSpring[0] = new Solution(parent1);
offSpring[1] = new Solution(parent2);
// SBX crossover
double rand;
double y1, y2, yL, yu;
double c1, c2;
double alpha, beta, betaq;
double valueX1,valueX2;
XReal x1 = new XReal(parent1) ;
XReal x2 = new XReal(parent2) ;
XReal offs1 = new XReal(offSpring[0]) ;
XReal offs2 = new XReal(offSpring[1]) ;
int numberOfVariables = x1.size() ;
if (PseudoRandom.randDouble() <= realProbability) {
for (int i=0; i<x1.size(); i++){
valueX1 = x1.getValue(i);
valueX2 = x2.getValue(i);
if (PseudoRandom.randDouble()<=0.5 ){
if (java.lang.Math.abs(valueX1- valueX2) > EPS) {
if (valueX1 < valueX2){
y1 = valueX1;
y2 = valueX2;
} else {
y1 = valueX2;
y2 = valueX1;
} // if
yL = x1.getLowerBound(i) ;
yu = x1.getUpperBound(i) ;
rand = PseudoRandom.randDouble();
beta = 1.0 + (2.0*(y1-yL)/(y2-y1));
alpha = 2.0 - java.lang.Math.pow(beta,-(distributionIndex_+1.0));
if (rand <= (1.0/alpha)){
betaq = java.lang.Math.pow ((rand*alpha),(1.0/(distributionIndex_+1.0)));
} else {
betaq = java.lang.Math.pow ((1.0/(2.0 - rand*alpha)),(1.0/(distributionIndex_+1.0)));
} // if
c1 = 0.5*((y1+y2)-betaq*(y2-y1));
beta = 1.0 + (2.0*(yu-y2)/(y2-y1));
alpha = 2.0 - java.lang.Math.pow(beta,-(distributionIndex_+1.0));
if (rand <= (1.0/alpha)){
betaq = java.lang.Math.pow ((rand*alpha),(1.0/(distributionIndex_+1.0)));
} else {
betaq = java.lang.Math.pow ((1.0/(2.0 - rand*alpha)),(1.0/(distributionIndex_+1.0)));
} // if
c2 = 0.5*((y1+y2)+betaq*(y2-y1));
if (c1<yL)
c1=yL;
if (c2<yL)
c2=yL;
if (c1>yu)
c1=yu;
if (c2>yu)
c2=yu;
if (PseudoRandom.randDouble()<=0.5) {
offs1.setValue(i, c2) ;
offs2.setValue(i, c1) ;
} else {
offs1.setValue(i, c1) ;
offs2.setValue(i, c2) ;
} // if
} // if
else {
offs1.setValue(i,valueX1) ;
offs2.setValue(i, valueX2) ;
} // if
} // if
else {
offs1.setValue(i, valueX2) ;
offs2.setValue(i, valueX1) ;
} // else
} // for
} // if
// Single point crossover
if (PseudoRandom.randDouble()<=binaryProbability) {
Binary binaryChild0 = (Binary)offSpring[0].getDecisionVariables()[1] ;
Binary binaryChild1 = (Binary)offSpring[1].getDecisionVariables()[1] ;
int totalNumberOfBits = binaryChild0.getNumberOfBits() ;
//2. Calcule the point to make the crossover
int crossoverPoint = PseudoRandom.randInt(0, totalNumberOfBits - 1);
//5. Make the crossover;
for (int i = crossoverPoint; i < totalNumberOfBits; i++) {
boolean swap = binaryChild0.bits_.get(i);
binaryChild0.bits_.set(i, binaryChild1.bits_.get(i));
binaryChild1.bits_.set(i, swap);
} // for
} // if
return offSpring;
} // doCrossover
@Override
public Object execute(Object object) throws JMException {
Solution [] parents = (Solution [])object;
if (parents.length != 2) {
Configuration.logger_.severe("SBXSinglePointCrossover.execute: operator " +
"needs two parents");
Class cls = java.lang.String.class;
String name = cls.getName();
throw new JMException("Exception in " + name + ".execute()") ;
} // if
if (!(VALID_TYPES.contains(parents[0].getType().getClass()) &&
VALID_TYPES.contains(parents[1].getType().getClass())) ) {
Configuration.logger_.severe("SBXSinglePointCrossover.execute: the solutions " +
"type " + parents[0].getType() + " is not allowed with this operator");
Class cls = java.lang.String.class;
String name = cls.getName();
throw new JMException("Exception in " + name + ".execute()") ;
} // if
Solution [] offSpring;
offSpring = doCrossover(realCrossoverProbability_,
binaryCrossoverProbability_, parents[0], parents[1]);
return offSpring ;
} // execute
} // SBXSinglePointCrossover