diff --git a/src/eva2/server/go/operators/terminators/DiversityTerminator.java b/src/eva2/server/go/operators/terminators/DiversityTerminator.java index 3e6ea263..d3e08baa 100644 --- a/src/eva2/server/go/operators/terminators/DiversityTerminator.java +++ b/src/eva2/server/go/operators/terminators/DiversityTerminator.java @@ -13,8 +13,8 @@ import eva2.tools.SelectedTag; /** * The diversity terminator uses the distance of individuals - * in the population as termination criterion. If the average distance - * sinks below the given limit, the optimization stops. + * in the population as termination criterion. If the average (min./max.) distance + * stagnates, the optimization stops. * May be computationally expensive. * * @see Population.getPopulationMeasures() @@ -22,88 +22,26 @@ import eva2.tools.SelectedTag; * @author mkron * */ -public class DiversityTerminator implements InterfaceTerminator, Serializable { - private double distanceLimit = 0.001; +public class DiversityTerminator extends PopulationMeasureTerminator implements InterfaceTerminator, Serializable { + public enum DiversityCriterion {averageDistance, minimumDistance, maximumDistance}; +// private double distanceLimit = 0.001; private InterfaceDistanceMetric metric = new PhenotypeMetric(); - private String msg = ""; // leave the string order for this SelectedTag! (analogy to Population.getPopulationMeasures) - private SelectedTag criterion = new SelectedTag("Average distance", "Minimum distance", "Maximum distance"); + private DiversityCriterion criterion = DiversityCriterion.averageDistance; - public DiversityTerminator() {} - - /** - * The default uses Phenotype metric and average distance as criterion. - * - * @param limit - */ - public DiversityTerminator(double limit) { - distanceLimit = limit; - metric = new PhenotypeMetric(); - criterion.setSelectedTag(0); + public DiversityTerminator() { + super(); } - /** - * Create a special DiversityTerminator defining distance limit, metric and distance - * criterion to use (average, minimum or maximum distance). - * - * @param limit the distance limit of individuals below which termination is triggered - * @param metric the metric to be used to calculate individual distances - * @param criterionID 0 for average distance, 1 for minimum distance and 2 for maximum distance - */ - public DiversityTerminator(double limit, InterfaceDistanceMetric metric, int criterionID) { - distanceLimit = limit; + public DiversityTerminator(DiversityCriterion divCrit, InterfaceDistanceMetric metric, double convergenceThreshold, int stagnationTime, StagnationTypeEnum stagType, ChangeTypeEnum changeType, DirectionTypeEnum dirType) { + super(convergenceThreshold, stagnationTime, stagType, changeType, dirType); this.metric = metric; - criterion.setSelectedTag(criterionID); + this.criterion = divCrit; } - public void init(InterfaceOptimizationProblem prob) { - msg = "Not terminated."; - } - public static String globalInfo() { return "The diversity terminator uses the distance of individuals in the population as a termination criterion."; } - - /** - * Returns true if the average phenotypic distance within the given - * population is below the limit set in the terminator instance. - * - * @return true if the population is seen as converged due to low average phenotypic distance, else false - */ - public boolean isTerminated(PopulationInterface pop) { - double[] measures = ((Population)pop).getPopulationMeasures(metric); - int measureIndex = criterion.getSelectedTagID(); - if (measures[measureIndex] < distanceLimit) { - msg = "Average individual distance below " + distanceLimit; - return true; - } else return false; - } - - public boolean isTerminated(InterfaceSolutionSet sols) { - return isTerminated(sols.getCurrentPopulation()); - } - - public String lastTerminationMessage() { - return msg; - } - - /** - * @return the avgDistanceLimit - */ - public double getDistanceLimit() { - return distanceLimit; - } - - /** - * @param avgDistanceLimit the avgDistanceLimit to set - */ - public void setDistanceLimit(double avgDistanceLimit) { - this.distanceLimit = avgDistanceLimit; - } - - public String distanceLimitTipText() { - return "Set the distance limit of individuals below which termination is triggered."; - } /** * @return the metric @@ -111,10 +49,6 @@ public class DiversityTerminator implements InterfaceTerminator, Serializable { public InterfaceDistanceMetric getMetric() { return metric; } - - /** - * @param metric the metric to set - */ public void setMetric(InterfaceDistanceMetric metric) { this.metric = metric; } @@ -126,18 +60,30 @@ public class DiversityTerminator implements InterfaceTerminator, Serializable { /** * @return the criterion */ - public SelectedTag getCriterion() { + public DiversityCriterion getCriterion() { return criterion; } - - /** - * @param criterion the criterion to set - */ - public void setCriterion(SelectedTag criterion) { + public void setCriterion(DiversityCriterion criterion) { this.criterion = criterion; } - public String criterionTipText() { return "Define the distance criterion to check for in a population."; } + + @Override + protected double calcInitialMeasure(PopulationInterface pop) { + return calcPopulationMeasure(pop); + } + + @Override + protected double calcPopulationMeasure(PopulationInterface pop) { + double[] measures = ((Population)pop).getPopulationMeasures(metric); + int measureIndex = criterion.ordinal(); + return measures[measureIndex]; + } + + @Override + protected String getMeasureName() { + return "Population diversity ("+criterion+")"; + } } diff --git a/src/eva2/server/go/operators/terminators/FitnessConvergenceTerminator.java b/src/eva2/server/go/operators/terminators/FitnessConvergenceTerminator.java index 9845ee28..9237b100 100644 --- a/src/eva2/server/go/operators/terminators/FitnessConvergenceTerminator.java +++ b/src/eva2/server/go/operators/terminators/FitnessConvergenceTerminator.java @@ -20,8 +20,8 @@ implements InterfaceTerminator, Serializable { super(); } - public FitnessConvergenceTerminator(double thresh, int stagnPeriod, boolean bFitCallBased, boolean bAbsolute, boolean bImprovement) { - super(thresh, stagnPeriod, bFitCallBased, ChangeTypeEnum.absoluteChange, bImprovement); + public FitnessConvergenceTerminator(double thresh, int stagnPeriod, StagnationTypeEnum stagType, ChangeTypeEnum changeType, DirectionTypeEnum dirType) { + super(thresh, stagnPeriod, stagType, changeType, dirType); } public FitnessConvergenceTerminator(FitnessConvergenceTerminator other) { diff --git a/src/eva2/server/go/operators/terminators/ParetoMetricTerminator.java b/src/eva2/server/go/operators/terminators/ParetoMetricTerminator.java index 23487264..d07fb569 100644 --- a/src/eva2/server/go/operators/terminators/ParetoMetricTerminator.java +++ b/src/eva2/server/go/operators/terminators/ParetoMetricTerminator.java @@ -32,8 +32,8 @@ public class ParetoMetricTerminator extends PopulationMeasureTerminator implemen //public PopulationMeasureTerminator(double convergenceThreshold, int stagnationTime, boolean bFitCallBased, ChangeTypeEnum detectChangeType, boolean bImprovement) { - public ParetoMetricTerminator(InterfaceParetoFrontMetric metric, boolean useCurrentPop, double convergenceThreshold, int stagnationTime, boolean bFitCallBased, ChangeTypeEnum detectChangeType, boolean bImprovement) { - super(convergenceThreshold, stagnationTime, bFitCallBased, detectChangeType, bImprovement); + public ParetoMetricTerminator(InterfaceParetoFrontMetric metric, boolean useCurrentPop, double convergenceThreshold, int stagnationTime, StagnationTypeEnum stagType, ChangeTypeEnum changeType, DirectionTypeEnum dirType) { + super(convergenceThreshold, stagnationTime, stagType, changeType, dirType); this.pMetric = metric; this.useCurrentPop = useCurrentPop; } diff --git a/src/eva2/server/go/operators/terminators/PhenotypeConvergenceTerminator.java b/src/eva2/server/go/operators/terminators/PhenotypeConvergenceTerminator.java index f102aaba..dda9d335 100644 --- a/src/eva2/server/go/operators/terminators/PhenotypeConvergenceTerminator.java +++ b/src/eva2/server/go/operators/terminators/PhenotypeConvergenceTerminator.java @@ -16,8 +16,8 @@ public class PhenotypeConvergenceTerminator extends PopulationMeasureTerminator pMetric = new PhenotypeMetric(); } - public PhenotypeConvergenceTerminator(double thresh, int stagnTime, boolean bFitCallBased, ChangeTypeEnum changeType, boolean bImprovement) { - super(thresh, stagnTime, bFitCallBased, changeType, bImprovement); + public PhenotypeConvergenceTerminator(double thresh, int stagnTime, StagnationTypeEnum stagType, ChangeTypeEnum changeType, DirectionTypeEnum dirType) { + super(thresh, stagnTime, stagType, changeType, dirType); pMetric = new PhenotypeMetric(); } diff --git a/src/eva2/server/go/operators/terminators/PopulationMeasureTerminator.java b/src/eva2/server/go/operators/terminators/PopulationMeasureTerminator.java index d64d50f1..47e95d34 100644 --- a/src/eva2/server/go/operators/terminators/PopulationMeasureTerminator.java +++ b/src/eva2/server/go/operators/terminators/PopulationMeasureTerminator.java @@ -28,6 +28,8 @@ import eva2.tools.SelectedTag; public abstract class PopulationMeasureTerminator implements InterfaceTerminator, Serializable { public enum ChangeTypeEnum {relativeChange, absoluteChange, absoluteValue}; + public enum DirectionTypeEnum {decreaseImprovement, bidirectional}; + public enum StagnationTypeEnum {fitnessCallBased, generationBased}; protected static boolean TRACE = false; private double convThresh = 0.01; //, convThreshLower=0.02; @@ -36,21 +38,23 @@ Serializable { private int oldPopFitCalls = 1000; private int oldPopGens = 1000; private boolean firstTime = true; - private SelectedTag stagnationMeasure = new SelectedTag("Fitness calls", "Generations"); + private StagnationTypeEnum stagnationMeasure = StagnationTypeEnum.fitnessCallBased; // private SelectedTag convCondition = new SelectedTag("Relative change", "Absolute change", "Absolute value"); private ChangeTypeEnum changeType = ChangeTypeEnum.relativeChange; - private SelectedTag condImprovementOrChange = new SelectedTag("Improvement", "Improvement and Deterioration"); + private DirectionTypeEnum condDirection = DirectionTypeEnum.decreaseImprovement; +// private SelectedTag condImprovementOrChange = new SelectedTag("Decrease", "Improvement and Deterioration"); protected String msg="Not terminated."; public PopulationMeasureTerminator() {} - public PopulationMeasureTerminator(double convergenceThreshold, int stagnationTime, boolean bFitCallBased, ChangeTypeEnum detectChangeType, boolean bImprovement) { - convThresh = convergenceThreshold; - stagTime = stagnationTime; - stagnationMeasure.setSelectedTag(bFitCallBased ? 0 : 1); -// convergenceCondition.setSelectedTag(bAbsolute ? 1 : 0); - changeType = detectChangeType; - condImprovementOrChange.setSelectedTag(bImprovement ? 0 : 1); + public PopulationMeasureTerminator(double convergenceThreshold, int stagnationTime, StagnationTypeEnum stagType, ChangeTypeEnum changeType, DirectionTypeEnum dirType) { + this.convThresh = convergenceThreshold; + this.stagTime = stagnationTime; + this.stagnationMeasure = stagType; +// this.convergenceCondition.setSelectedTag(bAbsolute ? 1 : 0); + this.changeType = changeType; + this.condDirection = dirType; +// this.condImprovementOrChange.setSelectedTag(bImprovement ? 0 : 1); } public PopulationMeasureTerminator(PopulationMeasureTerminator o) { @@ -62,10 +66,11 @@ Serializable { // oldFit = o.oldFit.clone(); // oldNorm = o.oldNorm; msg = o.msg; - this.stagnationMeasure.setSelectedTag(o.stagnationMeasure.getSelectedTagID()); + this.stagnationMeasure = o.stagnationMeasure; // this.convergenceCondition.setSelectedTag(o.convergenceCondition.getSelectedTagID()); this.changeType = o.changeType; - this.condImprovementOrChange.setSelectedTag(o.condImprovementOrChange.getSelectedTagID()); + this.condDirection = o.condDirection; +// this.condImprovementOrChange.setSelectedTag(o.condImprovementOrChange.getSelectedTagID()); } // public void hideHideable() { @@ -163,7 +168,7 @@ Serializable { } sb.append(" for "); sb.append(stagTime); - if (stagnationMeasure.isSelectedString("Generations")) sb.append(" generations."); + if (stagnationMeasure == StagnationTypeEnum.generationBased) sb.append(" generations."); else sb.append(" function calls."); return sb.toString(); } @@ -238,7 +243,8 @@ Serializable { } public boolean doCheckImprovement() { - return condImprovementOrChange.isSelectedString("Improvement"); + return (condDirection==DirectionTypeEnum.decreaseImprovement); +// return condImprovementOrChange.isSelectedString("Improvement"); } public boolean isRelativeConvergence() { @@ -253,7 +259,7 @@ Serializable { * @return */ private boolean stagnationTimeHasPassed(PopulationInterface pop) { - if (stagnationMeasure.isSelectedString("Fitness calls")) { // by fitness calls + if (stagnationMeasure==StagnationTypeEnum.fitnessCallBased) { // by fitness calls // System.out.println("stagnationTimeHasPassed returns " + ((pop.getFunctionCalls() - popFitCalls) >= m_stagTime) + " after " + (pop.getFunctionCalls() - popFitCalls)); return (pop.getFunctionCalls() - oldPopFitCalls) >= stagTime; } else {// by generation @@ -269,7 +275,7 @@ Serializable { return convThresh; } public String convergenceThresholdTipText() { - return "Ratio of improvement or absolute value of improvement or change to determine convergence."; + return "Ratio of improvement/change or absolute value of improvement/change to determine convergence."; } // public void setConvergenceThresholdLower(double x) { @@ -292,14 +298,14 @@ Serializable { return "Terminate if the population has not improved for this time"; } - public SelectedTag getStagnationMeasure() { + public StagnationTypeEnum getStagnationMeasure() { return stagnationMeasure; } - public void setStagnationMeasure(SelectedTag stagnationTimeIn) { + public void setStagnationMeasure(StagnationTypeEnum stagnationTimeIn) { this.stagnationMeasure = stagnationTimeIn; } public String stagnationMeasureTipText() { - return "Stagnation time is measured in fitness calls or generations, to be selected here."; + return "Stagnation time is measured in fitness calls or generations."; } public ChangeTypeEnum getConvergenceCondition() { @@ -313,14 +319,15 @@ Serializable { return "Select between absolute and relative convergence condition"; } - public SelectedTag getCheckType() { - return condImprovementOrChange; + public DirectionTypeEnum getCheckType() { + return condDirection; +// return condImprovementOrChange; } - public void setCheckType(SelectedTag ct) { - this.condImprovementOrChange = ct; + public void setCheckType(DirectionTypeEnum dt) { + this.condDirection = dt; // GenericObjectEditor.setHideProperty(this.getClass(), "convergenceThresholdUpper", isRelativeConvergence() || doCheckImprovement()); } public String checkTypeTipText() { - return "Detect improvement only (one-directional change) or improvement and deterioration (two-directional change)."; + return "Detect improvement only (decreasing measure) or change in both directions (de- and increase)."; } } \ No newline at end of file diff --git a/src/eva2/server/go/problems/AbstractOptimizationProblem.java b/src/eva2/server/go/problems/AbstractOptimizationProblem.java index d79dee73..145ed22b 100644 --- a/src/eva2/server/go/problems/AbstractOptimizationProblem.java +++ b/src/eva2/server/go/problems/AbstractOptimizationProblem.java @@ -31,6 +31,8 @@ import eva2.server.go.operators.terminators.CombinedTerminator; import eva2.server.go.operators.terminators.EvaluationTerminator; import eva2.server.go.operators.terminators.PhenotypeConvergenceTerminator; import eva2.server.go.operators.terminators.PopulationMeasureTerminator.ChangeTypeEnum; +import eva2.server.go.operators.terminators.PopulationMeasureTerminator.DirectionTypeEnum; +import eva2.server.go.operators.terminators.PopulationMeasureTerminator.StagnationTypeEnum; import eva2.server.go.populations.Population; import eva2.server.go.strategies.InterfaceOptimizer; @@ -484,7 +486,7 @@ implements InterfaceOptimizationProblem /*, InterfaceParamControllable*/, Serial Population pop = new Population(1); pop.add(orig); InterfaceTerminator term = new EvaluationTerminator(maxEvaluations); - if (epsilonFitConv > 0) term = new CombinedTerminator(new PhenotypeConvergenceTerminator(epsilonFitConv, 100*dim, true, ChangeTypeEnum.absoluteChange, true), term, false); + if (epsilonFitConv > 0) term = new CombinedTerminator(new PhenotypeConvergenceTerminator(epsilonFitConv, 100*dim, StagnationTypeEnum.fitnessCallBased, ChangeTypeEnum.absoluteChange, DirectionTypeEnum.decreaseImprovement), term, false); int evalsPerf = PostProcess.processSingleCandidatesNMCMA(PostProcessMethod.nelderMead, pop, term, initRelPerturb, prob); overallDist = metric.distance(indy, pop.getBestEAIndividual()); //System.out.println(System.currentTimeMillis() + " in " + evalsPerf + " evals moved by "+ overallDist); diff --git a/src/eva2/server/go/problems/AbstractProblemDouble.java b/src/eva2/server/go/problems/AbstractProblemDouble.java index 08e63365..56f59f8e 100644 --- a/src/eva2/server/go/problems/AbstractProblemDouble.java +++ b/src/eva2/server/go/problems/AbstractProblemDouble.java @@ -11,6 +11,9 @@ import eva2.server.go.operators.constraint.AbstractConstraint; import eva2.server.go.operators.constraint.GenericConstraint; import eva2.server.go.operators.postprocess.PostProcess; import eva2.server.go.operators.terminators.FitnessConvergenceTerminator; +import eva2.server.go.operators.terminators.PopulationMeasureTerminator.ChangeTypeEnum; +import eva2.server.go.operators.terminators.PopulationMeasureTerminator.DirectionTypeEnum; +import eva2.server.go.operators.terminators.PopulationMeasureTerminator.StagnationTypeEnum; import eva2.server.go.populations.Population; import eva2.server.go.strategies.InterfaceOptimizer; import eva2.tools.Pair; @@ -396,7 +399,7 @@ public abstract class AbstractProblemDouble extends AbstractOptimizationProblem tmpIndy.SetDoubleGenotype(pos); ((AbstractEAIndividual)tmpIndy).SetFitness(prob.eval(pos)); pop.add(tmpIndy); - FitnessConvergenceTerminator convTerm = new FitnessConvergenceTerminator(1e-25, 10, false, true, true); + FitnessConvergenceTerminator convTerm = new FitnessConvergenceTerminator(1e-25, 10, StagnationTypeEnum.generationBased, ChangeTypeEnum.absoluteChange, DirectionTypeEnum.decreaseImprovement); int calls = PostProcess.processSingleCandidatesNMCMA(PostProcessMethod.nelderMead, pop, convTerm, 0.001, prob); return ((InterfaceDataTypeDouble)pop.getBestEAIndividual()).getDoubleData(); } diff --git a/src/eva2/server/go/strategies/EvolutionStrategyIPOP.java b/src/eva2/server/go/strategies/EvolutionStrategyIPOP.java index a310b552..122924fd 100644 --- a/src/eva2/server/go/strategies/EvolutionStrategyIPOP.java +++ b/src/eva2/server/go/strategies/EvolutionStrategyIPOP.java @@ -8,6 +8,9 @@ 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.operators.terminators.PopulationMeasureTerminator.ChangeTypeEnum; +import eva2.server.go.operators.terminators.PopulationMeasureTerminator.DirectionTypeEnum; +import eva2.server.go.operators.terminators.PopulationMeasureTerminator.StagnationTypeEnum; import eva2.server.go.populations.Population; import eva2.server.go.populations.SolutionSet; @@ -156,7 +159,7 @@ public class EvolutionStrategyIPOP extends EvolutionStrategies implements Interf bestList = new LinkedList(); best = getPopulation().getBestEAIndividual(); dim = AbstractEAIndividual.getDoublePositionShallow(getPopulation().getEAIndividual(0)).length; - fitConvTerm = new FitnessConvergenceTerminator(stagThreshold, (isStagnationTimeUserDef()) ? stagTimeArbitrary : calcDefaultStagnationTime(), false, true, true); // gen. based, absolute + fitConvTerm = new FitnessConvergenceTerminator(stagThreshold, (isStagnationTimeUserDef()) ? stagTimeArbitrary : calcDefaultStagnationTime(), StagnationTypeEnum.generationBased, ChangeTypeEnum.absoluteChange, DirectionTypeEnum.decreaseImprovement); // gen. based, absolute getPopulation().addPopulationChangedEventListener(this); getPopulation().setNotifyEvalInterval(initialLambda); }