New GA mutation and crossover operators with subsegment-maintenance
This commit is contained in:
parent
af42465438
commit
e8c14b0aa8
@ -92,6 +92,23 @@ public abstract class AbstractEAIndividual implements IndividualInterface, java.
|
||||
*/
|
||||
public abstract Object clone();
|
||||
|
||||
/**
|
||||
* Set the init/mutation/crossover operator and probabilities to the given values.
|
||||
*
|
||||
* @param initOp
|
||||
* @param mutOp
|
||||
* @param pMut
|
||||
* @param coOp
|
||||
* @param pCross
|
||||
*/
|
||||
public void setOperators(InterfaceInitialization initOp, InterfaceMutation mutOp, double pMut, InterfaceCrossover coOp, double pCross) {
|
||||
m_InitOperator = initOp;
|
||||
m_MutationProbability = pMut;
|
||||
m_MutationOperator = mutOp;
|
||||
m_CrossoverProbability = pCross;
|
||||
m_CrossoverOperator = coOp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mutation/crossover operator and probabilities to the given values.
|
||||
*
|
||||
@ -101,10 +118,7 @@ public abstract class AbstractEAIndividual implements IndividualInterface, java.
|
||||
* @param pCross
|
||||
*/
|
||||
public void setOperators(InterfaceMutation mutOp, double pMut, InterfaceCrossover coOp, double pCross) {
|
||||
m_MutationProbability = pMut;
|
||||
m_MutationOperator = mutOp;
|
||||
m_CrossoverProbability = pCross;
|
||||
m_CrossoverOperator = coOp;
|
||||
setOperators(new DefaultInitialization(), mutOp, pMut, coOp, pCross);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,6 +32,11 @@ public class GAIndividualBinaryData extends AbstractEAIndividual implements Inte
|
||||
this.m_Genotype = new BitSet();
|
||||
}
|
||||
|
||||
public GAIndividualBinaryData(int genotypeLen) {
|
||||
this();
|
||||
this.setBinaryDataLength(genotypeLen);
|
||||
}
|
||||
|
||||
public GAIndividualBinaryData(GAIndividualBinaryData individual) {
|
||||
if (individual.m_Phenotype != null)
|
||||
this.m_Phenotype = (BitSet) individual.m_Phenotype.clone();
|
||||
@ -131,7 +136,7 @@ public class GAIndividualBinaryData extends AbstractEAIndividual implements Inte
|
||||
result += "})\n Value: ";
|
||||
result += "{";
|
||||
for (int i = 0; i < this.m_GenotypeLength; i++) {
|
||||
if (i%10==0) result+="|";
|
||||
if (i%8==0) result+="|";
|
||||
if (this.m_Genotype.get(i)) result += "1";
|
||||
else result += "0";
|
||||
}
|
||||
|
@ -10,14 +10,15 @@ import eva2.server.go.problems.InterfaceOptimizationProblem;
|
||||
import eva2.tools.math.RNG;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: streiche
|
||||
* Date: 18.03.2003
|
||||
* Time: 12:45:06
|
||||
* To change this template use Options | File Templates.
|
||||
* The famous n-point crossover operator on a binary genotype. Genotypes of
|
||||
* parent individuals are recombined by exchanging subsegments within randomly
|
||||
* selected points. Therefore, far-away allels (larger GA schemas) are more likely to be split
|
||||
* between individuals.
|
||||
*
|
||||
* @author mkron, streiche
|
||||
*/
|
||||
public class CrossoverGANPoint implements InterfaceCrossover, java.io.Serializable {
|
||||
private InterfaceOptimizationProblem m_OptimizationProblem;
|
||||
// private InterfaceOptimizationProblem m_OptimizationProblem;
|
||||
private int m_NumberOfCrossovers = 3;
|
||||
|
||||
public CrossoverGANPoint() {
|
||||
@ -30,7 +31,7 @@ public class CrossoverGANPoint implements InterfaceCrossover, java.io.Serializab
|
||||
}
|
||||
|
||||
public CrossoverGANPoint(CrossoverGANPoint mutator) {
|
||||
this.m_OptimizationProblem = mutator.m_OptimizationProblem;
|
||||
// this.m_OptimizationProblem = mutator.m_OptimizationProblem;
|
||||
this.m_NumberOfCrossovers = mutator.m_NumberOfCrossovers;
|
||||
}
|
||||
|
||||
@ -41,7 +42,7 @@ public class CrossoverGANPoint implements InterfaceCrossover, java.io.Serializab
|
||||
return new CrossoverGANPoint(this);
|
||||
}
|
||||
|
||||
/** This method performs crossover on two individuals. If the individuals do
|
||||
/** This method performs crossover on multiple individuals. If the individuals do
|
||||
* not implement InterfaceGAIndividual, then nothing will happen.
|
||||
* @param indy1 The first individual
|
||||
* @param partners The second individual
|
||||
@ -58,7 +59,7 @@ public class CrossoverGANPoint implements InterfaceCrossover, java.io.Serializab
|
||||
if ((indy1 instanceof InterfaceGAIndividual) && (partners.get(0) instanceof InterfaceGAIndividual)) {
|
||||
int length = ((InterfaceGAIndividual)indy1).getGenotypeLength();
|
||||
int mixer = RNG.randomInt(0, partners.size());
|
||||
int[] crossoverPoints = new int[this.m_NumberOfCrossovers];
|
||||
int[] crossoverPoints = null;
|
||||
BitSet[][] tmpBitSet = new BitSet[2][partners.size()+1];
|
||||
|
||||
tmpBitSet[0][0] = ((InterfaceGAIndividual)indy1).getBGenotype();
|
||||
@ -69,10 +70,8 @@ public class CrossoverGANPoint implements InterfaceCrossover, java.io.Serializab
|
||||
length = Math.max(length, ((InterfaceGAIndividual)partners.get(i)).getGenotypeLength());
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.m_NumberOfCrossovers; i++) {
|
||||
crossoverPoints[i] = RNG.randomInt(0, length-1);
|
||||
//System.out.println("crpoint: "+crossoverPoints[i]);
|
||||
}
|
||||
crossoverPoints=getCrossoverPoints(length, m_NumberOfCrossovers);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
for (int j = 0; j < this.m_NumberOfCrossovers; j++) {
|
||||
if (i == crossoverPoints[j]) mixer++;
|
||||
@ -88,13 +87,27 @@ public class CrossoverGANPoint implements InterfaceCrossover, java.io.Serializab
|
||||
|
||||
for (int i = 0; i < result.length; i++) ((InterfaceGAIndividual)result[i]).SetBGenotype(tmpBitSet[1][i]);
|
||||
}
|
||||
//in case the crossover was successfull lets give the mutation operators a chance to mate the strategy parameters
|
||||
//in case the crossover was successful lets give the mutation operators a chance to mate the strategy parameters
|
||||
for (int i = 0; i < result.length; i++) result[i].getMutationOperator().crossoverOnStrategyParameters(indy1, partners);
|
||||
//for (int i = 0; i < result.length; i++) System.out.println("After Crossover: " +result[i].getSolutionRepresentationFor());
|
||||
return result;
|
||||
}
|
||||
|
||||
/** This method allows you to evaluate wether two crossover operators
|
||||
/**
|
||||
* Select the crossover points within the genotype of given length.
|
||||
* @param length
|
||||
* @param numberOfCrossovers
|
||||
* @return
|
||||
*/
|
||||
protected int[] getCrossoverPoints(int length, int numberOfCrossovers) {
|
||||
int[] crossoverPoints = new int[numberOfCrossovers];
|
||||
for (int i = 0; i < numberOfCrossovers; i++) {
|
||||
crossoverPoints[i] = RNG.randomInt(0, length-1);
|
||||
}
|
||||
return crossoverPoints;
|
||||
}
|
||||
|
||||
/** This method allows you to evaluate wether two crossover operators
|
||||
* are actually the same.
|
||||
* @param crossover The other crossover operator
|
||||
*/
|
||||
@ -114,7 +127,7 @@ public class CrossoverGANPoint implements InterfaceCrossover, java.io.Serializab
|
||||
* @param opt The optimization problem.
|
||||
*/
|
||||
public void init(AbstractEAIndividual individual, InterfaceOptimizationProblem opt) {
|
||||
this.m_OptimizationProblem = opt;
|
||||
// this.m_OptimizationProblem = opt;
|
||||
}
|
||||
|
||||
public String getStringRepresentation() {
|
||||
|
@ -0,0 +1,70 @@
|
||||
package eva2.server.go.operators.crossover;
|
||||
|
||||
import eva2.tools.math.RNG;
|
||||
|
||||
/**
|
||||
* A variation of the GA n-point crossover. Restricts crossover to segment bounds
|
||||
* of fixed length, so crossings occur at multiples of the segment length only. Segments
|
||||
* will not be destroyed.
|
||||
*
|
||||
* @author mkron
|
||||
*
|
||||
*/
|
||||
public class CrossoverGANPointSegmentwise extends CrossoverGANPoint {
|
||||
int segmentLength=8;
|
||||
|
||||
public CrossoverGANPointSegmentwise() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CrossoverGANPointSegmentwise(CrossoverGANPointSegmentwise o) {
|
||||
super(o);
|
||||
this.segmentLength=o.segmentLength;
|
||||
}
|
||||
|
||||
public CrossoverGANPointSegmentwise(int nPoints, int segmentLen) {
|
||||
super(nPoints);
|
||||
setSegmentLength(segmentLen);
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
return new CrossoverGANPointSegmentwise(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object crossover) {
|
||||
if (super.equals(crossover) && (crossover instanceof CrossoverGANPointSegmentwise)) {
|
||||
return ((CrossoverGANPointSegmentwise)crossover).segmentLength==this.segmentLength;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] getCrossoverPoints(int length, int numberOfCrossovers) {
|
||||
int[] cPoints = new int[numberOfCrossovers];
|
||||
int i=0;
|
||||
while (i<numberOfCrossovers && (i<length/segmentLength)) {
|
||||
cPoints[i]=segmentLength*RNG.randomInt(length/segmentLength);
|
||||
i++;
|
||||
}
|
||||
return cPoints;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "GA N-Point segment-wise crossover";
|
||||
}
|
||||
|
||||
public static String globalInfo() {
|
||||
return "This is an n-point crossover between m individuals which also splits at certain segment limits. Crossover points are selected from multiples of the segment length.";
|
||||
}
|
||||
|
||||
public int getSegmentLength() {
|
||||
return segmentLength;
|
||||
}
|
||||
public void setSegmentLength(int segmentLength) {
|
||||
this.segmentLength = segmentLength;
|
||||
}
|
||||
public String segmentLengthTipText() {
|
||||
return "The fixed length of segments (genes) which are not split by crossover.";
|
||||
}
|
||||
|
||||
}
|
@ -4,6 +4,7 @@ import java.util.BitSet;
|
||||
|
||||
import eva2.server.go.individuals.AbstractEAIndividual;
|
||||
import eva2.server.go.individuals.InterfaceGAIndividual;
|
||||
import eva2.server.go.individuals.InterfaceGIIndividual;
|
||||
import eva2.server.go.problems.InterfaceOptimizationProblem;
|
||||
import eva2.tools.EVAERROR;
|
||||
import eva2.tools.math.RNG;
|
||||
@ -65,23 +66,25 @@ public class GAInitializeSegmentwise implements InterfaceInitialization, java.io
|
||||
if (k<genotypeLen) genotype.set(k, nextSeg.get(k-i));
|
||||
}
|
||||
}
|
||||
// write back the genotype (it may have been cloned, who knows...)
|
||||
gaIndy.SetBGenotype(genotype);
|
||||
} else { // the number of bits to set may vary from segment to segment.
|
||||
if (bitsPerSegmentArray.length * segmentLength != genotypeLen) EVAERROR.errorMsgOnce("Warning, potential mismatch between segment lengths and genotype length in " + this.getClass());
|
||||
if (bitsPerSegmentArray.length * segmentLength < genotypeLen) System.err.println("Warning, " + (genotypeLen - bitsPerSegmentArray.length * segmentLength) + " bits will not be initialized!");
|
||||
for (int s=0; s<bitsPerSegmentArray.length; s++) {
|
||||
// look at each segment individually
|
||||
BitSet nextSeg=RNG.randomBitSet(bitsPerSegmentArray[s], bitsPerSegment);
|
||||
for (int k=(s)*bitsPerSegment; k<(s+1)*bitsPerSegment; k++) {
|
||||
if (k<genotypeLen) genotype.set(k, nextSeg.get(k-(s*bitsPerSegment)));
|
||||
BitSet nextSeg=RNG.randomBitSet(bitsPerSegmentArray[s], segmentLength);
|
||||
for (int k=(s)*segmentLength; k<(s+1)*segmentLength; k++) {
|
||||
if (k<genotypeLen) genotype.set(k, nextSeg.get(k-(s*segmentLength)));
|
||||
}
|
||||
}
|
||||
}
|
||||
// write back the genotype (it may have been cloned, who knows...)
|
||||
gaIndy.SetBGenotype(genotype);
|
||||
// System.out.println(genotype.cardinality());
|
||||
} else if (indy instanceof InterfaceGIIndividual) {
|
||||
// TODO ADD INTEGER IMPLEMENTATION???
|
||||
} else throw new RuntimeException("Error: "+ this.getClass() + " must be used with individuals of type " + InterfaceGAIndividual.class + "!");
|
||||
}
|
||||
|
||||
|
||||
public int[] getBitsPerSegmentArray() {
|
||||
return bitsPerSegmentArray;
|
||||
}
|
||||
|
@ -0,0 +1,219 @@
|
||||
package eva2.server.go.operators.mutation;
|
||||
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import eva2.server.go.individuals.AbstractEAIndividual;
|
||||
import eva2.server.go.individuals.InterfaceGAIndividual;
|
||||
import eva2.server.go.populations.Population;
|
||||
import eva2.server.go.problems.InterfaceOptimizationProblem;
|
||||
import eva2.tools.EVAERROR;
|
||||
import eva2.tools.math.RNG;
|
||||
|
||||
/**
|
||||
* Swap two random bits of a GA individual within subsequences (segments) of fixed length.
|
||||
* If preferPairs is true, unequal pairs
|
||||
* are picked with some preference (by trying for >= s/2 times, where s is the binary
|
||||
* segment length).
|
||||
* Multiple mutations per segment can occur if the boolean switch is activated, meaning
|
||||
* that further mutations are performed recursively with p_mut. Thus, the probability
|
||||
* to perform k mutations per segment is (p_mut)^k. However, more than s mutations per segment will
|
||||
* never be performed.
|
||||
*
|
||||
* User: mkron
|
||||
* Date: 05.08.2004
|
||||
* Time: 17:45:36
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class MutateGASwapBitsSegmentwise implements InterfaceMutation, java.io.Serializable {
|
||||
private double mutationProbPerSegment = 0.7;
|
||||
private boolean multiplesPerSegment = false;
|
||||
private int segmentLength = 8;
|
||||
private boolean preferPairs = true; // if true, pairs of (1,0) are swapped with higher probability
|
||||
|
||||
public MutateGASwapBitsSegmentwise() {
|
||||
|
||||
}
|
||||
public MutateGASwapBitsSegmentwise(MutateGASwapBitsSegmentwise mutator) {
|
||||
this.mutationProbPerSegment = mutator.mutationProbPerSegment;
|
||||
this.setPreferTrueChange(mutator.isPreferTrueChange());
|
||||
this.multiplesPerSegment = mutator.multiplesPerSegment;
|
||||
this.segmentLength = mutator.segmentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor setting all properties.
|
||||
*
|
||||
* @param p_mut
|
||||
* @param multPerSeg
|
||||
* @param segmentLen
|
||||
* @param prefPairs
|
||||
*/
|
||||
public MutateGASwapBitsSegmentwise(double p_mut, boolean multPerSeg, int segmentLen, boolean prefPairs) {
|
||||
mutationProbPerSegment=p_mut;
|
||||
multiplesPerSegment=multPerSeg;
|
||||
segmentLength=segmentLen;
|
||||
preferPairs=prefPairs;
|
||||
}
|
||||
|
||||
/** This method will enable you to clone a given mutation operator
|
||||
* @return The clone
|
||||
*/
|
||||
public Object clone() {
|
||||
return new MutateGASwapBitsSegmentwise(this);
|
||||
}
|
||||
|
||||
/** This method allows you to evaluate wether two mutation operators
|
||||
* are actually the same.
|
||||
* @param mutator The other mutation operator
|
||||
*/
|
||||
public boolean equals(Object mutator) {
|
||||
if (mutator instanceof MutateGASwapBitsSegmentwise) {
|
||||
MutateGASwapBitsSegmentwise mut = (MutateGASwapBitsSegmentwise)mutator;
|
||||
if (this.mutationProbPerSegment != mut.mutationProbPerSegment) return false;
|
||||
if (this.segmentLength != mut.segmentLength) return false;
|
||||
if (this.multiplesPerSegment != mut.multiplesPerSegment) return false;
|
||||
if (this.preferPairs != mut.preferPairs) return false;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
/** This method allows you to init the mutation operator
|
||||
* @param individual The individual that will be mutated.
|
||||
* @param opt The optimization problem.
|
||||
*/
|
||||
public void init(AbstractEAIndividual individual, InterfaceOptimizationProblem opt) {
|
||||
|
||||
}
|
||||
|
||||
/** This method allows you to perform either crossover on the strategy parameters
|
||||
* or to deal in some other way with the crossover event.
|
||||
* @param indy1 The original mother
|
||||
* @param partners The original partners
|
||||
*/
|
||||
public void crossoverOnStrategyParameters(AbstractEAIndividual indy1, Population partners) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
/** This method will mutate a given AbstractEAIndividual. If the individual
|
||||
* doesn't implement InterfaceGAIndividual nothing happens.
|
||||
* @param individual The individual that is to be mutated
|
||||
*/
|
||||
public void mutate(AbstractEAIndividual individual) {
|
||||
//System.out.println("Before Mutate: " +((GAIndividual)individual).getSolutionRepresentationFor());
|
||||
if (individual instanceof InterfaceGAIndividual) {
|
||||
BitSet tmpBitSet = ((InterfaceGAIndividual)individual).getBGenotype();
|
||||
int genLen=((InterfaceGAIndividual)individual).getGenotypeLength();
|
||||
for (int i=0; i<genLen; i+=segmentLength) {
|
||||
if (i+segmentLength>genLen) { // avoid to violate genotype length in a segment mutation
|
||||
EVAERROR.errorMsgOnce("Warning, genotype length is not a multiple of the segment length.. ignoring last bits in " + this.getClass());
|
||||
break;
|
||||
}
|
||||
if (RNG.flipCoin(mutationProbPerSegment)) {
|
||||
int cntMutes=0;
|
||||
// swap bits within a segment within certain probability
|
||||
do { // this may happen multiple times depending on the settings
|
||||
swapBitsInSegmentAt(tmpBitSet, i, segmentLength);
|
||||
cntMutes++;
|
||||
// multiples only if the corresponding switch is true and another flipCoin succeeds.
|
||||
// more than segmentLength mutations will never be performed per segment
|
||||
} while(multiplesPerSegment && cntMutes<segmentLength && RNG.flipCoin(mutationProbPerSegment));
|
||||
}
|
||||
}
|
||||
((InterfaceGAIndividual)individual).SetBGenotype(tmpBitSet); // write back the genotype
|
||||
}
|
||||
//System.out.println("After Mutate: " +((GAIndividual)individual).getSolutionRepresentationFor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap one pair of bits within an indicated segment.
|
||||
*
|
||||
* @param tmpBitSet
|
||||
* @param i
|
||||
* @param segmentLength2
|
||||
*/
|
||||
private void swapBitsInSegmentAt(BitSet bs, int i, int segLen) {
|
||||
int indexOne = getRandomIndex(bs, i, segLen, true); // may prefer true bits
|
||||
int indexTwo = getRandomIndex(bs, i, segLen, false); // may prefer false bits
|
||||
|
||||
boolean tmpBit = bs.get(indexTwo);
|
||||
bs.set(indexTwo, bs.get(indexOne));
|
||||
bs.set(indexOne, tmpBit);
|
||||
}
|
||||
|
||||
private int getRandomIndex(BitSet bs, int offset, int len, boolean maybePrefered) {
|
||||
int k = RNG.randomInt(offset, offset+len-1);
|
||||
if (isPreferTrueChange()) {
|
||||
int maxTries=(1+len)/2;
|
||||
while (!(maybePrefered==bs.get(k)) && (maxTries>=0)) {
|
||||
k=RNG.randomInt(offset, offset+len-1); ; // try next random position
|
||||
maxTries--;
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
// private int getRandomSecondIndex(int firstIndex, AbstractEAIndividual individual) {
|
||||
// int genoLen = ((InterfaceGAIndividual)individual).getGenotypeLength();
|
||||
// return RNG.randomInt(0, genoLen);
|
||||
// }
|
||||
|
||||
/** This method allows you to get a string representation of the mutation
|
||||
* operator
|
||||
* @return A descriptive string.
|
||||
*/
|
||||
public String getStringRepresentation() {
|
||||
return "GA swap bits segment-wise mutation";
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************
|
||||
* These are for GUI
|
||||
*/
|
||||
/** This method allows the CommonJavaObjectEditorPanel to read the
|
||||
* name to the current object.
|
||||
* @return The name.
|
||||
*/
|
||||
public String getName() {
|
||||
return "GA swap bits segment-wise mutation";
|
||||
}
|
||||
/** This method returns a global info string
|
||||
* @return description
|
||||
*/
|
||||
public static String globalInfo() {
|
||||
return "This mutation operator swaps bits in subsegments of the genotype.";
|
||||
}
|
||||
|
||||
public void setPreferTrueChange(boolean preferPairs) {
|
||||
this.preferPairs = preferPairs;
|
||||
}
|
||||
public boolean isPreferTrueChange() {
|
||||
return preferPairs;
|
||||
}
|
||||
public String preferTrueChangeTipText() {
|
||||
return "If set to true, mutation events will prefer swapping 1 and 0";
|
||||
}
|
||||
|
||||
public double getMutationProbPerSegment() {
|
||||
return mutationProbPerSegment;
|
||||
}
|
||||
public void setMutationProbPerSegment(double mutationProbPerSegment) {
|
||||
this.mutationProbPerSegment = mutationProbPerSegment;
|
||||
}
|
||||
|
||||
public boolean isMultiplesPerSegment() {
|
||||
return multiplesPerSegment;
|
||||
}
|
||||
public void setMultiplesPerSegment(boolean multiplesPerSegment) {
|
||||
this.multiplesPerSegment = multiplesPerSegment;
|
||||
}
|
||||
|
||||
public int getSegmentLength() {
|
||||
return segmentLength;
|
||||
}
|
||||
public void setSegmentLength(int segmentLength) {
|
||||
this.segmentLength = segmentLength;
|
||||
}
|
||||
public String segmentLengthTipText() {
|
||||
return "The length of sub-segments to regard (substrings of the GA genotype)";
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user