From e8c14b0aa8e80f1843e7a80bc1def861420d8966 Mon Sep 17 00:00:00 2001 From: Marcel Kronfeld Date: Wed, 19 Jan 2011 10:53:09 +0000 Subject: [PATCH] New GA mutation and crossover operators with subsegment-maintenance --- .../go/individuals/AbstractEAIndividual.java | 22 +- .../individuals/GAIndividualBinaryData.java | 7 +- .../crossover/CrossoverGANPoint.java | 45 ++-- .../CrossoverGANPointSegmentwise.java | 70 ++++++ .../GAInitializeSegmentwise.java | 15 +- .../mutation/MutateGASwapBitsSegmentwise.java | 219 ++++++++++++++++++ 6 files changed, 351 insertions(+), 27 deletions(-) create mode 100644 src/eva2/server/go/operators/crossover/CrossoverGANPointSegmentwise.java create mode 100644 src/eva2/server/go/operators/mutation/MutateGASwapBitsSegmentwise.java diff --git a/src/eva2/server/go/individuals/AbstractEAIndividual.java b/src/eva2/server/go/individuals/AbstractEAIndividual.java index 622c3712..e2814101 100644 --- a/src/eva2/server/go/individuals/AbstractEAIndividual.java +++ b/src/eva2/server/go/individuals/AbstractEAIndividual.java @@ -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); } /** diff --git a/src/eva2/server/go/individuals/GAIndividualBinaryData.java b/src/eva2/server/go/individuals/GAIndividualBinaryData.java index e22d61d2..a5bf62aa 100644 --- a/src/eva2/server/go/individuals/GAIndividualBinaryData.java +++ b/src/eva2/server/go/individuals/GAIndividualBinaryData.java @@ -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"; } diff --git a/src/eva2/server/go/operators/crossover/CrossoverGANPoint.java b/src/eva2/server/go/operators/crossover/CrossoverGANPoint.java index 782610fe..33559ff5 100644 --- a/src/eva2/server/go/operators/crossover/CrossoverGANPoint.java +++ b/src/eva2/server/go/operators/crossover/CrossoverGANPoint.java @@ -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() { diff --git a/src/eva2/server/go/operators/crossover/CrossoverGANPointSegmentwise.java b/src/eva2/server/go/operators/crossover/CrossoverGANPointSegmentwise.java new file mode 100644 index 00000000..cb49e657 --- /dev/null +++ b/src/eva2/server/go/operators/crossover/CrossoverGANPointSegmentwise.java @@ -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= 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; igenLen) { // 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=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)"; + } +} \ No newline at end of file