From 68241a0dc0d2b9bfb28bf1ed3a38fe158e6c9660 Mon Sep 17 00:00:00 2001 From: Marcel Kronfeld Date: Fri, 29 Aug 2008 14:04:32 +0000 Subject: [PATCH] Larger commit, adding IPOP-ES and RankMuCMA mutator. Revs. 130-174 from MK-branch should be merged with this. --- resources/EvolutionStrategies.html | 22 +- resources/EvolutionStrategyIPOP.html | 30 + resources/MutateESRankMuCMA.html | 33 + src/eva2/server/go/GOStandaloneVersion.java | 4 +- .../AbstractEAIndividualComparator.java | 27 +- .../InterfaceMutationGenerational.java | 15 + .../mutation/MutateESCorrolated.java | 34 +- .../MutateESCovarianceMatrixAdaption.java | 2 + .../mutation/MutateESFixedStepSize.java | 3 +- ...d.java => MutateESPathLengthAdaption.java} | 151 ++-- .../operators/mutation/MutateESRankMuCMA.java | 648 ++++++++++++++++++ .../operators/mutation/MutateESStandard.java | 241 ++++--- .../mutation/MutateESSuccessRule.java | 47 +- .../FitnessConvergenceTerminator.java | 8 + .../server/go/populations/Population.java | 3 + .../problems/AbstractOptimizationProblem.java | 2 +- .../CHCAdaptiveSearchAlgorithm.java | 6 +- .../go/strategies/ClusteringHillClimbing.java | 8 +- .../go/strategies/DifferentialEvolution.java | 8 +- .../go/strategies/EvolutionStrategies.java | 246 ++++--- .../go/strategies/EvolutionStrategyIPOP.java | 251 +++++++ .../strategies/EvolutionaryProgramming.java | 8 +- .../server/go/strategies/FloodAlgorithm.java | 8 +- .../go/strategies/GeneticAlgorithm.java | 20 +- .../strategies/GradientDescentAlgorithm.java | 8 +- .../server/go/strategies/HillClimbing.java | 12 +- .../go/strategies/InterfaceOptimizer.java | 8 +- .../server/go/strategies/IslandModelEA.java | 7 +- .../go/strategies/MemeticAlgorithm.java | 8 +- .../go/strategies/MonteCarloSearch.java | 8 +- .../ParticleFilterOptimization.java | 8 +- .../strategies/ParticleSwarmOptimization.java | 4 +- .../PopulationBasedIncrementalLearning.java | 6 +- .../go/strategies/SimulatedAnnealing.java | 8 +- .../server/go/strategies/SteadyStateGA.java | 8 +- .../go/strategies/ThresholdAlgorithm.java | 8 +- src/eva2/server/go/strategies/Tribes.java | 5 + src/eva2/tools/Mathematics.java | 12 + src/wsi/ra/math/Jama/Matrix.java | 62 +- 39 files changed, 1593 insertions(+), 404 deletions(-) create mode 100644 resources/EvolutionStrategyIPOP.html create mode 100644 resources/MutateESRankMuCMA.html create mode 100644 src/eva2/server/go/operators/mutation/InterfaceMutationGenerational.java rename src/eva2/server/go/operators/mutation/{MutateESDerandomized.java => MutateESPathLengthAdaption.java} (51%) create mode 100644 src/eva2/server/go/operators/mutation/MutateESRankMuCMA.java create mode 100644 src/eva2/server/go/strategies/EvolutionStrategyIPOP.java diff --git a/resources/EvolutionStrategies.html b/resources/EvolutionStrategies.html index 4ec6818b..712430e0 100644 --- a/resources/EvolutionStrategies.html +++ b/resources/EvolutionStrategies.html @@ -3,19 +3,23 @@ Evolution Strategy - ES

Evolution Strategy - ES


An ES works on a population of real valued solutions by repeated use of evolutionary operators like reproduction, -recombination and mutation (see pseudocode in figures. -lambda offspring individuals are generated from mu parents -by recombination and mutation. After evaluating the fitness of the lambda -offspring individuals, mu individuals with the best fitness are -selected by a comma-strategy to build the parent population for the next generation. -On the other hand, a plus-strategy selects the best mu individuals -from the aggregation of parents and offspring individuals. -The properties of ES are given in the population sub frame. +recombination and mutation. +λ offspring individuals are generated from μ parents +by recombination and mutation (with μ < λ). +
+After evaluating the fitness of the λ +offspring individuals, the comma-strategy selects the μ individuals +with the best fitness as parent population for the next generation. +On the other hand, a plus-strategy selects the best μ individuals +from the aggregation of parents and offspring individuals, so in this +case the best individual is guaranteed to survive. +In general, however, the comma-strategy is more robust and can easier +escape from local optima, which is why it is usually the standard selection. +
\ No newline at end of file diff --git a/resources/EvolutionStrategyIPOP.html b/resources/EvolutionStrategyIPOP.html new file mode 100644 index 00000000..eb9628b6 --- /dev/null +++ b/resources/EvolutionStrategyIPOP.html @@ -0,0 +1,30 @@ + + +Increasing Population Size ES - IPOP-ES + + +

Increasing Population Size ES - IPOP-ES

+
+

+

+This class implements the IPOP (increased population size) restart strategy ES, which increases +the ES population size (i.e., lambda) after phases of stagnation and then restarts the optimization +by reinitializing the individuals and operators.
+Stagnation is for this implementation defined by a FitnessConvergenceTerminator instance +which terminates if the absolute change in fitness is below a threshold (default 10e-12) for a +certain number of generations (default: 10+floor(30*n/lambda) for problem dimension n). +

+

+If the MutateESRankMuCMA mutation operator is employed, additional criteria are used for restarts, +such as numeric conditions of the covariance matrix. +Lambda is increased multiplicatively for every restart, and typical initial values are +mu=5, lambda=10, incFact=2. +The IPOP-CMA-ES won the CEC 2005 benchmark challenge. +Refer to Auger&Hansen 05 for more details. +

+
+A.Auger & N.Hansen. A Restart CMA Evolution Strategy With Increasing Population Size. CEC 2005. + + + + \ No newline at end of file diff --git a/resources/MutateESRankMuCMA.html b/resources/MutateESRankMuCMA.html new file mode 100644 index 00000000..7b63d861 --- /dev/null +++ b/resources/MutateESRankMuCMA.html @@ -0,0 +1,33 @@ + + +Covariance Matrix Adaptation with Rank-Mu-Update + + +

Covariance Matrix Adaptation with rank-mu update after Hansen & Kern 2004

+ +Implementing CMA ES with rank-mu-update and weighted recombination. This operator won the CEC 2005 +challenge employed with a restart scheme with increasing population size. +Basically, in each generation the population is resampled around the weighted center of the +last population using the adapted covariance matrix C. In contrast to earlier CMA versions, +this implementation only holds one single covariance matrix for the whole population, making +it much more memory efficient and useful for high dimensional problems as well. +
+While C is adapted based on a cumulated evolution path, the step size sigma is adapted based +on path length control. +Due to the repeated resampling starting from a single "center", the CMA version can +be interpreted as a sophisticated local search, if the initial solution set is sampled +close to an initial guess. In this case, a small initial sigma is favourable. +
+For multimodal problems, the initial population can be sampled randomly in the search space +and the initial sigma must be rather high. +To meet both conditions, the initial sigma may be set to half the average problem range +or to the average distance in the initial population. + +
+

+ + * N.Hansen & S.Kern 2004: Evaluating the CMA Evolution Strategy on Multimodal Test Functions. +Parallel Problem Solving from Nature 2004. + + + \ No newline at end of file diff --git a/src/eva2/server/go/GOStandaloneVersion.java b/src/eva2/server/go/GOStandaloneVersion.java index cedf89e6..a5431296 100644 --- a/src/eva2/server/go/GOStandaloneVersion.java +++ b/src/eva2/server/go/GOStandaloneVersion.java @@ -35,8 +35,8 @@ import eva2.server.go.individuals.GAIndividualDoubleData; import eva2.server.go.individuals.InterfaceDataTypeDouble; import eva2.server.go.operators.crossover.CrossoverGANPoint; import eva2.server.go.operators.mutation.InterfaceMutation; +import eva2.server.go.operators.mutation.MutateESFixedStepSize; import eva2.server.go.operators.mutation.MutateESLocal; -import eva2.server.go.operators.mutation.MutateESStandard; import eva2.server.go.operators.selection.SelectTournament; import eva2.server.go.operators.terminators.EvaluationTerminator; import eva2.server.go.populations.Population; @@ -304,7 +304,7 @@ public class GOStandaloneVersion implements InterfaceGOStandalone, InterfacePopu this.m_OutputPath = "results/"; // These are some tmp Variables InterfaceDataTypeDouble tmpIndy = new ESIndividualDoubleData(); - InterfaceMutation tmpMut = new MutateESStandard(); + InterfaceMutation tmpMut = new MutateESFixedStepSize(); switch (experimentType) { case 0 : { diff --git a/src/eva2/server/go/individuals/AbstractEAIndividualComparator.java b/src/eva2/server/go/individuals/AbstractEAIndividualComparator.java index e32f8e8b..69a2ece3 100644 --- a/src/eva2/server/go/individuals/AbstractEAIndividualComparator.java +++ b/src/eva2/server/go/individuals/AbstractEAIndividualComparator.java @@ -2,6 +2,19 @@ package eva2.server.go.individuals; import java.util.Comparator; +/** + * Comparator implementation which compares two individuals based on their fitness. + * The default version calls isDominatingDebConstraints() of the AbstractEAIndividual + * class and assigns -1 if first is dominant, 1 if second is dominant, 0 if the two ind.s + * are not comparable. + * As an alternative, a data key String may be set which is then used to request a data + * object from the individuals. The objects are interpreted as fitness vectors (double[]) and + * the comparison is based on those. This may be used to access alternative (e.g. older or + * best-so-far fitness values) for individual comparison. + * + * @author mkron + * + */ public class AbstractEAIndividualComparator implements Comparator { // flag whether a data field should be used. @@ -31,9 +44,21 @@ public class AbstractEAIndividualComparator implements Comparator { this.indyDataKey = indyDataKey; } + public AbstractEAIndividualComparator(AbstractEAIndividualComparator other) { + indyDataKey = other.indyDataKey; + } + + public Object clone() { + return new AbstractEAIndividualComparator(this); + } + /** - * Compare two individuals, return -1 if first is dominant, 1 if second is dominant, 0 if they + * Compare two individuals, return -1 if the first is dominant, 1 if the second is dominant, 0 if they * are not comparable. + * + * @param o1 the first AbstractEAIndividual to compare + * @param o2 the second AbstractEAIndividual to compare + * @return -1 if the first is dominant, 1 if the second is dominant, else 0 */ public int compare(Object o1, Object o2) { boolean o1domO2, o2domO1; diff --git a/src/eva2/server/go/operators/mutation/InterfaceMutationGenerational.java b/src/eva2/server/go/operators/mutation/InterfaceMutationGenerational.java new file mode 100644 index 00000000..40529a07 --- /dev/null +++ b/src/eva2/server/go/operators/mutation/InterfaceMutationGenerational.java @@ -0,0 +1,15 @@ +package eva2.server.go.operators.mutation; + +import eva2.server.go.populations.Population; + +/** + * An interface for a mutation operator which is updated on a generational basis, such as + * the 1/5-success rule. + * + * @author mkron + * + */ +public interface InterfaceMutationGenerational extends InterfaceMutation { + public void adaptAfterSelection(Population oldGen, Population selected); + public void adaptGenerational(Population selectedPop, Population parentPop, Population newPop, boolean updateSelected); +} diff --git a/src/eva2/server/go/operators/mutation/MutateESCorrolated.java b/src/eva2/server/go/operators/mutation/MutateESCorrolated.java index ba91423b..606cff81 100644 --- a/src/eva2/server/go/operators/mutation/MutateESCorrolated.java +++ b/src/eva2/server/go/operators/mutation/MutateESCorrolated.java @@ -18,8 +18,8 @@ public class MutateESCorrolated implements InterfaceMutation, java.io.Serializab protected double m_Tau1 = 0.15; protected double m_LowerLimitStepSize = 0.0000005; private static final long serialVersionUID = 1L; - private double[] m_Sigmas; - private double[] m_Alphas; + private double[] m_Sigmas = null; + private double[] m_Alphas = null; protected double m_Tau2 = 0.15; public MutateESCorrolated() { @@ -56,7 +56,7 @@ public class MutateESCorrolated implements InterfaceMutation, java.io.Serializab return new MutateESCorrolated(this); } - /** This method allows you to evaluate wether two mutation operators + /** This method allows you to evaluate whether two mutation operators * are actually the same. * @param mutator The other mutation operator */ @@ -85,7 +85,19 @@ public class MutateESCorrolated implements InterfaceMutation, java.io.Serializab * @param opt The optimization problem. */ public void init(AbstractEAIndividual individual, InterfaceOptimizationProblem opt) { - + if (individual instanceof InterfaceESIndividual) { + double[] x = ((InterfaceESIndividual)individual).getDGenotype(); + if (this.m_Sigmas == null) { + // init the Sigmas + this.m_Sigmas = new double[x.length]; + for (int i = 0; i < this.m_Sigmas.length; i++) this.m_Sigmas[i] = this.m_MutationStepSize; + } + if (this.m_Alphas == null) { + // init the Alphas + this.m_Alphas = new double[(x.length*(x.length-1))/2]; + for (int i = 0; i < this.m_Alphas.length; i++) this.m_Alphas[i] = 0.0; + } + } } /** This method will mutate a given AbstractEAIndividual. If the individual @@ -158,22 +170,12 @@ public class MutateESCorrolated implements InterfaceMutation, java.io.Serializab double[][] range = ((InterfaceESIndividual)individual).getDoubleRange(); double tmpR = RNG.gaussianDouble(1); - if (this.m_Sigmas == null) { - // init the Sigmas - this.m_Sigmas = new double[x.length]; - for (int i = 0; i < this.m_Sigmas.length; i++) this.m_Sigmas[i] = this.m_MutationStepSize; - } //Mutate Sigmas for (int i = 0; i < x.length; i++) { this.m_Sigmas[i] = this.m_Sigmas[i] * Math.exp(this.m_Tau1 * tmpR + this.m_Tau2 * RNG.gaussianDouble(1)); if (this.m_Sigmas[i] < this.m_LowerLimitStepSize) this.m_Sigmas[i] = this.m_LowerLimitStepSize; } - if (this.m_Alphas == null) { - // init the Alphas - this.m_Alphas = new double[(x.length*(x.length-1))/2]; - for (int i = 0; i < this.m_Alphas.length; i++) this.m_Alphas[i] = 0.0; - } //Mutate Alphas for (int i = 0; i < this.m_Alphas.length; i++) { this.m_Alphas[i] = this.m_Alphas[i] + RNG.gaussianDouble(0.2); @@ -230,7 +232,7 @@ public class MutateESCorrolated implements InterfaceMutation, java.io.Serializab sum+=j-i; sum--; return this.m_Alphas[sum]; }else{ - System.out.println("Falscher Zugriff auf Alphaliste!"); + System.err.println("Falscher Zugriff auf Alphaliste!"); return 0.0; } } @@ -240,7 +242,7 @@ public class MutateESCorrolated implements InterfaceMutation, java.io.Serializab * @return A descriptive string. */ public String getStringRepresentation() { - return "ES local mutation"; + return "ES local correlated mutation"; } /********************************************************************************************************************** diff --git a/src/eva2/server/go/operators/mutation/MutateESCovarianceMatrixAdaption.java b/src/eva2/server/go/operators/mutation/MutateESCovarianceMatrixAdaption.java index 8fef4f06..93f0d0f9 100644 --- a/src/eva2/server/go/operators/mutation/MutateESCovarianceMatrixAdaption.java +++ b/src/eva2/server/go/operators/mutation/MutateESCovarianceMatrixAdaption.java @@ -160,6 +160,7 @@ public class MutateESCovarianceMatrixAdaption implements InterfaceMutation, java double pathLen = 0.0; for (int i = 0; i < this.m_D; i++) this.s_N[i] = (1.0 - this.m_c) * this.s_N[i] + this.m_c * this.cu * this.Bz[i]; +// System.out.println("C bef:\n" + m_C.toString()); // ADAPT COVARIANCE for (int i = 0; i ranges[i][1]) x[i] = ranges[i][1]; - } + + this.adaptStrategy(); // this updates the path using the old step and adapts sigma + + this.calculateNewStep(); + + this.mutateX(x, ranges, true); // this performs new mutation + ((InterfaceESIndividual)individual).SetDGenotype(x); } //System.out.println("After Mutate: " +((GAIndividual)individual).getSolutionRepresentationFor()); } + + private void checkRange(double[] x, double[][] ranges) { + for (int i = 0; i < x.length; i++) { + if (x[i] < ranges[i][0]) x[i] = ranges[i][0]; + if (x[i] > ranges[i][1]) x[i] = ranges[i][1]; + } + } - /** This method allows you to perform either crossover on the strategy parameters + private void calculateNewStep() { + for (int i = 0; i < m_dim; i++) m_randZ[i] = RNG.gaussianDouble(1.0); + } + + /** 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 @@ -109,21 +138,23 @@ public class MutateESDerandomized implements InterfaceMutation, java.io.Serializ } private void adaptStrategy() { - double length_of_Z = 0; - for (int i = 0; i < m_D; i++) { - m_Path [i] = (1.0 -m_c) * m_Path[i] + Math.sqrt(m_c*(2.0-m_c))*m_Z[i]; - length_of_Z = length_of_Z + m_Path[i] * m_Path[i]; + // remember the path taken. m_randZ is at this time the last step before selection. + for (int i = 0; i < m_dim; i++) { + m_Path [i] = (1.0 -m_c) * m_Path[i] + m_cu*m_randZ[i]; } - length_of_Z = Math.sqrt(length_of_Z); - double E_of_length_of_Z = Math.sqrt(((double)m_D)+0.5); - double kappa_d = ((double)m_D)/4.0+1.0; - double Exponent = (length_of_Z - E_of_length_of_Z)/(kappa_d*E_of_length_of_Z); - m_SigmaGlobal = m_SigmaGlobal * Math.exp(Exponent); + double pathLen = Mathematics.norm(m_Path); + +// double expectedPathLen = Math.sqrt(((double)m_dim)+0.5); +// double kappa_d = ((double)m_dim)/4.0+1.0; + + double exp = (pathLen - expectedPathLen)/(dampening*expectedPathLen); + m_SigmaGlobal = m_SigmaGlobal * Math.exp(exp); } - private void evaluateNewObjectX(double[] x,double[][] range) { + private void mutateX(double[] x,double[][] range, boolean checkRange) { for (int i = 0; i < x.length; i++) - x[i] = x[i] + m_SigmaGlobal * m_Z[i]; + x[i] = x[i] + m_SigmaGlobal * m_randZ[i]; + if (checkRange) checkRange(x, range); } /** This method allows you to get a string representation of the mutation @@ -131,7 +162,7 @@ public class MutateESDerandomized implements InterfaceMutation, java.io.Serializ * @return A descriptive string. */ public String getStringRepresentation() { - return "CMA mutation"; + return "Mutation/Path-Length-Control"; } /********************************************************************************************************************** * These are for GUI @@ -141,27 +172,27 @@ public class MutateESDerandomized implements InterfaceMutation, java.io.Serializ * @return The name. */ public String getName() { - return "CMA mutation"; + return "Mutation/Path-Length-Control"; } /** This method returns a global info string * @return description */ public String globalInfo() { - return "This is the most sophisticated CMA mutation."; + return "The single step size is controlled using the evolution path."; } - /** Use only positive numbers this limits the freedom of effect. - * @param bit The new representation for the inner constants. - */ - public void setUsePath(boolean bit) { - this.m_UsePath = bit; - } - public boolean getUsePath() { - return this.m_UsePath; - } - public String usePathTipText() { - return "Use path."; - } +// /** Use only positive numbers this limits the freedom of effect. +// * @param bit The new representation for the inner constants. +// */ +// public void setUsePath(boolean bit) { +// this.m_UsePath = bit; +// } +// public boolean getUsePath() { +// return this.m_UsePath; +// } +// public String usePathTipText() { +// return "Use path."; +// } /** This method allows you to set the initial sigma value. * @param d The initial sigma value. @@ -173,6 +204,6 @@ public class MutateESDerandomized implements InterfaceMutation, java.io.Serializ return this.m_SigmaGlobal; } public String initSigmaGlobalTipText() { - return "Set the initial global sigma value."; + return "Set the initial global step size."; } } \ No newline at end of file diff --git a/src/eva2/server/go/operators/mutation/MutateESRankMuCMA.java b/src/eva2/server/go/operators/mutation/MutateESRankMuCMA.java new file mode 100644 index 00000000..e594682f --- /dev/null +++ b/src/eva2/server/go/operators/mutation/MutateESRankMuCMA.java @@ -0,0 +1,648 @@ +package eva2.server.go.operators.mutation; + +import java.io.Serializable; +import java.util.Arrays; + +import wsi.ra.math.RNG; +import wsi.ra.math.Jama.EigenvalueDecomposition; +import wsi.ra.math.Jama.Matrix; +import eva2.gui.BeanInspector; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.individuals.InterfaceDataTypeDouble; +import eva2.server.go.populations.Population; +import eva2.server.go.problems.InterfaceOptimizationProblem; +import eva2.tools.EVAERROR; +import eva2.tools.Mathematics; +import eva2.tools.Pair; + + +/** + * Implementing CMA ES with rank-mu-update and weighted recombination. This is partly based on the + * java implementation provided on http://www.bionik.tu-berlin.de/user/niko/cmaes_inmatlab.html. + * + * N.Hansen & S.Kern 2004: Evaluating the CMA Evolution Strategy on Multimodal Test Functions. + * Parallel Problem Solving from Nature 2004. + * + * @author mkron + * + */ +public class MutateESRankMuCMA implements InterfaceMutationGenerational, Serializable { + int dim; + private double c_c, expRandStepLen; + private double[] z, zCor; + + private InitialSigmaEnum initialSig = InitialSigmaEnum.avgInitialDistance; + private static double firstSigma = -1.; + private static double sigma; + private static double d_sig, c_sig; + private static double[] meanX, pathC, pathS, eigenvalues; + private static double[] weights = null; + private static double[][] range = null; + private static Matrix mC; + private static Matrix mB; +// private static double[] mBD; + private static boolean firstAdaptionDone = false; + private static boolean TRACE_1 = false; + private static boolean TRACE_2 = false; + private static boolean TRACE_TEST = false; +// private Matrix BD; + + public MutateESRankMuCMA() { + firstAdaptionDone = false; + } + + public MutateESRankMuCMA(MutateESRankMuCMA mutator) { + this.c_c = mutator.c_c; +// this.c_sig = mutator.c_sig; +// this.c_u_sig = mutator.c_u_sig; +// this.d_sig = mutator.d_sig; + this.expRandStepLen = mutator.expRandStepLen; + this.dim = mutator.dim; + this.initialSig = mutator.initialSig; + +// if (mutator.meanX != null) this.meanX = (double[]) mutator.meanX.clone(); +// if (mutator.pathC != null) this.pathC = (double[]) mutator.pathC.clone(); +// if (mutator.pathS != null) this.pathS = (double[]) mutator.pathS.clone(); + if (mutator.z != null) this.z = (double[]) mutator.z.clone(); + if (mutator.zCor != null) this.zCor = (double[]) mutator.zCor.clone(); +// if (mutator.eigenvalues != null) this.eigenvalues = (double[]) mutator.eigenvalues.clone(); +// if (mutator.mC != null) this.mC = (Matrix) mutator.mC.clone(); +// if (mutator.mB != null) this.mB = (Matrix) mutator.mB.clone(); + } + + public Object clone() { +// if (TRACE) System.out.println("WCMA clone"); + return new MutateESRankMuCMA(this); + } + + /** + * Retrieve the initial sigma for the given population and the user defined method. + * @param initGen + * @return + */ + private double getInitSigma(Population initGen) { + switch (initialSig) { + case avgInitialDistance: return initGen.getPopulationMeasures()[0]; + case halfRange: return getAvgRange()/2.; + default: return 0.2; + } + } + + public void adaptAfterSelection(Population oldGen, Population selectedP) { + Population selectedSorted = selectedP.getSortedBestFirst(); + + int mu,lambda; + mu = selectedP.size(); + lambda = oldGen.size(); + if (mu>= lambda) { + EVAERROR.errorMsgOnce("Warning: invalid mu/lambda ratio! Setting mu to lambda/2."); + mu = lambda/2; + } + if (!firstAdaptionDone) { + initWeights(mu, lambda); + double muEff = getMuEff(mu); + c_sig = (muEff+2)/(muEff+dim+3); +// c_u_sig = Math.sqrt(c_sig * (2.-c_sig)); + d_sig = c_sig+1+2*Math.max(0, Math.sqrt((muEff-1)/(dim+1)) - 1); + sigma = getInitSigma(oldGen); + firstSigma = sigma; + meanX = oldGen.getCenter(); // this might be ok? + } + + int generation = oldGen.getGeneration(); + + if (TRACE_1) { + System.out.println("WCMA adaptGenerational"); +// System.out.println("newPop measures: " + BeanInspector.toString(newPop.getPopulationMeasures())); + System.out.println("mu_eff: " + getMuEff(mu)); + System.out.println("meanX: " + BeanInspector.toString(meanX)); + System.out.println("pathC: " + BeanInspector.toString(pathC)); + System.out.println("pathS: " + BeanInspector.toString(pathS)); + } + + double[] newMeanX = calcMeanX(selectedSorted); + if (TRACE_1) System.out.println("newMeanX: " + BeanInspector.toString(newMeanX)); + + double[] BDz = new double[dim]; + for (int i=0; i 1) { + // selected pop is sorted + if (nearlySame(selected.getEAIndividual(0).getFitness(),selected.getEAIndividual(selected.size()-1).getFitness())) { + if (TRACE_1) System.err.println("flat fitness landscape, consider reformulation of fitness, step-size increased"); + sigma *= Math.exp(0.2+getCs()/getDamps()); +// sigma=0.1; + } + } + /* Align (renormalize) scale C (and consequently sigma) */ + /* e.g. for infinite stationary state simulations (noise + * handling needs to be introduced for that) */ + double fac = 1.; + double minEig = 1e-12; + double maxEig = 1e8; + if (Mathematics.max(eigenvalues) < minEig) + fac = 1./Math.sqrt(Mathematics.max(eigenvalues)); + else if (Mathematics.min(eigenvalues) > maxEig) + fac = 1./Math.sqrt(Mathematics.min(eigenvalues)); + + if (fac != 1.) { + System.err.println("Scaling by " + fac); + sigma /= fac; + for(int i = 0; i < dim; ++i) { + pathC[i] *= fac; + eigenvalues[i] *= fac*fac; + for (int j = 0; j <= i; ++j) { + mC.set(i, j, mC.get(i,j)*fac*fac); + if (i!=j) mC.set(j, i, mC.get(i,j)); + } + } + } + } // Test... + + private boolean nearlySame(double[] bestFitness, double[] worstFitness) { + double epsilon = 1e-14; + for (int i=0; iepsilon) return false; + return true; + } + + /** + * Return the range scaled sigma parameter for dimension i. + * + * @param i + * @return + */ + private double getSigma(int i) { + return sigma; + } + + private double getDamps() { + return d_sig; + } + + private double getCc() { + return c_c; + } + + private double getCs() { + return c_sig; + } + + private double calcExpRandStepLen() { + // scale by avg range? + return Math.sqrt(dim)*(1.-(1./(4*dim))+(1./(21*dim*dim))); + } + + private double getAvgRange() { + double sum = 0.; + for (int i=0; i 0) { + /* (only upper triangle!) */ + /* update covariance matrix */ + //System.out.println("CCov " + getCCov(selected) + " Cc " + getCc() + " muCov " + getMuCov(selected)); + for (int i = 0; i < dim; ++i) + for (int j = 0; j <= i; ++j) { +// oldVal = mC.get(i,j); + newVal = (1 - getCCov(mu)) * mC.get(i,j) + + getCCov(mu) + * (1. / getMuCov(mu)) + * (newPathC[i] * newPathC[j] + (1 - hsig) * getCc() + * (2. - getCc()) * mC.get(i,j)); + mC.set(i,j,newVal); + for (int k = 0; k < mu; ++k) { /* + * additional rank mu + * update + */ + double[] x_k = ((InterfaceDataTypeDouble)selected.getEAIndividual(k)).getDoubleData(); + newVal = mC.get(i,j)+ getCCov(mu) * (1 - 1. / getMuCov(mu)) + * getWeight(k) * (x_k[i] - meanX[i]) + * (x_k[j] - meanX[j]) / (getSigma(i) * getSigma(j)); // TODO right sigmas? + mC.set(i,j, newVal); + } + } + // fill rest of C + for (int i = 0; i < dim; ++i) { + for (int j = i+1; j < dim; ++j) { + + mC.set(i, j, mC.get(j,i)); + } + + } + if (mC.get(0,1) != mC.get(1,0)) { + System.err.println("WARNING"); + } +// maxsqrtdiagC = Math.sqrt(math.max(math.diag(C))); +// minsqrtdiagC = Math.sqrt(math.min(math.diag(C))); + } // update of C + + } + + private double getMuCov(int mu) { + // default parameter value ( HK03, sec. 2) + return getMuEff(mu); + } + + private double getCCov(int mu) { + // ( HK03, sec. 2) + //return Math.min(1., 2*getMuEff(selected)/(dim*dim)); + double ccov = (2./(getMuCov(mu)*Math.pow(dim+Math.sqrt(2.), 2)))+(1.-(1./getMuCov(mu)))*Math.min(1., (2*getMuEff(mu)-1.)/(dim*dim+2*dim+4+getMuEff(mu))); + return ccov; + } + + private double getMuEff(int mu) { + double res = 0, u; + for (int i=0; i 5) return repairMutation(x, range); // allow some nice tries before using brute force + else return mutate(x, range, count+1); // for really bad initial deviations this might be a quasi infinite loop + } + } + + private double[] repairMutation(double[] x, double[][] range) { +// TODO % You may handle constraints here. You may either resample +// % arz(:,k) and/or multiply it with a factor between -1 and 1 +// % (the latter will decrease the overall step size) and +// % recalculate arx accordingly. Do not change arx or arz in any +// % other way. + for (int i=0; irange[i][1]) x[i]=range[i][1]; + } + return x; + } + + private boolean isInRange(double[] x, double[][] range) { + for (int i=0; irange[i][1])) return false; + } + return true; + } + + /** + * After optimization start, this returns the initial sigma value + * actually employed. + * + * @return the initial sigma value actually employed + */ + public double getFirstSigma() { + return firstSigma; + } + + /** + * @return the initialSig + */ + public InitialSigmaEnum getInitialSigma() { + return initialSig; + } + + /** + * @param initialSig the initialSig to set + */ + public void setInitialSigma(InitialSigmaEnum initialSig) { + this.initialSig = initialSig; + } + + public String initialSigmaTipText() { + return "Method to use for setting the initial step size."; + } + + /** + * From Auger&Hansen, CEC '05, stopping criterion TolX. + * + * @param tolX + * @return + */ + public boolean testAllDistBelow(double tolX) { +// if all(sigma*(max(abs(pc), sqrt(diag(C)))) < stopTolX) + boolean res = true; + int i=0; + while (res && i= d. + * + * @param d + * @return true, if a diagonal entry is <= 0 or >= d, else false + */ + public boolean testCCondition(double d) { +// if (min(diag(D)) <= 0) || (max(diag(D)) > 1e14*min(diag(D))) +// stopflag(end+1) = {'warnconditioncov'}; + Pair minMax = mC.getMinMaxDiag(); + if ((minMax.head <= 0) || (minMax.tail >= d)) { + if (TRACE_TEST) System.out.println("testCCondition hit"); + return true; + } else return false; + } +} + +enum InitialSigmaEnum { + halfRange, avgInitialDistance; +} diff --git a/src/eva2/server/go/operators/mutation/MutateESStandard.java b/src/eva2/server/go/operators/mutation/MutateESStandard.java index 11fcda35..771212ef 100644 --- a/src/eva2/server/go/operators/mutation/MutateESStandard.java +++ b/src/eva2/server/go/operators/mutation/MutateESStandard.java @@ -1,121 +1,120 @@ -package eva2.server.go.operators.mutation; - -import eva2.server.go.individuals.AbstractEAIndividual; -import eva2.server.go.individuals.InterfaceDataTypeDouble; -import eva2.server.go.individuals.InterfaceESIndividual; -import eva2.server.go.populations.Population; -import eva2.server.go.problems.InterfaceOptimizationProblem; -import wsi.ra.math.RNG; - -/** - * Created by IntelliJ IDEA. - * User: streiche - * Date: 15.05.2003 - * Time: 17:04:24 - * To change this template use Options | File Templates. - */ -public class MutateESStandard implements InterfaceMutation, java.io.Serializable { - protected double m_MutationStepSize = 0.1; - - public MutateESStandard() { - } - - public MutateESStandard(MutateESStandard d) { - this.m_MutationStepSize = d.m_MutationStepSize; - } - - /** This method will enable you to clone a given mutation operator - * @return The clone - */ - public Object clone() { - return new MutateESStandard(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 MutateESStandard) { - MutateESStandard mut = (MutateESStandard)mutator; - if (this.m_MutationStepSize != mut.m_MutationStepSize) 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 will mutate a given AbstractEAIndividual. If the individual - * doesn't implement InterfaceESIndividual 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 InterfaceESIndividual) { - double[] x = ((InterfaceESIndividual)individual).getDGenotype(); - double[][] range = ((InterfaceESIndividual)individual).getDoubleRange(); - for (int i = 0; i < x.length; i++) { - x[i] += ((range[i][1] -range[i][0])/2)*RNG.gaussianDouble(this.m_MutationStepSize); - if (range[i][0] > x[i]) x[i] = range[i][0]; - if (range[i][1] < x[i]) x[i] = range[i][1]; - } - ((InterfaceESIndividual)individual).SetDGenotype(x); - - } - //System.out.println("After Mutate: " +((GAIndividual)individual).getSolutionRepresentationFor()); - } - - /** 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 allows you to get a string representation of the mutation - * operator - * @return A descriptive string. - */ - public String getStringRepresentation() { - return "ES standard 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 "ES standard mutation "; - } - /** This method returns a global info string - * @return description - */ - public String globalInfo() { - return "The standard mutation alters all elements of the double attributes with a fixed mutation step size."; - } - - /** This method allows you to set the fixed mutation step size - * @param step The new mutation step size - */ - public void setMutationStepSize(double step) { - if (step < 0) step = 0.0000001; - this.m_MutationStepSize = step; - } - public double getMutationStepSize() { - return this.m_MutationStepSize; - } - public String mutationStepSizeTipText() { - return "Set the value for the fixed mutation step size."; - } -} +//package eva2.server.go.operators.mutation; +// +//import eva2.server.go.individuals.AbstractEAIndividual; +//import eva2.server.go.individuals.InterfaceDataTypeDouble; +//import eva2.server.go.individuals.InterfaceESIndividual; +//import eva2.server.go.populations.Population; +//import eva2.server.go.problems.InterfaceOptimizationProblem; +//import wsi.ra.math.RNG; +// +///** +// * Created by IntelliJ IDEA. +// * User: streiche +// * Date: 15.05.2003 +// * Time: 17:04:24 +// * To change this template use Options | File Templates. +// */ +//public class MutateESStandard implements InterfaceMutation, java.io.Serializable { +// protected double m_MutationStepSize = 0.1; +// public MutateESStandard() { +// } +// +// public MutateESStandard(MutateESStandard d) { +// this.m_MutationStepSize = d.m_MutationStepSize; +// } +// +// /** This method will enable you to clone a given mutation operator +// * @return The clone +// */ +// public Object clone() { +// return new MutateESStandard(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 MutateESStandard) { +// MutateESStandard mut = (MutateESStandard)mutator; +// if (this.m_MutationStepSize != mut.m_MutationStepSize) 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 will mutate a given AbstractEAIndividual. If the individual +// * doesn't implement InterfaceESIndividual 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 InterfaceESIndividual) { +// double[] x = ((InterfaceESIndividual)individual).getDGenotype(); +// double[][] range = ((InterfaceESIndividual)individual).getDoubleRange(); +// for (int i = 0; i < x.length; i++) { +// x[i] += ((range[i][1] -range[i][0])/2)*RNG.gaussianDouble(this.m_MutationStepSize); +// if (range[i][0] > x[i]) x[i] = range[i][0]; +// if (range[i][1] < x[i]) x[i] = range[i][1]; +// } +// ((InterfaceESIndividual)individual).SetDGenotype(x); +// +// } +// //System.out.println("After Mutate: " +((GAIndividual)individual).getSolutionRepresentationFor()); +// } +// +// /** 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 allows you to get a string representation of the mutation +// * operator +// * @return A descriptive string. +// */ +// public String getStringRepresentation() { +// return "ES standard 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 "ES standard mutation "; +// } +// /** This method returns a global info string +// * @return description +// */ +// public String globalInfo() { +// return "The standard mutation alters all elements of the double attributes with a fixed mutation step size."; +// } +// +// /** This method allows you to set the fixed mutation step size +// * @param step The new mutation step size +// */ +// public void setMutationStepSize(double step) { +// if (step < 0) step = 0.0000001; +// this.m_MutationStepSize = step; +// } +// public double getMutationStepSize() { +// return this.m_MutationStepSize; +// } +// public String mutationStepSizeTipText() { +// return "Set the value for the fixed mutation step size."; +// } +//} diff --git a/src/eva2/server/go/operators/mutation/MutateESSuccessRule.java b/src/eva2/server/go/operators/mutation/MutateESSuccessRule.java index a197d30f..45cec399 100644 --- a/src/eva2/server/go/operators/mutation/MutateESSuccessRule.java +++ b/src/eva2/server/go/operators/mutation/MutateESSuccessRule.java @@ -14,11 +14,7 @@ import wsi.ra.math.RNG; * Time: 14:11:49 * To change this template use File | Settings | File Templates. */ -public class MutateESSuccessRule extends MutateESStandard implements InterfaceMutation, java.io.Serializable { -/* - * This is a bit of a cheat as the implementation does only hold some - * more parameters while the ES strategy really acts on it. - */ +public class MutateESSuccessRule extends MutateESFixedStepSize implements InterfaceMutationGenerational, java.io.Serializable { // it would be quite nice to make this variable static, but in that case // no one could runs n independent ES runs in parallel anymore *sigh* // protected static double m_MutationStepSize = 0.2; @@ -30,7 +26,7 @@ public class MutateESSuccessRule extends MutateESStandard implements InterfaceMu } public MutateESSuccessRule(MutateESSuccessRule mutator) { - this.m_MutationStepSize = mutator.m_MutationStepSize; + super(mutator); this.m_SuccessRate = mutator.m_SuccessRate; this.m_Alpha = mutator.m_Alpha; } @@ -49,12 +45,13 @@ public class MutateESSuccessRule extends MutateESStandard implements InterfaceMu public boolean equals(Object mutator) { if (mutator instanceof MutateESSuccessRule) { MutateESSuccessRule mut = (MutateESSuccessRule)mutator; - if (this.m_MutationStepSize != mut.m_MutationStepSize) return false; + if (this.m_Sigma != mut.m_Sigma) return false; if (this.m_SuccessRate != mut.m_SuccessRate) return false; if (this.m_Alpha != mut.m_Alpha) return false; return true; } else return false; } + /** This method allows you to get a string representation of the mutation * operator * @return A descriptive string. @@ -66,12 +63,12 @@ public class MutateESSuccessRule extends MutateESStandard implements InterfaceMu /** This method increases the mutation step size. */ public void increaseMutationStepSize() { - this.m_MutationStepSize = this.m_MutationStepSize * this.m_Alpha; + this.m_Sigma = this.m_Sigma * this.m_Alpha; } /** This method decrease the mutation step size. */ public void decreaseMutationStepSize() { - this.m_MutationStepSize = this.m_MutationStepSize / this.m_Alpha; + this.m_Sigma = this.m_Sigma / this.m_Alpha; } /********************************************************************************************************************** @@ -121,6 +118,36 @@ public class MutateESSuccessRule extends MutateESStandard implements InterfaceMu return this.m_Alpha; } public String alphaTipText() { - return "Choose the factor by which the mutation step size is to be increased/decreased."; + return "Choose the factor > 1 by which the mutation step size is to be increased/decreased."; } + + public void adaptAfterSelection(Population oldGen, Population selected) { + // nothing to do here + } + + public void adaptGenerational(Population selectedPop, Population parentPop, Population newPop, boolean updateSelected) { + double rate = 0.; + for (int i = 0; i < parentPop.size(); i++) { + // calculate success rate +// System.out.println("new fit / old fit: " + BeanInspector.toString(newPop.getEAIndividual(i).getFitness()) + " , " + BeanInspector.toString(parentPop.getEAIndividual(i).getFitness())); + if (newPop.getEAIndividual(i).getFitness(0) < parentPop.getEAIndividual(i).getFitness(0)) rate++; + } + rate = rate / parentPop.size(); + + if (updateSelected) for (int i = 0; i < selectedPop.size(); i++) { // applied to the old population as well in case of plus strategy + MutateESSuccessRule mutator = (MutateESSuccessRule)((AbstractEAIndividual)selectedPop.get(i)).getMutationOperator(); + updateMutator(rate, mutator); +// System.out.println("old pop step size " + mutator.getSigma()+ " (" + mutator+ ")"); + } + for (int i = 0; i < newPop.size(); i++) { + MutateESSuccessRule mutator = (MutateESSuccessRule)((AbstractEAIndividual)newPop.get(i)).getMutationOperator(); + updateMutator(rate, mutator); +// System.out.println("new pop step size " + mutator.getSigma()+ " (" + mutator+ ")"); + } + } + + private void updateMutator(double rate, MutateESSuccessRule mutator) { + if (rate < mutator.getSuccessRate()) mutator.decreaseMutationStepSize(); + else mutator.increaseMutationStepSize(); + } } \ No newline at end of file diff --git a/src/eva2/server/go/operators/terminators/FitnessConvergenceTerminator.java b/src/eva2/server/go/operators/terminators/FitnessConvergenceTerminator.java index bf92c656..143a7344 100644 --- a/src/eva2/server/go/operators/terminators/FitnessConvergenceTerminator.java +++ b/src/eva2/server/go/operators/terminators/FitnessConvergenceTerminator.java @@ -62,6 +62,14 @@ Serializable { else convergenceCondition.setSelectedTag("Relative"); } + public FitnessConvergenceTerminator(FitnessConvergenceTerminator other) { + pMetric = new PhenotypeMetric(); + convThresh = other.convThresh; + this.m_stagTime = other.m_stagTime; + stagnationMeasure.setSelectedTag(other.getStagnationMeasure().getSelectedTagID()); + convergenceCondition.setSelectedTag(other.getConvergenceCondition().getSelectedTagID()); + } + /** * */ diff --git a/src/eva2/server/go/populations/Population.java b/src/eva2/server/go/populations/Population.java index 7f114887..de2fe208 100644 --- a/src/eva2/server/go/populations/Population.java +++ b/src/eva2/server/go/populations/Population.java @@ -941,6 +941,9 @@ public class Population extends ArrayList implements PopulationInterface, Clonea /** * Fire an event every n function calls, the event sends the public String funCallIntervalReached. + * Be aware that if this interval is smaller than the population size, it may happen that a notification + * is fired before all individuals have been evaluated once, meaning that a false zero fitness + * appears at the beginning of the optimization. * * @param notifyEvalInterval the notifyEvalInterval to set */ diff --git a/src/eva2/server/go/problems/AbstractOptimizationProblem.java b/src/eva2/server/go/problems/AbstractOptimizationProblem.java index 4dc0890f..5b025183 100644 --- a/src/eva2/server/go/problems/AbstractOptimizationProblem.java +++ b/src/eva2/server/go/problems/AbstractOptimizationProblem.java @@ -56,7 +56,7 @@ public abstract class AbstractOptimizationProblem implements InterfaceOptimizati // System.err.println("Population evaluation seems not required!"); // } else { // @todo This is the position to implement a granular - // @todo paralliziation scheme + // @todo paralleliziation scheme evaluatePopulationStart(population); for (int i = 0; i < population.size(); i++) { tmpIndy = (AbstractEAIndividual) population.get(i); diff --git a/src/eva2/server/go/strategies/CHCAdaptiveSearchAlgorithm.java b/src/eva2/server/go/strategies/CHCAdaptiveSearchAlgorithm.java index 236987a7..e477ed66 100644 --- a/src/eva2/server/go/strategies/CHCAdaptiveSearchAlgorithm.java +++ b/src/eva2/server/go/strategies/CHCAdaptiveSearchAlgorithm.java @@ -90,8 +90,10 @@ public class CHCAdaptiveSearchAlgorithm implements InterfaceOptimizer, java.io.S System.out.println("Problem does not apply InterfaceGAIndividual, which is the only individual type valid for CHC!"); } - this.evaluatePopulation(this.m_Population); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.evaluatePopulation(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } } /** This method will evaluate the current population using the diff --git a/src/eva2/server/go/strategies/ClusteringHillClimbing.java b/src/eva2/server/go/strategies/ClusteringHillClimbing.java index e1ed74f6..f424865e 100644 --- a/src/eva2/server/go/strategies/ClusteringHillClimbing.java +++ b/src/eva2/server/go/strategies/ClusteringHillClimbing.java @@ -124,9 +124,11 @@ public class ClusteringHillClimbing implements InterfacePopulationChangedEventLi loopCnt = 0; this.m_Population = (Population)pop.clone(); m_Population.addPopulationChangedEventListener(null); - if (reset) this.m_Population.init(); - this.m_Problem.evaluate(this.m_Population); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.m_Population.init(); + this.m_Problem.evaluate(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } } /** Something has changed diff --git a/src/eva2/server/go/strategies/DifferentialEvolution.java b/src/eva2/server/go/strategies/DifferentialEvolution.java index 2cd48e54..347cdffc 100644 --- a/src/eva2/server/go/strategies/DifferentialEvolution.java +++ b/src/eva2/server/go/strategies/DifferentialEvolution.java @@ -93,11 +93,13 @@ public class DifferentialEvolution implements InterfaceOptimizer, java.io.Serial */ public void initByPopulation(Population pop, boolean reset) { this.m_Population = (Population)pop.clone(); - if (reset) this.m_Population.init(); + if (reset) { + this.m_Population.init(); + this.evaluatePopulation(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } // if (reset) this.m_Population.init(); // else children = new Population(m_Population.size()); - this.evaluatePopulation(this.m_Population); - this.firePropertyChangedEvent("NextGenerationPerformed"); } /** This method will evaluate the current population using the diff --git a/src/eva2/server/go/strategies/EvolutionStrategies.java b/src/eva2/server/go/strategies/EvolutionStrategies.java index 41fc7666..add9803b 100644 --- a/src/eva2/server/go/strategies/EvolutionStrategies.java +++ b/src/eva2/server/go/strategies/EvolutionStrategies.java @@ -1,7 +1,10 @@ package eva2.server.go.strategies; +import eva2.gui.BeanInspector; +import eva2.gui.GenericObjectEditor; import eva2.server.go.InterfacePopulationChangedEventListener; import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.operators.mutation.InterfaceMutationGenerational; import eva2.server.go.operators.mutation.MutateESSuccessRule; import eva2.server.go.operators.selection.InterfaceSelection; import eva2.server.go.operators.selection.SelectBestIndividuals; @@ -33,7 +36,6 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ //private double m_MyuRatio = 6; private int m_Mu = 5; private int m_Lambda = 20; - private int m_InitialPopulationSize = 0; private boolean m_UsePlusStrategy = false; private Population m_Population = new Population(); private InterfaceOptimizationProblem m_Problem = new B1Problem(); @@ -42,7 +44,7 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ private InterfaceSelection m_EnvironmentSelection = new SelectBestIndividuals(); private int m_NumberOfPartners = 1; private int origPopSize = -1; // especially for CBN - private double[] m_FitnessOfParents = null; +// private double[] m_FitnessOfParents = null; private boolean forceOrigPopSize = true;// especially for CBN transient private String m_Identifier = ""; @@ -64,7 +66,6 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ this.m_Problem = (InterfaceOptimizationProblem)a.m_Problem.clone(); this.m_Mu = a.m_Mu; this.m_Lambda = a.m_Lambda; - this.m_InitialPopulationSize = a.m_InitialPopulationSize; this.m_UsePlusStrategy = a.m_UsePlusStrategy; this.m_NumberOfPartners = a.m_NumberOfPartners; this.m_ParentSelection = (InterfaceSelection)a.m_ParentSelection.clone(); @@ -72,6 +73,10 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ this.m_EnvironmentSelection = (InterfaceSelection)a.m_EnvironmentSelection.clone(); } + public void hideHideable() { + GenericObjectEditor.setHideProperty(this.getClass(), "population", true); + } + public Object clone() { return (Object) new EvolutionStrategies(this); } @@ -86,7 +91,7 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ this.m_Problem.initPopulation(this.m_Population); this.evaluatePopulation(this.m_Population); // this.m_Population.setPopulationSize(orgPopSize); - this.firePropertyChangedEvent("NextGenerationPerformed"); +// this.firePropertyChangedEvent("NextGenerationPerformed");// not necessary if incrGeneration is called } @@ -98,9 +103,11 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ origPopSize = pop.getPopulationSize(); // System.out.println("ES: orig popsize is " + origPopSize); this.m_Population = (Population)pop.clone(); - if (reset) this.m_Population.init(); - this.evaluatePopulation(this.m_Population); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.m_Population.init(); + this.evaluatePopulation(this.m_Population); +// this.firePropertyChangedEvent("NextGenerationPerformed"); // not necessary if incrGeneration is called + } } /** This method will evaluate the current population using the @@ -129,94 +136,88 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ /** This method will generate the offspring population from the * given population of evaluated individuals. */ - private Population generateChildren() { - Population result = this.m_Population.cloneWithoutInds(), parents; + protected Population generateEvalChildren(Population fromPopulation) { + Population result = m_Population.cloneWithoutInds(), parents; AbstractEAIndividual[] offSprings; AbstractEAIndividual tmpIndy; result.clear(); - this.m_ParentSelection.prepareSelection(this.m_Population); - this.m_PartnerSelection.prepareSelection(this.m_Population); - parents = this.m_ParentSelection.selectFrom(this.m_Population, this.m_Lambda); + this.m_ParentSelection.prepareSelection(fromPopulation); + this.m_PartnerSelection.prepareSelection(fromPopulation); + parents = this.m_ParentSelection.selectFrom(fromPopulation, this.m_Lambda); + for (int i = 0; i < parents.size(); i++) { tmpIndy = (AbstractEAIndividual)parents.get(i); - if (tmpIndy == null) System.out.println("Individual null "+i); - if (parents == null) System.out.println("parents null "+i); - if (tmpIndy.getMutationOperator() instanceof MutateESSuccessRule) { - if (this.m_FitnessOfParents == null) this.m_FitnessOfParents = new double[this.m_Lambda]; - this.m_FitnessOfParents[i] = tmpIndy.getFitness(0); - } - offSprings = tmpIndy.mateWith(this.m_PartnerSelection.findPartnerFor(tmpIndy, this.m_Population, this.m_NumberOfPartners)); -// for (int j = 0; j < offSprings.length; j++) { -// offSprings[j].mutate(); -// } + offSprings = tmpIndy.mateWith(this.m_PartnerSelection.findPartnerFor(tmpIndy, fromPopulation, this.m_NumberOfPartners)); offSprings[0].mutate(); result.add(i, offSprings[0]); } + this.evaluatePopulation(result); + + if (result.getEAIndividual(0).getMutationOperator() instanceof InterfaceMutationGenerational) { + // this seems to be the right moment for the 1/5-success rule + // parents and result have the same size and correspond per individual + ((InterfaceMutationGenerational)parents.getEAIndividual(0).getMutationOperator()).adaptGenerational(fromPopulation, parents, result, m_UsePlusStrategy); + } + return result; } - + + protected Population selectParents() { + this.m_EnvironmentSelection.prepareSelection(this.m_Population); + return this.m_EnvironmentSelection.selectFrom(this.m_Population, this.m_Mu); + } + /** The optimize method will compute a 'improved' and evaluated population */ public void optimize() { Population nextGeneration, parents; -// // calculate myu and lambda from the current population size and settings -// if (this.m_UsePlusStrategy) { -// this.m_Myu = (int)Math.round((this.m_Population.size()/this.m_MyuRatio) - (this.m_Population.size()/Math.pow(this.m_MyuRatio, 2))); -// this.m_Myu = Math.max(1, this.m_Myu); -// this.m_Lambda = this.m_Population.size() - this.m_Myu; -//// System.out.println("Parameters: (Pop.size:"+this.m_Population.size()+"; MyuRatio:"+this.m_MyuRatio+")"); -//// System.out.println("Population Strategy: ("+ this.m_Myu+"+"+this.m_Lambda+")"); -// } -// else { -// this.m_Lambda = this.m_Population.size(); -// this.m_Myu = (int)Math.round(this.m_Population.size()/this.m_MyuRatio); -// this.m_Myu = Math.max(1, this.m_Myu); -//// System.out.println("Parameters: (Pop.size:"+this.m_Population.size()+"; MyuRatio:"+this.m_MyuRatio+")"); -//// System.out.println("Population Strategy: ("+ this.m_Myu+","+this.m_Lambda+")"); -// } //System.out.println("optimize"); // first perform the environment selection to select myu parents - this.m_EnvironmentSelection.prepareSelection(this.m_Population); - parents = this.m_EnvironmentSelection.selectFrom(this.m_Population, this.m_Mu); - this.m_Population.clear(); - this.m_Population.addPopulation(parents); + parents = selectParents(); +// System.out.println("-- selected avg fit " + BeanInspector.toString(parents.getMeanFitness()) + " from last gen " + BeanInspector.toString(m_Population.getMeanFitness())); + + // m_Population / parents are of sizes lambda / mu + if (parents.getEAIndividual(0).getMutationOperator() instanceof InterfaceMutationGenerational) { + ((InterfaceMutationGenerational)parents.getEAIndividual(0).getMutationOperator()).adaptAfterSelection(getPopulation(), parents); + } // now generate the lambda offsprings - this.m_FitnessOfParents = null; - nextGeneration = this.generateChildren(); - this.evaluatePopulation(nextGeneration); - if ((this.m_FitnessOfParents != null) && (((AbstractEAIndividual)parents.get(0)).getMutationOperator() instanceof MutateESSuccessRule)) { - double rate = 0; - - for (int i = 0; i < this.m_FitnessOfParents.length; i++) { - if (((AbstractEAIndividual)nextGeneration.get(i)).getFitness(0) < this.m_FitnessOfParents[i]) rate++; - } - this.applySuccessRule((rate/((double)this.m_FitnessOfParents.length)), this.m_Population, nextGeneration); - } - if (this.m_UsePlusStrategy) nextGeneration.addPopulation(this.m_Population); + nextGeneration = this.generateEvalChildren(parents); // create lambda new ones from mu parents - if (forceOrigPopSize && (origPopSize > 0) && (origPopSize < nextGeneration.size())) { - // this is especially for CBN: - this.m_EnvironmentSelection.prepareSelection(nextGeneration); - Population tmpPop = (Population)nextGeneration.clone(); - nextGeneration.clear(); - nextGeneration.addPopulation(this.m_EnvironmentSelection.selectFrom(tmpPop, origPopSize)); -// System.out.println("ES post selection! " + origPopSize + " from " + tmpPop.size()); - m_Population = nextGeneration; - } else { - if ((origPopSize > 0) && (origPopSize != nextGeneration.size())) { - System.err.println("Warning in ES! orig: " + origPopSize + " / " + nextGeneration.size()); - } - this.m_Population = nextGeneration; - } - //System.out.println("Population size: " + this.m_Population.size()); - //System.out.println("-- Best Fitness " + this.m_Population.getBestFitness()[0]); + if (this.isPlusStrategy()) nextGeneration.addPopulation(parents); + + setPop(getReplacePop(nextGeneration)); +// System.out.println("Population size: " + this.m_Population.size()); +// System.out.println("-- Best Fitness " + this.m_Population.getBestFitness()[0]); - this.firePropertyChangedEvent("NextGenerationPerformed"); + this.firePropertyChangedEvent("NextGenerationPerformed"); // necessary here because evalPop was not called on m_Population + } + + /** + * Usually, this just returns the given population. + * However, in case of CBN this method prepares the next generation according to the species size. + * + * @param nextGeneration + * @return + */ + protected Population getReplacePop(Population nextGeneration) { + if (forceOrigPopSize && (origPopSize > 0) && (origPopSize < nextGeneration.size())) { + // this is especially for CBN: + this.m_EnvironmentSelection.prepareSelection(nextGeneration); + Population tmpPop = (Population)nextGeneration.clone(); + nextGeneration.clear(); + nextGeneration.addPopulation(this.m_EnvironmentSelection.selectFrom(tmpPop, origPopSize)); +// System.out.println("ES post selection! " + origPopSize + " from " + tmpPop.size()); + } else { + if ((origPopSize > 0) && (origPopSize != nextGeneration.size())) { + System.err.println("Warning in ES! orig: " + origPopSize + " / " + nextGeneration.size()); + } + } + return nextGeneration; } /** This method is just a shortcut to set the mutation step size for @@ -227,46 +228,48 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ * @param oldPop The old population * @param newPop The new population */ - private void applySuccessRule(double successRate, Population oldPop, Population newPop) { - MutateESSuccessRule mutator = (MutateESSuccessRule)((AbstractEAIndividual)oldPop.get(0)).getMutationOperator(); - boolean success = (successRate < mutator.getSuccessRate()); - // this was the old solution when the mutation step size was still static -// if (successRate < mutator.getSuccessRate()) { -// mutator.decreaseMutationStepSize(); -// } else { -// mutator.increaseMutationStepSize(); +// private void applySuccessRule(double successRate, Population oldPop, Population newPop) { +// MutateESSuccessRule mutator = (MutateESSuccessRule)((AbstractEAIndividual)oldPop.get(0)).getMutationOperator(); +// boolean success = (successRate < mutator.getSuccessRate()); +// // this was the old solution when the mutation step size was still static +//// if (successRate < mutator.getSuccessRate()) { +//// mutator.decreaseMutationStepSize(); +//// } else { +//// mutator.increaseMutationStepSize(); +//// } +// if (isPlusStrategy()) for (int i = 0; i < oldPop.size(); i++) { // applied to the old population as well for plus strategy +// if (((AbstractEAIndividual)oldPop.get(i)).getMutationOperator() instanceof MutateESSuccessRule) { +// mutator = (MutateESSuccessRule)((AbstractEAIndividual)oldPop.get(i)).getMutationOperator(); +// if (success) mutator.decreaseMutationStepSize(); +// else mutator.increaseMutationStepSize(); +// System.out.println("old pop step size " + mutator.getSigma()+ " (" + mutator+ ")"); +// } // } - for (int i = 0; i < oldPop.size(); i++) { - if (((AbstractEAIndividual)oldPop.get(i)).getMutationOperator() instanceof MutateESSuccessRule) { - mutator = (MutateESSuccessRule)((AbstractEAIndividual)oldPop.get(i)).getMutationOperator(); - if (success) mutator.decreaseMutationStepSize(); - else mutator.increaseMutationStepSize(); - } - } - for (int i = 0; i < newPop.size(); i++) { - if (((AbstractEAIndividual)newPop.get(i)).getMutationOperator() instanceof MutateESSuccessRule) { - mutator = (MutateESSuccessRule)((AbstractEAIndividual)newPop.get(i)).getMutationOperator(); - if (success) mutator.decreaseMutationStepSize(); - else mutator.increaseMutationStepSize(); - } - } - this.m_FitnessOfParents = null; - } +// for (int i = 0; i < newPop.size(); i++) { +// if (((AbstractEAIndividual)newPop.get(i)).getMutationOperator() instanceof MutateESSuccessRule) { +// mutator = (MutateESSuccessRule)((AbstractEAIndividual)newPop.get(i)).getMutationOperator(); +// if (success) mutator.decreaseMutationStepSize(); +// else mutator.increaseMutationStepSize(); +// System.out.println("new pop step size " + mutator.getSigma() + " (" + mutator+ ")"); +// } +// } +//// this.m_FitnessOfParents = null; +// } - /** This is for debugging only - */ - private String showFitness(Population pop) { - String result = ""; - AbstractEAIndividual indy; - double[] fitness; - for (int i = 0; i < pop.size(); i++) { - indy = (AbstractEAIndividual)pop.get(i); - fitness = indy.getFitness(); - for (int j = 0; j < fitness.length; j++) result += fitness[j] +"; "; - result += "\n"; - } - return result; - } +// /** This is for debugging only +// */ +// private String showFitness(Population pop) { +// String result = ""; +// AbstractEAIndividual indy; +// double[] fitness; +// for (int i = 0; i < pop.size(); i++) { +// indy = (AbstractEAIndividual)pop.get(i); +// fitness = indy.getFitness(); +// for (int j = 0; j < fitness.length; j++) result += fitness[j] +"; "; +// result += "\n"; +// } +// return result; +// } /** This method allows you to add the LectureGUI as listener to the Optimizer * @param ea @@ -276,7 +279,7 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ } /** Something has changed */ - protected void firePropertyChangedEvent (String name) { + protected void firePropertyChangedEvent(String name) { if (this.m_Listener != null) this.m_Listener.registerPopulationStateChanged(this, name); } @@ -354,7 +357,7 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ * @return The name of the algorithm */ public String getName() { - return "("+getMu()+(getPlusStrategy() ? "+" : ",")+getLambda()+")-ES"; + return "("+getMu()+(isPlusStrategy() ? "+" : ",")+getLambda()+")-ES"; } /** @@ -366,6 +369,12 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ public Population getPopulation() { return this.m_Population; } + + // for internal usage + protected void setPop(Population pop) { + m_Population = pop; + } + public void setPopulation(Population pop){ origPopSize = pop.size(); // System.out.println("ES: orig popsize is " + origPopSize); @@ -437,7 +446,7 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ this.m_UsePlusStrategy = elitism; this.checkPopulationConstraints(); } - public boolean getPlusStrategy() { + public boolean isPlusStrategy() { return this.m_UsePlusStrategy; } public String plusStrategyTipText() { @@ -513,17 +522,4 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ public String lambdaTipText() { return "This is the children population size."; } - - /** Set an initial population size (if smaller lambda this is ignored). - * @param l The inital population size. - */ - public void setInitialPopulationSize(int l) { - this.m_InitialPopulationSize = l; - } - public int getInitialPopulationSize() { - return this.m_InitialPopulationSize; - } - public String initialPopulationSizeTipText() { - return "Set an initial population size (if smaller lambda this is ignored)."; - } } diff --git a/src/eva2/server/go/strategies/EvolutionStrategyIPOP.java b/src/eva2/server/go/strategies/EvolutionStrategyIPOP.java new file mode 100644 index 00000000..1abd54c9 --- /dev/null +++ b/src/eva2/server/go/strategies/EvolutionStrategyIPOP.java @@ -0,0 +1,251 @@ +package eva2.server.go.strategies; + +import java.util.Arrays; +import java.util.LinkedList; + +import eva2.gui.GenericObjectEditor; +import eva2.server.go.InterfacePopulationChangedEventListener; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.operators.mutation.MutateESRankMuCMA; +import eva2.server.go.operators.terminators.FitnessConvergenceTerminator; +import eva2.server.go.populations.Population; +import eva2.server.go.populations.SolutionSet; + +/** + * This implements the IPOP (increased population size restart) strategy ES, which increases + * the ES population size (lambda) after phases or stagnation and restarts the optimization. + * Stagnation is for this implementation defined by a FitnessConvergenceTerminator instance + * which terminates if the absolute change in fitness is below a threshold (default 10e-12) for a + * certain number of generations (default: 10+floor(30*n/lambda) for problem dimension n). + * + * If the MutateESRankMuCMA mutation operator is used, additional criteria are used for restarts, + * such as numeric conditions of the covariance matrix. + * Lambda is increased multiplicatively for every restart, and typical initial values are + * mu=5, lambda=10, incFact=2. + * The IPOP-CMA-ES won the CEC 2005 benchmark challenge. + * Refer to Auger&Hansen 05 for more details. + * + * A.Auger & N.Hansen. A Restart CMA Evolution Strategy With Increasing Population Size. CEC 2005. + * + * @author mkron + * + */ +public class EvolutionStrategyIPOP extends EvolutionStrategies implements InterfacePopulationChangedEventListener { + private static final long serialVersionUID = 4102736881931867818L; + int dim = -1; + int initialLambda = 10; + + private double stagThreshold = 10e-12; + private int stagTime = -1; + + double incPopSizeFact = 2.; + FitnessConvergenceTerminator fitConvTerm = null; + LinkedList bestList = null; + AbstractEAIndividual best = null; + + public EvolutionStrategyIPOP() { + super(); + setMu(5); + setLambda(10); + } + + public EvolutionStrategyIPOP(EvolutionStrategyIPOP other) { + dim = other.dim; + initialLambda = other.initialLambda; + incPopSizeFact = other.incPopSizeFact; + stagThreshold = other.stagThreshold; + stagTime = other.stagTime; + + if (other.fitConvTerm != null) fitConvTerm = new FitnessConvergenceTerminator(other.fitConvTerm); + } + + public Object clone() { + return new EvolutionStrategyIPOP(this); + } + + /** The optimize method will compute a 'improved' and evaluated population + */ + public void optimize() { +// Population nextGeneration, parents; +// +// // first perform the environment selection to select myu parents +// parents = selectParents(); +// +// // m_Population / parents are of sizes lambda / mu +// if (parents.getEAIndividual(0).getMutationOperator() instanceof InterfaceMutationGenerational) { +// ((InterfaceMutationGenerational)parents.getEAIndividual(0).getMutationOperator()).adaptAfterSelection(getPopulation(), parents); +// } +// +// // now generate the lambda offsprings +// nextGeneration = this.generateEvalChildren(parents); // create lambda new ones from mu parents +// +// if (this.isPlusStrategy()) nextGeneration.addPopulation(parents); +// +// setPop(getReplacePop(nextGeneration)); +// +// this.firePropertyChangedEvent("NextGenerationPerformed"); + ////////////////////////// + super.optimize(); + + // remember the best indy + if ((best == null) || !best.isDominating(getPopulation().getBestEAIndividual())) { + best = getPopulation().getBestEAIndividual(); + } + if (testIPOPStopCrit(getPopulation())) { + // reinitialize population with increased mu,lambda + boostPopSize(); + } + } + + public void hideHideable() { + GenericObjectEditor.setHideProperty(this.getClass(), "population", true); + } + + /** + * Reinitialize population with increased mu,lambda + **/ + private void boostPopSize() { + // increase by at least one + int newLambda = Math.max((int)(getLambda()*incPopSizeFact), getLambda() + 1); + super.setLambda(newLambda); + bestList.add(best); + best = null; + Population newPop = getPopulation().cloneWithoutInds(); + getProblem().initPopulation(newPop); + double[] badFit = getPopulation().getBestFitness().clone(); + Arrays.fill(badFit, Double.MAX_VALUE); + newPop.setAllFitnessValues(badFit); + getPopulation().clear(); + getPopulation().addAll(newPop); + getProblem().evaluate(getPopulation()); + } + + protected void firePropertyChangedEvent(String name) { + if (name.equals(Population.funCallIntervalReached)) { + super.firePropertyChangedEvent("NextGenerationPerformed"); + } + else {} // nothing, evt is produced in #registerPopulationStateChanged, dont forward original due to changing pop size + } + + public void init() { +// setMu(initialMu); + super.setLambda(initialLambda); + getPopulation().setNotifyEvalInterval(initialLambda); + super.init(); + bestList = new LinkedList(); + best = getPopulation().getBestEAIndividual(); + dim = AbstractEAIndividual.getDoublePosition(getPopulation().getEAIndividual(0)).length; + + stagTime = (int)(10+Math.floor(30*dim/getPopulation().size())); + + fitConvTerm = new FitnessConvergenceTerminator(stagThreshold, stagTime, false, true); // gen. based, absolute + getPopulation().addPopulationChangedEventListener(this); + getPopulation().setNotifyEvalInterval(initialLambda); + } + + /** + * Test for the IPOP stopping criteria. + * @param population + * @return + */ + private boolean testIPOPStopCrit(Population pop) { + int curGen = pop.getGeneration(); + MutateESRankMuCMA rcmaMute = null; + if (pop.getEAIndividual(0).getMutationOperator() instanceof MutateESRankMuCMA) { + rcmaMute = (MutateESRankMuCMA)pop.getEAIndividual(0).getMutationOperator(); + } + + // stop if the range of the best fitness of the last 10 + flor(30 n /lambda) generations is zero + // or if the range of these values and all fit values of the recent generation is below Tolfun = 10^-12 + //// interpret it a bit differently using FitnessConvergenceTerminator + if (fitConvTerm.isTerminated(new SolutionSet(pop))) { + return true; + } + + if (rcmaMute != null) { + // stop if the std dev of the normal distribution is smaller than TolX in all coords + // and sigma p_c is smaller than TolX in all components; TolX = 10^-12 sigma_0 + + if (rcmaMute.testAllDistBelow(10e-12*rcmaMute.getFirstSigma())) return true; + + // stop if adding a 0.1 std dev vector in a principal axis dir. of C does not change _w^g + if (rcmaMute.testNoChangeAddingDevAxis(0.1, curGen)) return true; + + // stop if adding a 0.2 std dev in each coordinate does (not???) change _w^g + if (rcmaMute.testNoEffectCoord(0.2)) return true; + + // stop if the condition number of C exceeds 10^14 + if (rcmaMute.testCCondition(10e14)) return true; + } + + return false; + } + + /** + * Returns the current population and a set of best individuals found (best current + * and best single ones before + * reinitializing the population after boosting the population size). + * + * @return A solution set of the current population and possibly earlier solutions + */ + public SolutionSet getAllSolutions() { + Population sols = getPopulation().cloneWithoutInds(); + if (bestList != null) sols.addAll(bestList); + if (best != null) sols.add(best); + else sols.add(getPopulation().getBestEAIndividual()); + + SolutionSet solSet = new SolutionSet(getPopulation(), sols); + return solSet; + } + + public void registerPopulationStateChanged(Object source, String name) { + if (name.equals(Population.funCallIntervalReached)) { + getPopulation().SetFunctionCalls(((Population)source).getFunctionCalls()); // TODO this is ugly + super.firePropertyChangedEvent(name); + } else { +// System.err.println("Not forwarding event " + name); + } + } + + public String getName() { + return "ES-IPOP"; + } + + public String globalInfo() { + return "An ES with increasing population size."; + } + + /** Set an initial population size (if smaller lambda this is ignored). + * @param l The inital population size. + */ + public void setInitialLambda(int l) { + initialLambda = l; + if (initialLambda < getMu()) setMu((initialLambda/2)+1); + } + + public int getInitialLambda() { + return initialLambda; + } + + public String initialLambdaTipText() { + return "Set the initial population size (lambda); mu should be about lambda/2"; + } + + /** + * @return the incPopSizeFact + */ + public double getIncPopSizeFact() { + return incPopSizeFact; + } + + /** + * @param incPopSizeFact the incPopSizeFact to set + */ + public void setIncPopSizeFact(double incPopSizeFact) { + this.incPopSizeFact = incPopSizeFact; + } + + public String incPopSizeFactTipText() { + return "Factor by which to increase lambda for each restart event, default is 2."; + } +} diff --git a/src/eva2/server/go/strategies/EvolutionaryProgramming.java b/src/eva2/server/go/strategies/EvolutionaryProgramming.java index bebfae3f..f9cfe261 100644 --- a/src/eva2/server/go/strategies/EvolutionaryProgramming.java +++ b/src/eva2/server/go/strategies/EvolutionaryProgramming.java @@ -58,9 +58,11 @@ public class EvolutionaryProgramming implements InterfaceOptimizer, java.io.Seri */ public void initByPopulation(Population pop, boolean reset) { this.m_Population = (Population)pop.clone(); - if (reset) this.m_Population.init(); - this.evaluatePopulation(this.m_Population); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.m_Population.init(); + this.evaluatePopulation(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } } /** This method will evaluate the current population using the diff --git a/src/eva2/server/go/strategies/FloodAlgorithm.java b/src/eva2/server/go/strategies/FloodAlgorithm.java index eccbcce7..1df5152f 100644 --- a/src/eva2/server/go/strategies/FloodAlgorithm.java +++ b/src/eva2/server/go/strategies/FloodAlgorithm.java @@ -67,10 +67,12 @@ public class FloodAlgorithm implements InterfaceOptimizer, java.io.Serializable */ public void initByPopulation(Population pop, boolean reset) { this.m_Population = (Population)pop.clone(); - if (reset) this.m_Population.init(); - this.m_Problem.evaluate(this.m_Population); + if (reset) { + this.m_Population.init(); + this.m_Problem.evaluate(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } this.m_CurrentFloodPeak = this.m_InitialFloodPeak; - this.firePropertyChangedEvent("NextGenerationPerformed"); } /** This method will optimize diff --git a/src/eva2/server/go/strategies/GeneticAlgorithm.java b/src/eva2/server/go/strategies/GeneticAlgorithm.java index de7aa4e2..20bd3286 100644 --- a/src/eva2/server/go/strategies/GeneticAlgorithm.java +++ b/src/eva2/server/go/strategies/GeneticAlgorithm.java @@ -3,6 +3,7 @@ package eva2.server.go.strategies; import eva2.server.go.InterfacePopulationChangedEventListener; import eva2.server.go.individuals.AbstractEAIndividual; import eva2.server.go.individuals.GAIndividualBinaryData; +import eva2.server.go.operators.mutation.InterfaceMutationGenerational; import eva2.server.go.operators.selection.InterfaceSelection; import eva2.server.go.operators.selection.SelectTournament; import eva2.server.go.populations.InterfaceSolutionSet; @@ -66,9 +67,11 @@ public class GeneticAlgorithm implements InterfaceOptimizer, java.io.Serializabl */ public void initByPopulation(Population pop, boolean reset) { this.m_Population = (Population)pop.clone(); - if (reset) this.m_Population.init(); - this.evaluatePopulation(this.m_Population); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.m_Population.init(); + this.evaluatePopulation(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } } /** This method will evaluate the current population using the @@ -110,6 +113,10 @@ public class GeneticAlgorithm implements InterfaceOptimizer, java.io.Serializabl parents = this.m_ParentSelection.selectFrom(this.m_Population, this.m_Population.getPopulationSize()); //System.out.println("Parents:"+parents.getSolutionRepresentationFor()); + if (parents.getEAIndividual(0).getMutationOperator() instanceof InterfaceMutationGenerational) { + ((InterfaceMutationGenerational)parents.getEAIndividual(0).getMutationOperator()).adaptAfterSelection(m_Population, parents); + } + for (int i = 0; i < parents.size(); i++) { tmpIndy = ((AbstractEAIndividual)parents.get(i)); if (tmpIndy == null) System.out.println("Individual null " + i + " Population size: "+ parents.size()); @@ -121,13 +128,18 @@ public class GeneticAlgorithm implements InterfaceOptimizer, java.io.Serializabl } result.add(i, offSprings[0]); } + this.evaluatePopulation(result); + + if (parents.getEAIndividual(0).getMutationOperator() instanceof InterfaceMutationGenerational) { + ((InterfaceMutationGenerational)parents.getEAIndividual(0).getMutationOperator()).adaptGenerational(m_Population, parents, result, true); + } return result; } public void optimize() { Population nextGeneration; nextGeneration = this.generateChildren(); - this.evaluatePopulation(nextGeneration); + if (this.m_UseElitism) { AbstractEAIndividual elite = this.m_Population.getBestEAIndividual(); if (elite != null) { diff --git a/src/eva2/server/go/strategies/GradientDescentAlgorithm.java b/src/eva2/server/go/strategies/GradientDescentAlgorithm.java index 8d741fc0..d8f2cd89 100644 --- a/src/eva2/server/go/strategies/GradientDescentAlgorithm.java +++ b/src/eva2/server/go/strategies/GradientDescentAlgorithm.java @@ -53,9 +53,11 @@ public class GradientDescentAlgorithm implements InterfaceOptimizer, java.io.Ser public void initByPopulation(Population pop, boolean reset) { this.setPopulation((Population) pop.clone()); - if (reset) this.getPopulation().init(); - this.m_Problem.evaluate(this.getPopulation()); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.getPopulation().init(); + this.m_Problem.evaluate(this.getPopulation()); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } //System.out.println("initByPopulation() called"); indyhash = new Hashtable(); } diff --git a/src/eva2/server/go/strategies/HillClimbing.java b/src/eva2/server/go/strategies/HillClimbing.java index 15928cb2..8598ad2c 100644 --- a/src/eva2/server/go/strategies/HillClimbing.java +++ b/src/eva2/server/go/strategies/HillClimbing.java @@ -58,15 +58,13 @@ public class HillClimbing implements InterfaceOptimizer, java.io.Serializable { this.firePropertyChangedEvent("NextGenerationPerformed"); } - /** This method will init the optimizer with a given population - * @param pop The initial population - * @param reset If true the population is reset. - */ public void initByPopulation(Population pop, boolean reset) { this.m_Population = (Population)pop.clone(); - if (reset) this.m_Population.init(); - this.m_Problem.evaluate(this.m_Population); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.m_Population.init(); + this.m_Problem.evaluate(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } } /** This method will optimize diff --git a/src/eva2/server/go/strategies/InterfaceOptimizer.java b/src/eva2/server/go/strategies/InterfaceOptimizer.java index bb96d06b..1a106fc1 100644 --- a/src/eva2/server/go/strategies/InterfaceOptimizer.java +++ b/src/eva2/server/go/strategies/InterfaceOptimizer.java @@ -38,9 +38,11 @@ public interface InterfaceOptimizer { */ public void init(); - /** This method will init the optimizer with a given population + /** + * This method will init the optimizer with a given population. + * * @param pop The initial population - * @param reset If true the population is reset. + * @param reset If true the population is reinitialized and reevaluated. */ public void initByPopulation(Population pop, boolean reset); @@ -66,7 +68,7 @@ public interface InterfaceOptimizer { * May return the the same set as getPopulation if the optimizer makes no distinction, i.e. does * not collect solutions outside the current population. * - * @return A population of found solutions. + * @return A solution set of the current population and possibly earlier solutions. */ public InterfaceSolutionSet getAllSolutions(); diff --git a/src/eva2/server/go/strategies/IslandModelEA.java b/src/eva2/server/go/strategies/IslandModelEA.java index 19a37754..177f5263 100644 --- a/src/eva2/server/go/strategies/IslandModelEA.java +++ b/src/eva2/server/go/strategies/IslandModelEA.java @@ -142,6 +142,7 @@ public class IslandModelEA implements InterfacePopulationChangedEventListener, I * @param reset If true the population is reset. */ public void initByPopulation(Population tpop, boolean reset) { + // TODO this is again evil copy&paste style if (this.m_Show) { if (this.m_Plot == null) { double[] tmpD = new double[2]; @@ -152,8 +153,10 @@ public class IslandModelEA implements InterfacePopulationChangedEventListener, I } this.m_Population = (Population)tpop.clone(); - if (reset) this.m_Population.init(); - this.m_Population.incrGeneration(); + if (reset) { + this.m_Population.init(); + this.m_Population.incrGeneration(); + } this.m_Optimizer.init(); this.m_Optimizer.SetProblem(this.m_Problem); InterfacePopulationChangedEventListener myLocal = null; diff --git a/src/eva2/server/go/strategies/MemeticAlgorithm.java b/src/eva2/server/go/strategies/MemeticAlgorithm.java index 579fd2ce..d264d4b9 100644 --- a/src/eva2/server/go/strategies/MemeticAlgorithm.java +++ b/src/eva2/server/go/strategies/MemeticAlgorithm.java @@ -89,9 +89,11 @@ public class MemeticAlgorithm implements InterfaceOptimizer, public void initByPopulation(Population pop, boolean reset) { this.setPopulation((Population) pop.clone()); - if (reset) this.getPopulation().init(); - this.m_Problem.evaluate(this.getPopulation()); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.getPopulation().init(); + this.m_Problem.evaluate(this.getPopulation()); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } } public void init() { diff --git a/src/eva2/server/go/strategies/MonteCarloSearch.java b/src/eva2/server/go/strategies/MonteCarloSearch.java index 43ece97b..5bd13dc6 100644 --- a/src/eva2/server/go/strategies/MonteCarloSearch.java +++ b/src/eva2/server/go/strategies/MonteCarloSearch.java @@ -64,9 +64,11 @@ public class MonteCarloSearch implements InterfaceOptimizer, java.io.Serializabl */ public void initByPopulation(Population pop, boolean reset) { this.m_Population = (Population)pop.clone(); - if (reset) this.m_Population.init(); - this.m_Problem.evaluate(this.m_Population); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.m_Population.init(); + this.m_Problem.evaluate(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } } /** This method will optimize diff --git a/src/eva2/server/go/strategies/ParticleFilterOptimization.java b/src/eva2/server/go/strategies/ParticleFilterOptimization.java index c5c68433..4429fbe2 100644 --- a/src/eva2/server/go/strategies/ParticleFilterOptimization.java +++ b/src/eva2/server/go/strategies/ParticleFilterOptimization.java @@ -85,9 +85,11 @@ public class ParticleFilterOptimization implements InterfaceOptimizer, java.io.S */ public void initByPopulation(Population pop, boolean reset) { this.m_Population = (Population)pop.clone(); - if (reset) this.m_Population.init(); - this.evaluatePopulation(this.m_Population); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.m_Population.init(); + this.evaluatePopulation(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } } /** This method will evaluate the current population using the diff --git a/src/eva2/server/go/strategies/ParticleSwarmOptimization.java b/src/eva2/server/go/strategies/ParticleSwarmOptimization.java index 5f704920..22f5bd48 100644 --- a/src/eva2/server/go/strategies/ParticleSwarmOptimization.java +++ b/src/eva2/server/go/strategies/ParticleSwarmOptimization.java @@ -372,7 +372,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se indy.SetData(indexKey, i); indy.setIndividualIndex(i); } - this.evaluatePopulation(this.m_Population); + if (reset) this.evaluatePopulation(this.m_Population); for (int i = 0; i < this.m_Population.size(); i++) { indy = (AbstractEAIndividual) this.m_Population.get(i); @@ -382,7 +382,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se } this.m_BestIndividual = (AbstractEAIndividual)this.m_Population.getBestEAIndividual().clone(); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) this.firePropertyChangedEvent("NextGenerationPerformed"); treeLevels = 0; // the HPSO tree will contain layers 0...HPSOLevels, the last one is "incomplete" with only HPSOOrphans number of nodes diff --git a/src/eva2/server/go/strategies/PopulationBasedIncrementalLearning.java b/src/eva2/server/go/strategies/PopulationBasedIncrementalLearning.java index 7597e7d7..6c447a90 100644 --- a/src/eva2/server/go/strategies/PopulationBasedIncrementalLearning.java +++ b/src/eva2/server/go/strategies/PopulationBasedIncrementalLearning.java @@ -72,10 +72,12 @@ public class PopulationBasedIncrementalLearning implements InterfaceOptimizer, j System.err.println("Error: PBIL only works with GAIndividuals!"); } this.m_Population = new PBILPopulation(); - if (reset) this.m_Population.init(); this.m_Population.addPopulation((Population)pop.clone()); + if (reset) { + this.m_Population.init(); + this.evaluatePopulation(this.m_Population); + } ((PBILPopulation)this.m_Population).buildProbabilityVector(); - this.evaluatePopulation(this.m_Population); this.firePropertyChangedEvent("NextGenerationPerformed"); } diff --git a/src/eva2/server/go/strategies/SimulatedAnnealing.java b/src/eva2/server/go/strategies/SimulatedAnnealing.java index 3dbcb422..233d4775 100644 --- a/src/eva2/server/go/strategies/SimulatedAnnealing.java +++ b/src/eva2/server/go/strategies/SimulatedAnnealing.java @@ -67,10 +67,12 @@ public class SimulatedAnnealing implements InterfaceOptimizer, java.io.Serializa */ public void initByPopulation(Population pop, boolean reset) { this.m_Population = (Population)pop.clone(); - if (reset) this.m_Population.init(); - this.m_Problem.evaluate(this.m_Population); this.m_CurrentTemperature = this.m_InitialTemperature; - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.m_Population.init(); + this.m_Problem.evaluate(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } } /** This method will optimize diff --git a/src/eva2/server/go/strategies/SteadyStateGA.java b/src/eva2/server/go/strategies/SteadyStateGA.java index 12b2a004..5f572122 100644 --- a/src/eva2/server/go/strategies/SteadyStateGA.java +++ b/src/eva2/server/go/strategies/SteadyStateGA.java @@ -62,9 +62,11 @@ public class SteadyStateGA implements InterfaceOptimizer, java.io.Serializable { */ public void initByPopulation(Population pop, boolean reset) { this.m_Population = (Population)pop.clone(); - if (reset) this.m_Population.init(); - this.evaluatePopulation(this.m_Population); - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.m_Population.init(); + this.evaluatePopulation(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } } /** This method will evaluate the current population using the diff --git a/src/eva2/server/go/strategies/ThresholdAlgorithm.java b/src/eva2/server/go/strategies/ThresholdAlgorithm.java index b0dc5fd8..3e96fd64 100644 --- a/src/eva2/server/go/strategies/ThresholdAlgorithm.java +++ b/src/eva2/server/go/strategies/ThresholdAlgorithm.java @@ -65,10 +65,12 @@ public class ThresholdAlgorithm implements InterfaceOptimizer, java.io.Serializa */ public void initByPopulation(Population pop, boolean reset) { this.m_Population = (Population)pop.clone(); - if (reset) this.m_Population.init(); - this.m_Problem.evaluate(this.m_Population); this.m_CurrentT = this.m_InitialT; - this.firePropertyChangedEvent("NextGenerationPerformed"); + if (reset) { + this.m_Population.init(); + this.m_Problem.evaluate(this.m_Population); + this.firePropertyChangedEvent("NextGenerationPerformed"); + } } /** This method will optimize diff --git a/src/eva2/server/go/strategies/Tribes.java b/src/eva2/server/go/strategies/Tribes.java index 2805b0ca..a4cc2eb0 100644 --- a/src/eva2/server/go/strategies/Tribes.java +++ b/src/eva2/server/go/strategies/Tribes.java @@ -240,6 +240,11 @@ public class Tribes implements InterfaceOptimizer, java.io.Serializable { } + /** + * As TRIBES manages an own structured set of particles (the list of Tribes containing explorers + * and memories), the setPopulation method is only telling Tribes the range + * of the indiviuals in the beginning of the run, the individuals will be discarded. + */ public void initByPopulation(Population pop, boolean reset) { setPopulation(pop); } diff --git a/src/eva2/tools/Mathematics.java b/src/eva2/tools/Mathematics.java index 107aaca2..56b5025e 100644 --- a/src/eva2/tools/Mathematics.java +++ b/src/eva2/tools/Mathematics.java @@ -675,4 +675,16 @@ public class Mathematics { } return A; } + + public static double max(double[] vals) { + double maxVal = vals[0]; + for (int i=1; i getMinMaxDiag() { + if (m<1 || n<1) return null; + + double v = get(0,0); + Pair ret = new Pair(v,v); + for (int i=1; i