diff --git a/src/eva2/gui/BeanInspector.java b/src/eva2/gui/BeanInspector.java index 5b89bdc7..bb6321d4 100644 --- a/src/eva2/gui/BeanInspector.java +++ b/src/eva2/gui/BeanInspector.java @@ -164,7 +164,7 @@ public class BeanInspector { } if (Target instanceof List && !(Target instanceof Population)) { // handle the list case - StringBuffer sbuf = new StringBuffer("[ "); + StringBuffer sbuf = new StringBuffer("[ "); List lst = (List)Target; for (Object o : lst) { sbuf.append(o.toString()); diff --git a/src/eva2/gui/Plot.java b/src/eva2/gui/Plot.java index 835e4744..3983b940 100644 --- a/src/eva2/gui/Plot.java +++ b/src/eva2/gui/Plot.java @@ -39,14 +39,14 @@ import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; - import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; import eva2.EvAInfo; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.populations.Population; import eva2.tools.chart2d.DPointSet; import eva2.tools.tool.BasicResourceLoader; -import eva2.server.go.populations.Population; /*==========================================================================* * CLASS DECLARATION *==========================================================================*/ @@ -287,10 +287,22 @@ public class Plot implements PlotInterface, Serializable { */ public void drawPopulation(String prefix, Population pop) { for (int i=0; i iDist = Population.getClosestFarthestIndy(loners.getEAIndividual(l), species[spI], m_Metric, true); + if (iDist.tail() < m_ClusterDistance) { // its close enough to be added + // set SP ID only if its the closest species which is still below cluster distance + if (minDist<0 || (iDist.tail() < minDist)) res[l]=spI; + } + } // end for all species + } // end for all loners + return res; } - + /********************************************************************************************************************** * These are for GUI */ @@ -236,6 +258,10 @@ public class ClusteringDensityBased implements InterfaceClustering, java.io.Seri return "Set the minimum group size for the DBSCAN method."; } + public String initClustering(Population pop) { + return null; + } + // /** For debuggy only // * @param plot TopoPlot diff --git a/src/eva2/server/go/operators/cluster/ClusteringKMeans.java b/src/eva2/server/go/operators/cluster/ClusteringKMeans.java index 2c5a2dce..71238a8b 100644 --- a/src/eva2/server/go/operators/cluster/ClusteringKMeans.java +++ b/src/eva2/server/go/operators/cluster/ClusteringKMeans.java @@ -1,5 +1,7 @@ package eva2.server.go.operators.cluster; +import java.util.Arrays; + import eva2.gui.Chart2DDPointIconCircle; import eva2.gui.Chart2DDPointIconText; import eva2.gui.GraphPointSet; @@ -59,7 +61,7 @@ public class ClusteringKMeans implements InterfaceClustering, java.io.Serializab * @param pop The population of individuals that is to be clustered. * @return Population[] */ - public Population[] cluster(Population pop) { + public Population[] cluster(Population pop, Population referencePop) { double[][] data = this.extractClusterDataFrom(pop); if (!(this.m_ReuseC) || (this.m_C == null)) { this.m_C = new double[this.m_K][]; @@ -278,20 +280,27 @@ public class ClusteringKMeans implements InterfaceClustering, java.io.Serializab * @param species2 The second species. * @return True if species converge, else False. */ - public boolean mergingSpecies(Population species1, Population species2) { + public boolean mergingSpecies(Population species1, Population species2, Population referencePop) { // @todo i could use the BIC metric from X-means to calculate this return false; } - /** This method decides if a unclustered individual belongs to an already established species. - * @param indy A unclustered individual. - * @param species A species. - * @return True or False. - */ - public boolean belongsToSpecies(AbstractEAIndividual indy, Population species) { - // @todo perhaps the same as in convergingSpecies - return false; - } +// /** This method decides if a unclustered individual belongs to an already established species. +// * @param indy A unclustered individual. +// * @param species A species. +// * @return True or False. +// */ +// public boolean belongsToSpecies(AbstractEAIndividual indy, Population species, Population pop) { +// // @todo perhaps the same as in convergingSpecies +// return false; +// } + + public int[] associateLoners(Population loners, Population[] species, Population referencePop) { + int[] res=new int[loners.size()]; + System.err.println("Warning, associateLoners not implemented for " + this.getClass()); + Arrays.fill(res, -1); + return res; + } /** This method allows you to recieve the c centroids * @return The centroids @@ -313,7 +322,7 @@ public class ClusteringKMeans implements InterfaceClustering, java.io.Serializab f1.setProblemDimension(2); f1.setEAIndividual(new ESIndividualDoubleData()); f1.initPopulation(pop); - ckm.cluster(pop); + ckm.cluster(pop, (Population)null); } @@ -374,4 +383,8 @@ public class ClusteringKMeans implements InterfaceClustering, java.io.Serializab public String reuseCTipText() { return "Toggel reuse of previously found cluster centroids."; } + + public String initClustering(Population pop) { + return null; + } } \ No newline at end of file diff --git a/src/eva2/server/go/operators/cluster/ClusteringNearestBetter.java b/src/eva2/server/go/operators/cluster/ClusteringNearestBetter.java new file mode 100644 index 00000000..d3dece78 --- /dev/null +++ b/src/eva2/server/go/operators/cluster/ClusteringNearestBetter.java @@ -0,0 +1,401 @@ +package eva2.server.go.operators.cluster; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Vector; + +import eva2.gui.BeanInspector; +import eva2.gui.GenericObjectEditor; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.individuals.AbstractEAIndividualComparator; +import eva2.server.go.operators.distancemetric.InterfaceDistanceMetric; +import eva2.server.go.operators.distancemetric.PhenotypeMetric; +import eva2.server.go.populations.Population; +import eva2.tools.Pair; + +/** + * Hierarchical clustering after Preuss et al., "Counteracting Genetic Drift and Disruptive Recombination + * in (mu+,lambda)-EA on Multimodal Fitness Landscapes", GECCO '05. + * + * A tree is produced by assigning each individual the closest individual with better fitness. + * Connections with a distance above a certain threshold are cut. After that, each interconnected subtree forms a cluster. + * In the paper, the threshold is deduced as 2*d_p for d_p: the mean distance in the population. + * + * @author mkron + * + */ +public class ClusteringNearestBetter implements InterfaceClustering, Serializable { + private static final long serialVersionUID = 1L; + private InterfaceDistanceMetric metric = new PhenotypeMetric(); + private double absoluteDistThreshold = 0.5; + private boolean thresholdMultipleOfMeanDist = true; + private double meanDistFactor = 2.; // recommended setting + private double currentMeanDistance = -1.; + private int minimumGroupSize = 3; + private boolean testConvergingSpeciesOnBestOnly = true; // if two species are tested for convergence, only the best indies may be compared regarding the distance threshold + + private int[] uplink; + private double[] uplinkDist; + private AbstractEAIndividualComparator comparator = new AbstractEAIndividualComparator(); + private Vector[] children; + private static final String initializedForKey = "initializedClustNearestBetterOnHash"; + private static final String initializedRefData = "initializedClustNearestBetterData"; + + private static boolean TRACE = true; + + public ClusteringNearestBetter() { + } + + public ClusteringNearestBetter(ClusteringNearestBetter o) { + this.metric = o.metric; + this.absoluteDistThreshold = o.absoluteDistThreshold; + this.thresholdMultipleOfMeanDist = o.thresholdMultipleOfMeanDist; + this.meanDistFactor = o.meanDistFactor; + this.currentMeanDistance = o.currentMeanDistance; + this.minimumGroupSize = o.minimumGroupSize; + this.comparator = (AbstractEAIndividualComparator)o.comparator.clone(); + this.testConvergingSpeciesOnBestOnly = o.testConvergingSpeciesOnBestOnly; + } + + public void hideHideable() { + setAdaptiveThreshold(isAdaptiveThreshold()); + } + + /** This method allows you to make a deep clone of + * the object + * @return the deep clone + */ + public Object clone() { + return (Object) new ClusteringNearestBetter(this); + } + + /** + * Try to associate a set of loners with a given set of species. Return a list + * of indices assigning loner i with species j for all loners. If no species can + * be associated, -1 is returned as individual entry. + * Note that the last cluster threshold is used which may have depended on the last + * generation. + * + * @param loners + * @param species + * @return associative list matching loners to species. + */ + public int[] associateLoners(Population loners, Population[] species, Population referenceSet) { +// Pair[][] closestPerSpecList = new Pair[loners.size()][species.length]; + int[] res = new int[loners.size()]; + getRefData(referenceSet, loners); + for (int l=0; l sorted = pop.getSorted(comparator); +//// for (int i=sorted.size()-1; i>=1; i--) { // start with worst indies +//// if (sorted.get(i).getIndyID()==indy.getIndyID()) { // found the desired indy. +//// int uplink=-1; double uplinkDist = -1; +//// for (int j=i-1; j>=0; j--) { // search nearest better indy +//// double curDist = metric.distance(sorted.get(i), sorted.get(j)); +//// if (uplinkDist<0 || (curDist < uplinkDist)) { +//// uplink = j; +//// uplinkDist = curDist; +//// } +//// } +//// // if it belongs to species spec and the distance is below threshold, be happy and return true +//// if (uplink==-1) { // it is the best individual? +//// return false; +//// } +//// if (uplinkDist > currentDistThreshold()) return false; +//// else { +//// return (species.isMemberByID(pop.getEAIndividual(uplink))); +//// } +//// } +//// } +//// // size <= 1? +//// return false; +// } + + /** + * Perform one clustering step to measure the mean distance to the + * nearest better individual (only if used). + */ + public String initClustering(Population pop) { + if (this.isAdaptiveThreshold()) { + ArrayList sorted = pop.getSorted(comparator); + if (uplink==null || (uplink.length!=pop.size())) uplink = new int[pop.size()]; // parent index of all indys + if (uplinkDist==null || (uplinkDist.length!=pop.size())) uplinkDist = new double[pop.size()]; // parent distance for all indys + if (children==null || (children.length!=pop.size())) children = new Vector[pop.size()]; // list of children for all indies + else if (children.length==pop.size()) for (int i=0; i sorted = pop.getSorted(comparator); + if (uplink==null || (uplink.length!=pop.size())) uplink = new int[pop.size()]; // parent index of all indys + if (uplinkDist==null || (uplinkDist.length!=pop.size())) uplinkDist = new double[pop.size()]; // parent distance for all indys + if (children==null || (children.length!=pop.size())) children = new Vector[pop.size()]; // list of children for all indies + else if (children.length==pop.size()) for (int i=0; i allClusters = new LinkedList(); + while (current finalClusts = new ArrayList(allClusters.size()); + finalClusts.add(pop.cloneWithoutInds()); + for (Population clust : allClusters) { + if (clust.size() sorted) { + double edgeLengthSum=0; int edgeCnt = 0; + for (int i=sorted.size()-1; i>=1; i--) { // start with worst indies + // search for closest indy which is better + uplink[i]=-1; + uplinkDist[i] = -1; + for (int j=i-1; j>=0; j--) { // look at all which are better + // if the j-th indy is closer, reset the index + double curDist = metric.distance(sorted.get(i), sorted.get(j)); + if (uplinkDist[i]<0 || (curDist < uplinkDist[i])) { + uplink[i] = j; + uplinkDist[i] = curDist; + } + } + // the closest best for indy i is now known. connect them in the graph. + if (children[uplink[i]]==null) children[uplink[i]]=new Vector(); + children[uplink[i]].add(i); + edgeLengthSum+=uplinkDist[i]; + edgeCnt++; + } +// currentMeanDistance = pop.getPopulationMeasures(metric)[0]; + return edgeLengthSum/((double)edgeCnt); // the average edge length + } + + /** + * Add the next layer of children to the clustered population. + * + * @param current + * @param clustered + * @param sorted + * @param currentClust + */ + private void addChildren(int current, boolean[] clustered, ArrayList sorted, Population currentClust) { + if (children[current]!=null && (children[current].size()>0)) { + for (int i=0; i sortedArr = null; private int lastFitCrit = -1; + private transient static boolean TRACE = false; // remember when the last evaluation was performed // private Pair evaluationTimeHashes = null; @@ -76,6 +77,7 @@ public class Population extends ArrayList implements PopulationInterface, Clonea // private int evaluationTimeModCount = -1; public Population() { + if (TRACE) System.err.println("TRACING POP"); } /** @@ -86,10 +88,17 @@ public class Population extends ArrayList implements PopulationInterface, Clonea */ public Population(int initialCapacity) { super(initialCapacity); + if (TRACE) System.err.println("TRACING POP"); setTargetSize(initialCapacity); } + /** + * Clones parameters, individuals, history and archive. + * + * @param population + */ public Population(Population population) { + if (TRACE) System.err.println("TRACING POP"); setSameParams(population); for (int i = 0; i < population.size(); i++) { if (population.get(i) != null) @@ -97,10 +106,49 @@ public class Population extends ArrayList implements PopulationInterface, Clonea } copyHistAndArchive(population); } - - public void copyHistAndArchive(Population population) { + + public static Population makePopFromList(List indies) { + Population pop = new Population(indies.size()); + if (TRACE) System.err.println("TRACING POP"); + pop.setTargetSize(indies.size()); + for (AbstractEAIndividual indy : indies) { + pop.add(indy); + } + return pop; + } + + /** + * Create a new population from a solution set by merging + * both current population and solutions from the set. + * + * @param allSolutions + */ + public Population(InterfaceSolutionSet allSolutions) { + this(allSolutions.getCurrentPopulation().size()+allSolutions.getSolutions().size()); + if (TRACE) System.err.println("TRACING POP"); + addPopulation(allSolutions.getCurrentPopulation()); + HashMap checkCols = new HashMap(size()); + for (int i=0; i)population.m_History.clone(); + if (population.additionalPopData!=null) { + this.additionalPopData = (HashMap)additionalPopData.clone(); + if (population.additionalPopData.size()>0) { + for (String key : population.additionalPopData.keySet()) { + additionalPopData.put(key, population.additionalPopData.get(key)); + } + } + } } /** @@ -173,7 +221,7 @@ public class Population extends ArrayList implements PopulationInterface, Clonea * have been inited by a problem */ public void init() { - this.m_History = new ArrayList(); + this.m_History = new ArrayList(); this.m_Generation = 0; this.m_FunctionCalls = 0; // evaluationTimeHashes = null; @@ -302,8 +350,8 @@ public class Population extends ArrayList implements PopulationInterface, Clonea */ protected void firePropertyChangedEvent(String name) { if (listeners != null) { - for (Iterator iterator = listeners.iterator(); iterator.hasNext();) { - InterfacePopulationChangedEventListener listener = (InterfacePopulationChangedEventListener) iterator.next(); + for (Iterator iterator = listeners.iterator(); iterator.hasNext();) { + InterfacePopulationChangedEventListener listener = iterator.next(); if (listener!=null) listener.registerPopulationStateChanged(this, name); } } @@ -390,17 +438,86 @@ public class Population extends ArrayList implements PopulationInterface, Clonea * Note: After this operation the target population size may be exceeded. * @param pop The population that is to be added. */ - public void addPopulation(Population pop) { - if (pop == null) return; - for (int i = 0; i < pop.size(); i++) { - AbstractEAIndividual indy = (AbstractEAIndividual)pop.get(i); - if (indy != null) { - this.add(indy); + public Population addPopulation(Population pop) { + if (pop != null) { + for (int i = 0; i < pop.size(); i++) { + AbstractEAIndividual indy = (AbstractEAIndividual)pop.get(i); + if (indy != null) { + this.add(indy); + } } } + return this; + } + + /** + * Fill the population up to the given size with random elements + * from the given population. + * + * @param upTo target size of the population + * @param fromPop The population that is to be added. + * + */ + public boolean fillWithRandom(int upTo, Population fromPop) { + if (upTo <= this.size()) return true; + else if (fromPop==null || (fromPop.size()<1)) return false; + else { + int[] perm = RNG.randomPerm(fromPop.size()); + int i=0; + while ((i> findSamePositions() { + ArrayList> dupes = new ArrayList>(); + for (int i=0; i= 0) dupes.add(new Pair(i, nextIndex)); + } + return dupes; + } + + /** + * Return true if an individual with equal position is contained within the population. + * + * @param indy + * @return + */ + public boolean containsByPosition(AbstractEAIndividual indy) { + return indexByPosition(0,indy)>=0; + } + + /** + * Return the index of the first individual which has an equal position or -1. + * + * @param startIndex the first index to start the search + * @param indy + * @return the index of the first individual which has an equal position or -1 + */ + public int indexByPosition(int startIndex, AbstractEAIndividual indy) { + for (int i=startIndex; i getSorted(AbstractEAIndividualComparator comp) { + if (super.size()==0) return new ArrayList(); PriorityQueue sQueue = new PriorityQueue(super.size(), comp); for (int i = 0; i < super.size(); i++) { AbstractEAIndividual indy = getEAIndividual(i); @@ -1132,7 +1250,8 @@ public class Population extends ArrayList implements PopulationInterface, Clonea } /** - * ArrayList does not increase the modCount in set. Why??? + * ArrayList does not increase the modCount in set. Maybe because it is not + * seen as "structural change"? */ public Object set(int index, Object element) { Object prev = super.set(index, element); @@ -1250,10 +1369,32 @@ public class Population extends ArrayList implements PopulationInterface, Clonea * @return the average, minimal and maximal mean distance of individuals in an array of three */ public double[] getPopulationMeasures(InterfaceDistanceMetric metric) { - double d; +// Integer lastMeasuresModCount = (Integer)getData(lastPopMeasuresFlagKey); +// if (lastMeasuresModCount!=null && (lastMeasuresModCount==modCount)) { +// double[] measures = (double[])getData(lastPopMeasuresDatKey); +// if (TRACE ) { +// double[] verify = calcPopulationMeasures(metric); +// if (Mathematics.dist(measures, verify, 2)>1e-10) { +// System.out.println(getStringRepresentation()); +// System.err.println("Warning, invalid measures!!!"); +// +// } +// } +// return measures; +// } + double[] res = calcPopulationMeasures(metric); +// putData(lastPopMeasuresFlagKey, new Integer(modCount)); +// putData(lastPopMeasuresDatKey, res); +// System.out.println(getStringRepresentation()); +// System.out.println("0-1-dist: " + BeanInspector.toString(metric.distance((AbstractEAIndividual)this.get(0), (AbstractEAIndividual)this.get(1)))); + return res; + } + + private double[] calcPopulationMeasures(InterfaceDistanceMetric metric) { + double d; double[] res = new double[3]; - double distSum = 0.; + double meanDist = 0.; double maxDist = Double.MIN_VALUE; double minDist = Double.MAX_VALUE; @@ -1262,21 +1403,20 @@ public class Population extends ArrayList implements PopulationInterface, Clonea if (metric == null) d = EuclideanMetric.euclideanDistance(AbstractEAIndividual.getDoublePositionShallow(getEAIndividual(i)), AbstractEAIndividual.getDoublePositionShallow(getEAIndividual(j))); else d = metric.distance((AbstractEAIndividual)this.get(i), (AbstractEAIndividual)this.get(j)); - distSum += d; + meanDist += d; if (d < minDist) minDist = d; if (d > maxDist) maxDist = d; } } res[1] = minDist; res[2] = maxDist; - if (this.size() > 1) res[0] = distSum / (this.size() * (this.size()-1) / 2); + if (this.size() > 1) res[0] = meanDist / (this.size() * (this.size()-1) / 2); else { // only one indy? res[1]=0; res[2]=0; } -// System.out.println("0-1-dist: " + BeanInspector.toString(metric.distance((AbstractEAIndividual)this.get(0), (AbstractEAIndividual)this.get(1)))); - return res; - } + return res; + } /** * Returns the average, minimal and maximal individual fitness and std dev. for the population in the given criterion. @@ -1342,7 +1482,30 @@ public class Population extends ArrayList implements PopulationInterface, Clonea } return new Pair(sel,dist); } - + + /** + * Search for the closest (farthest) individual to the given individual. + * Return a Pair of the individuals index and distance. + * If the population is empty, a Pair of (-1,-1) is returned. + * + * @param pos + * @param pop + * @param closestOrFarthest if true, the closest individual is retrieved, otherwise the farthest + * @return + */ + public static Pair getClosestFarthestIndy(AbstractEAIndividual refIndy, Population pop, InterfaceDistanceMetric metric, boolean closestOrFarthest) { + double dist = -1.; + int sel=-1; + for (int i = 0; i < pop.size(); i++) { + double curDist = metric.distance(refIndy, pop.getEAIndividual(i)); + if ((dist<0) || (!closestOrFarthest && (dist < curDist)) + || (closestOrFarthest && (dist > curDist))) { + dist = curDist; + sel = i; + } + } + return new Pair(sel,dist); + } /** * Calculate the average position of the population. * @@ -1574,6 +1737,36 @@ public class Population extends ArrayList implements PopulationInterface, Clonea // if (evaluationTimeHashes == null) return false; // else return ((hashes.head().equals(evaluationTimeHashes.head())) && (hashes.tail().equals(evaluationTimeHashes.tail())) && (evaluationTimeModCount == modCount)); // } + /** + * Add the population data of a given population to this instance. + * Note that collisions are not checked! + */ + public void addDataFromPopulation(Population pop) { + if (pop.additionalPopData!=null) { + Set keys = pop.additionalPopData.keySet(); + for (String key : keys) { + Object earlierDat = this.getData(key); + if (earlierDat!=null && !(earlierDat.equals(pop.getData(key)))) System.err.println("Warning: Population already contained data keyed by " + key + ", overwriting data " + earlierDat + " with " + pop.getData(key)); + this.putData(key, pop.getData(key)); + } + } + } + + /** + * Returns true if the given individual is member of this population, + * where the comparison is done by individual ID. + * + * @param indy + * @return + */ + public boolean isMemberByID(AbstractEAIndividual indy) { + for (int i=0; i m_Species = new ArrayList(); - public Population m_Undifferentiated = new Population(); + private ArrayList m_Species = new ArrayList(); + private Population m_Undifferentiated = new Population(); + private transient Population m_doomedPop = new Population(); + private InterfaceOptimizationProblem m_Problem = new B1Problem(); private InterfaceOptimizer m_Optimizer = new GeneticAlgorithm(); private InterfaceClustering m_CAForSpeciesDifferentation = new ClusteringDensityBased(); - private InterfaceClustering m_CAForSpeciesConvergence = new ClusteringDensityBased(); - //private Distraction distraction = null; -// private boolean useDistraction = false; -// private double distrDefaultStrength = 1.; + private InterfaceClustering m_CAForSpeciesMerging = new ClusteringDensityBased(); +// private Distraction distraction = null; + private boolean useDistraction = false; +// private double distrDefaultStrength = .7; + private double epsilonBound = 1e-10; transient private String m_Identifier = ""; transient private InterfacePopulationChangedEventListener m_Listener; private int m_SpeciesCycle = 1; // from which size on is a species considered active - private int m_actSpecSize = 2; +// private int m_actSpecSize = 2; private int m_minGroupSize = 3; // private boolean m_UseClearing = false; - private boolean m_UseArchive = true; - private boolean m_UseSpeciesDifferentation = true; - private boolean m_UseSpeciesMerging = true; -// private boolean m_UseHaltingWindow = true; +// private boolean m_UseArchive = true; + private boolean m_UseSpeciesDifferentiation = true; + private boolean m_mergeSpecies = true; private int m_PopulationSize = 50; private int convergedCnt = 0; - private static boolean TRACE = false; + private static boolean TRACE = false, TRACE_STATE=false; private int m_ShowCycle = 0; transient private TopoPlot m_Topology; private int haltingWindow = 15; private double muLambdaRatio = 0.5; + private int sleepTime = 0; + private int m_maxSpeciesSize = 15; + private AbstractEAIndividualComparator reduceSizeComparator = new AbstractEAIndividualComparator(); - - public ClusterBasedNichingEA() { - this.m_CAForSpeciesConvergence = new ClusteringDensityBased(); - ((ClusteringDensityBased)this.m_CAForSpeciesConvergence).setMinimumGroupSize(m_minGroupSize); -// if (useDistraction) distraction = new Distraction(); + public ClusterBasedNichingEA() { + this.m_CAForSpeciesMerging = new ClusteringDensityBased(); + ((ClusteringDensityBased)this.m_CAForSpeciesMerging).setMinimumGroupSize(m_minGroupSize); +// if (useDistraction) distraction = new Distraction(distrDefaultStrength, Distraction.METH_BEST); } public ClusterBasedNichingEA(ClusterBasedNichingEA a) { + this.epsilonBound = a.epsilonBound; this.m_Population = (Population)a.m_Population.clone(); + this.m_Archive = (Population)a.m_Archive.clone(); + this.m_doomedPop = (Population)a.m_doomedPop.clone(); this.m_Problem = (InterfaceOptimizationProblem)a.m_Problem.clone(); this.m_Optimizer = (InterfaceOptimizer)a.m_Optimizer.clone(); - this.m_Species = (ArrayList)(a.m_Species.clone()); + this.m_Species = (ArrayList)(a.m_Species.clone()); this.m_Undifferentiated = (Population)a.m_Undifferentiated.clone(); - this.m_CAForSpeciesConvergence = (InterfaceClustering)this.m_CAForSpeciesConvergence.clone(); + this.m_CAForSpeciesMerging = (InterfaceClustering)this.m_CAForSpeciesMerging.clone(); this.m_CAForSpeciesDifferentation = (InterfaceClustering)this.m_CAForSpeciesDifferentation.clone(); this.m_SpeciesCycle = a.m_SpeciesCycle; - this.m_actSpecSize = a.m_actSpecSize; this.m_minGroupSize = a.m_minGroupSize; -// this.m_UseClearing = a.m_UseClearing; - this.m_UseSpeciesDifferentation = a.m_UseSpeciesDifferentation; - this.m_UseSpeciesMerging = a.m_UseSpeciesMerging; -// this.m_UseHaltingWindow = a.m_UseHaltingWindow; + this.m_UseSpeciesDifferentiation = a.m_UseSpeciesDifferentiation; + this.m_mergeSpecies = a.m_mergeSpecies; this.m_PopulationSize = a.m_PopulationSize; this.haltingWindow = a.haltingWindow; + this.m_maxSpeciesSize = a.m_maxSpeciesSize; + this.muLambdaRatio = a.muLambdaRatio; + this.sleepTime = a.sleepTime; + this.convergedCnt = a.convergedCnt; } public Object clone() { @@ -108,44 +118,58 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis } public void init() { - this.m_Optimizer.addPopulationChangedEventListener(this); - this.m_Undifferentiated = new Population(); + this.m_Undifferentiated = new Population(m_PopulationSize); this.m_Undifferentiated.setUseHistory(true); - this.m_Undifferentiated.setTargetSize(this.m_PopulationSize); - this.m_Species = new ArrayList(); - this.m_Problem.initPopulation(this.m_Undifferentiated); - this.evaluatePopulation(this.m_Undifferentiated); - this.m_Optimizer.initByPopulation(m_Undifferentiated, false); - m_Archive = new Population(); - convergedCnt = 0; - this.m_Undifferentiated = m_Optimizer.getPopulation(); // required for changes to the population by the optimizer -// this.getPopulation().setUseHistory(true); // TODO this makes no sense if getPopulation clones the pop. - this.firePropertyChangedEvent("FirstGenerationPerformed"); - } + this.m_Problem.initPopulation(this.m_Undifferentiated); + this.m_Optimizer.setPopulation(m_Undifferentiated); + if (m_Optimizer instanceof EvolutionStrategies) { + EvolutionStrategies es = (EvolutionStrategies)m_Optimizer; + es.setLambda(getPopulationSize()); + es.setMu((int)(muLambdaRatio*(double)getPopulationSize())); + } + this.m_Optimizer.init(); + m_doomedPop = new Population(); + if (m_Undifferentiated.getFunctionCalls()!=m_PopulationSize) { + System.err.println("Whats that in CBN!?"); + } + initDefaults(false); + } + + public void hideHideable() { + GenericObjectEditor.setHideProperty(this.getClass(), "population", true); + setMaxSpeciesSize(getMaxSpeciesSize()); + setUseMerging(isUseMerging()); + } + + /** + * Do not reinitialize the main population! + * + * @param evalPop + */ + private void initDefaults(boolean evalPop) { + this.m_Optimizer.addPopulationChangedEventListener(this); + this.m_Undifferentiated.setTargetSize(this.m_PopulationSize); + this.m_Species = new ArrayList(); + this.m_Archive = new Population(); +// if (useDistraction) distraction = new Distraction(distrDefaultStrength, Distraction.METH_BEST); + convergedCnt = 0; + if (evalPop) this.evaluatePopulation(this.m_Undifferentiated); + this.m_Optimizer.initByPopulation(m_Undifferentiated, false); + this.m_Undifferentiated = m_Optimizer.getPopulation(); // required for changes to the population by the optimizer + this.firePropertyChangedEvent("FirstGenerationPerformed"); + } + /** 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_Optimizer.addPopulationChangedEventListener(this); - pop.setUseHistory(true); this.m_Undifferentiated = (Population)pop.clone(); if (reset) this.m_Undifferentiated.init(); - this.m_Undifferentiated.setTargetSize(this.m_PopulationSize); - this.m_Species = new ArrayList(); - m_Archive = new Population(); - convergedCnt = 0; - this.evaluatePopulation(this.m_Undifferentiated); - this.m_Optimizer.initByPopulation(m_Undifferentiated, false); - this.m_Undifferentiated = m_Optimizer.getPopulation(); // required for changes to the population by the optimizer - this.firePropertyChangedEvent("FirstGenerationPerformed"); - } - - public void hideHideable() { - GenericObjectEditor.setHideProperty(this.getClass(), "population", true); - setUseMerging(isUseMerging()); + initDefaults(reset); } + /** This method will evaluate the current population using the * given problem. * @param population The population that is to be evaluated @@ -156,6 +180,7 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis } private void plot(int gen) { + if (!(this.m_Problem instanceof TF1Problem) && !(this.m_Problem instanceof Interface2DBorderProblem)) return; double[] a = new double[2]; a[0] = 0.0; a[1] = 0.0; @@ -193,7 +218,7 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis } if (this.m_Problem instanceof Interface2DBorderProblem) { DPointSet popRep = new DPointSet(); - InterfaceDataTypeDouble tmpIndy1, best; + InterfaceDataTypeDouble tmpIndy1; Population pop; this.m_Topology = new TopoPlot("CBN-Species at gen. " + gen,"x","y",a,a); @@ -209,63 +234,76 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis //draw the species for (int i = 0; i < this.m_Species.size(); i++) { pop = (Population)this.m_Species.get(i); - best = (InterfaceDataTypeDouble)pop.getBestIndividual(); - if (isActive(pop)) { - for (int j = 0; j < pop.size(); j++) { - popRep = new DPointSet(); - tmpIndy1 = (InterfaceDataTypeDouble)pop.get(j); - popRep.addDPoint(new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1])); - this.m_Topology.getFunctionArea().addDElement(popRep); - - popRep = new DPointSet(); - popRep.setConnected(true); - popRep.addDPoint(new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1])); - popRep.addDPoint(new DPoint(best.getDoubleData()[0], best.getDoubleData()[1])); - this.m_Topology.getFunctionArea().addDElement(popRep); - } - } else { - // this is an inactive species - plotInactive((InterfaceDataTypeDouble)pop.get(0)); - } + plotPopConnected(m_Topology, pop); } - for (int i = 0; i < this.m_Archive.size(); i++) { - plotInactive((InterfaceDataTypeDouble)m_Archive.get(i)); + if (!useDistraction) { + for (int i = 0; i < this.m_Archive.size(); i++) { + plotIndy('x',(InterfaceDataTypeDouble)m_Archive.get(i)); + } + } else { +// for (int i = 0; i < this.distraction.getDistractorSetSize(); i++) { +// plotPosFit('#',distraction.getDistractorCenter(i), distraction.getDistractorStrength(i)); +// } } } + if (sleepTime > 0) { + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } } - private void plotInactive(InterfaceDataTypeDouble tmpIndy) { + private void plotPopConnected(TopoPlot tp, Population pop) { + DPointSet popRep; + InterfaceDataTypeDouble tmpIndy1; + if (pop.size()>1) { + for (int j = 0; j < pop.size(); j++) { + popRep = new DPointSet(); + tmpIndy1 = (InterfaceDataTypeDouble)pop.get(j); + popRep.addDPoint(new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1])); + tp.getFunctionArea().addDElement(popRep); + + plotLine(tp, pop.getEAIndividual(j), pop.getBestEAIndividual()); + } + } else { + // this is an inactive species + plotIndy('+',(InterfaceDataTypeDouble)pop.get(0)); + } + } + + private void plotLine(TopoPlot tp, AbstractEAIndividual indy1, + AbstractEAIndividual indy2) { + DPointSet popRep; + double[] pos1, pos2; + if (indy1 instanceof InterfaceDataTypeDouble) pos1=((InterfaceDataTypeDouble)indy1).getDoubleData(); + else pos1=(indy1).getDoublePosition(); + if (indy2 instanceof InterfaceDataTypeDouble) pos2=((InterfaceDataTypeDouble)indy2).getDoubleData(); + else pos2 =(indy2).getDoublePosition(); + + popRep = new DPointSet(); + popRep.setConnected(true); + popRep.addDPoint(new DPoint(pos1[0], pos1[1])); + popRep.addDPoint(new DPoint(pos2[0], pos2[1])); + tp.getFunctionArea().addDElement(popRep); + } + + private void plotIndy(char c, InterfaceDataTypeDouble tmpIndy) { + plotPosFit(c, tmpIndy.getDoubleData(), ((AbstractEAIndividual)tmpIndy).getFitness(0)); + } + + private void plotPosFit(char c, double[] position, double fitness) { DPointSet popRep; popRep = new DPointSet(); - popRep.addDPoint(new DPoint(tmpIndy.getDoubleData()[0], tmpIndy.getDoubleData()[1])); - double d = Math.round(100*((AbstractEAIndividual)tmpIndy).getFitness(0))/(double)100; - DPointIcon icon = new Chart2DDPointIconText(""+d); + popRep.addDPoint(new DPoint(position[0], position[1])); + double d = Math.round(100*fitness)/(double)100; + DPointIcon icon = new Chart2DDPointIconText(c+""+d); ((Chart2DDPointIconText)icon).setIcon(new Chart2DDPointIconCircle()); popRep.setIcon(icon); this.m_Topology.getFunctionArea().addDElement(popRep); } - /** - * This method is used to cap the mutation rate. - * For the global ES mutation, set the mutation rate to not more than cap. - * - * @param pop The population - * @param cap The maximum mutation rate - */ - private void capMutationRate(Population pop, double cap) { - AbstractEAIndividual indy; - InterfaceMutation mutator; - - if (cap <= 0) return; - for (int i = 0; i < pop.size(); i++) { - indy = (AbstractEAIndividual) pop.get(i); - mutator = indy.getMutationOperator(); - if (mutator instanceof MutateESGlobal) { - ((MutateESGlobal)mutator).setMutationStepSize(Math.min(cap, ((MutateESGlobal)mutator).getMutationStepSize())); - } - } - } - /** This method is called to generate n freshly initialized individuals * @param n Number of new individuals * @return A population of new individuals @@ -274,10 +312,11 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis Population result = new Population(); result.setUseHistory(true); result.setTargetSize(n); - //@todo: crossover between species is to be impelemented - this.m_Problem.initPopulation(result); - this.m_Problem.evaluate(result); - this.capMutationRate(result, RNG.randomDouble(0.001, 0.1)); + //@todo: crossover between species is to be implemented + m_Problem.initPopulation(result); + m_Problem.evaluate(result); + m_Optimizer.setPopulation(result); // for some initialization by the optimizer, such as PSO memory +// capMutationRate(result, RNG.randomDouble(0.001, 0.1)); return result; } @@ -289,37 +328,59 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis * @return True if converged. */ private boolean testSpeciesForConvergence(Population pop) { - ArrayList tmpA = pop.m_History; - int length = pop.m_History.size(); + ArrayList speciesHistory = pop.m_History; + int histLen = speciesHistory.size(); - if (length <= haltingWindow) { + if (histLen <= haltingWindow) { // System.out.println("not long enough... gen " + pop.getGeneration()); return false; } else { - AbstractEAIndividual historicHWAgo = ((AbstractEAIndividual)pop.m_History.get(length-haltingWindow)); + AbstractEAIndividual historicHWAgo = speciesHistory.get(histLen-haltingWindow); for (int i = 1; i < haltingWindow; i++) { - // if historic[-hW] is worse than historic[-hW+] return false - AbstractEAIndividual historicIter = pop.m_History.get(length-haltingWindow+i); - if (historicIter.isDominatingDebConstraints(historicHWAgo)) return false; + // if historic[-hW] is worse than historic[-hW+i] return false + AbstractEAIndividual historicIter = speciesHistory.get(histLen-haltingWindow+i); + // if the iterated indy (the later one in history) has improved, there is no convergence. + if (testSecondForImprovement(historicHWAgo, historicIter)) return false; + // if (historicHWAgo.getFitness(0) > ((AbstractEAIndividual)pop.m_History.get(length-haltingWindow+i)).getFitness(0)) { // System.out.println("( " + historic.getFitness(0) + "/" + ((AbstractEAIndividual)pop.m_History.get(length-haltingWindow+i)).getFitness(0)); // return false; // } } } - if (TRACE) { + if (false) { // plot the historic fitness values double[] a = new double[2]; a[0] = 0; a[1] = 0; Plot plot = new Plot("HaltingWindow", "History", "Fitness", a, a); - for (int i = 0; i < tmpA.size(); i++) { - a = ((AbstractEAIndividual)tmpA.get(i)).getFitness(); - plot.setUnconnectedPoint(i, a[0], 0); + plot.setUnconnectedPoint(0, -1, 0); + for (int i = haltingWindow; i > 0; i--) { + a = speciesHistory.get(histLen-i).getFitness(); + plot.setUnconnectedPoint(haltingWindow-i+1, a[0], 0); } } return true; } - private Population optimizeSpecies(Population species) { + /** + * Define the criterion by which individual improvement is judged. The original version defined + * improvement strictly, but for some EA this should be done more laxly. E.g. DE will hardly ever + * stop improving slightly, so optionally use an epsilon-bound: improvement only counts if it is + * larger than epsilon in case useEpsilonBound is true. + * + * @param firstIndy + * @param secIndy + * @return true if the second individual has improved in relation to the first one + */ + private boolean testSecondForImprovement(AbstractEAIndividual firstIndy, AbstractEAIndividual secIndy) { + if (epsilonBound > 0) { + double fitDiff = (new ObjectiveSpaceMetric()).distance(firstIndy, secIndy); + boolean ret = (secIndy.isDominatingDebConstraints(firstIndy)); + ret = ret && (fitDiff > epsilonBound); // there is improvement if the second is dominant and the fitness difference is larger than epsilon + return ret; + } else return (secIndy.isDominatingDebConstraints(firstIndy)); + } + + private Population optimizeSpecies(Population species, boolean minorPlot) { m_Optimizer.setPopulation(species); // m_Optimizer.initByPopulation(species, false); if (m_Optimizer instanceof EvolutionStrategies) { @@ -327,7 +388,7 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis int mu = Math.max(1,(int)(muLambdaRatio*species.size())); if (mu >= species.size()) { if (TRACE) System.err.println("warning, muLambdaRatio produced mu >= lambda.. reducing to mu=lambda-1"); - mu = species.size() - 1; + mu = Math.max(1,species.size() - 1); } es.setMu(mu); es.setLambda(species.size()); @@ -337,8 +398,15 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis System.out.println("Bef: spec size: " + species.size() + ", target size " + species.getTargetSize()); System.out.println("Best bef: " + BeanInspector.toString(m_Optimizer.getPopulation().getBestFitness())); } + + if (BeanInspector.hasMethod(m_Optimizer, "getLastModelPopulation")!=null) { + Object pc = BeanInspector.callIfAvailable(m_Optimizer, "getLastTrainingPatterns", null); + System.out.println("MAPSO train set bef optSpec: " + BeanInspector.callIfAvailable(pc, "getStringRepresentation", null)); + } + this.m_Optimizer.optimize(); Population retPop = m_Optimizer.getPopulation(); + if (TRACE) { System.out.println("Aft: spec size: " + retPop.size() + ", target size " + retPop.getTargetSize()); System.out.println("Best aft: " + BeanInspector.toString(retPop.getBestFitness())); @@ -348,11 +416,17 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis retPop.synchSize(); } -// if (useDistraction) { +// if (useDistraction) { // distraction step // if ((distraction != null) && (!distraction.isEmpty())) { // System.out.println("Distraction step!!!"); +// boolean distrHappened = false; // for (int i=0; i0) { + reinitPop = this.initializeIndividuals(m_doomedPop.size()); // do not add these to undifferentiated yet, that would mess up the evaluation count + m_doomedPop.clear(); + if (TRACE) System.out.println("Reinited " + reinitPop.size() + " indies... "); + } + int countIndies = (reinitPop != null ? reinitPop.size() : 0) + m_Undifferentiated.size(); + for (int i=0; i 0) { - if ((this.m_Undifferentiated.getGeneration() == 0) || (this.m_Undifferentiated.getGeneration() == 1) || (this.m_Undifferentiated.getGeneration() == 2)) { - this.plot(this.m_Undifferentiated.getGeneration()); - } else { - if (this.m_Undifferentiated.getGeneration()%this.m_ShowCycle == 0) this.plot(this.m_Undifferentiated.getGeneration()); - } + if (m_Undifferentiated.getGeneration()<=1) plot(m_Undifferentiated.getGeneration()); } - // species evolution phase - if (TRACE) { - System.out.println(""); - System.out.println("Optimizing Generation " + this.m_Undifferentiated.getGeneration()); - } + // optimize D_0 this.m_Undifferentiated.synchSize(); - if (isActive(m_Undifferentiated)) { - this.capMutationRate(this.m_Undifferentiated, 0); // MK TODO this sets mutation rate to 0! why? - m_Undifferentiated = optimizeSpecies(m_Undifferentiated); - } else { - this.m_Undifferentiated.incrGeneration(); - //m_Undifferentiated.incrFunctionCallsby(m_Undifferentiated.size()); // TODO this is not optimal, an evaluation is wasted to keep N steps per gen. - } - - // now the population is of max size - if (TRACE) { - System.out.println("-Undiff. size: " + this.m_Undifferentiated.size()); - System.out.println("-Number of Demes: " + this.m_Species.size()); - System.out.println("-Funcalls: "+m_Undifferentiated.getFunctionCalls()); - } + if (m_Undifferentiated.size()>0) { +// this.capMutationRate(this.m_Undifferentiated, 0); // MK this sets mutation rate to 0! why? + m_Undifferentiated.putData(InterfaceSpeciesAware.populationTagKey, InterfaceSpeciesAware.explorerPopTag); + m_Undifferentiated = optimizeSpecies(m_Undifferentiated, false); + } else m_Undifferentiated.incrGeneration(); Population curSpecies; // optimize the clustered species @@ -399,7 +468,7 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis curSpecies = ((Population)this.m_Species.get(i)); curSpecies.SetFunctionCalls(0); curSpecies.synchSize(); - if (isActive(curSpecies)) { +// if (isActive(curSpecies)) { // Lets have only active species... if ((haltingWindow > 0) && (this.testSpeciesForConvergence(curSpecies))) { ///////////////////////////////////////////// Halting Window ///////////////////////////////////////////////// // if (this.m_Debug) { @@ -407,31 +476,32 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis // System.out.println("Diff.Size : " + ((Population)this.m_Species.get(i)).size() +"/"+((Population)this.m_Species.get(i)).getPopulationSize()); // } convergedCnt++; - if (TRACE) System.out.println("--Converged: "+convergedCnt); +// if (TRACE) + if (TRACE) System.out.print("--Converged: "+convergedCnt + " - " + testSpeciesForConvergence(curSpecies)); + if (TRACE) System.out.println(curSpecies.getBestEAIndividual()); + // memorize the best one.... AbstractEAIndividual best = (AbstractEAIndividual)curSpecies.getBestEAIndividual().getClone(); - - int reinitCount = -1; - -// if (useDistraction) { +// if (useDistraction) { // Add distractor! // if (distraction == null) distraction = new Distraction(distrDefaultStrength, Distraction.METH_BEST); // distraction.addDistractorFrom(curSpecies); // System.out.println("** Adding distractor! " + BeanInspector.toString(distraction.getDistractionCenter(curSpecies, distraction.getDistractionMethod().getSelectedTagID()))); // } - - if (m_UseArchive) { + int toReinit=0; + if (true) { //if (m_UseArchive) { m_Archive.add(best); - m_Species.remove(i); //REMOVES the converged Species - reinitCount = curSpecies.size(); // add all as new - } else { - // now reset the converged species to inactivity size = 1 - reinitCount = curSpecies.size()-1; // add all but one as new - deactivateSpecies(curSpecies, best); + m_Species.remove(i); // remove the converged Species + toReinit=curSpecies.size(); } - // reinit the surplus individuals and add these new individuals to undifferentiated - m_Undifferentiated.addPopulation(this.initializeIndividuals(reinitCount)); - m_Undifferentiated.incrFunctionCallsBy(reinitCount); - m_Undifferentiated.setTargetSize(this.m_Undifferentiated.getTargetSize()+reinitCount); +// else { +// // reset the converged species to inactivity size = 1 +// toReinit=curSpecies.size()-1; +// deactivateSpecies(curSpecies, best, null); +// } + // those will not be optimized anymore, so we dont need to doom them, but can directly add them to undiff! + m_Undifferentiated.addPopulation(initializeIndividuals(toReinit)); + m_Undifferentiated.incrFunctionCallsBy(toReinit); + // if (this.m_Debug) { // System.out.println("Undiff.Size: " + this.m_Undifferentiated.size() +"/"+this.m_Undifferentiated.getPopulationSize()); // System.out.println("Diff.Size : " + ((Population)this.m_Species.get(i)).size() +"/"+((Population)this.m_Species.get(i)).getPopulationSize()); @@ -440,218 +510,317 @@ public class ClusterBasedNichingEA implements InterfacePopulationChangedEventLis ////////////////////////////////////////////////////////////////////////////////////////////////////////////// } else { // actually optimize D_i - this.capMutationRate(curSpecies, 0.05); - Population optimizedSpec = optimizeSpecies(curSpecies); +// this.capMutationRate(curSpecies, 0.05); + curSpecies.putData(InterfaceSpeciesAware.populationTagKey, InterfaceSpeciesAware.localPopTag); + Population optimizedSpec = optimizeSpecies(curSpecies, true); this.m_Species.set(i, optimizedSpec); curSpecies = ((Population)this.m_Species.get(i)); // reset to expected population, just to be sure } - } else { - // a single individual species, this element is inactive - if (TRACE) System.out.println("inactive species not optimized"); -// curSpecies.incrFunctionCallsby(curSpecies.size()); // was todo: not so good - } +// } // This is necessary to keep track of the function calls needed - this.m_Undifferentiated.SetFunctionCalls(this.m_Undifferentiated.getFunctionCalls() + curSpecies.getFunctionCalls()); + m_Undifferentiated.incrFunctionCallsBy(curSpecies.getFunctionCalls()); if (TRACE) System.out.println("### funcalls: "+m_Undifferentiated.getFunctionCalls()); } - if (TRACE) System.out.println("-Number of Demes: " + this.m_Species.size()); ////////////////////// - if (!isActive(m_Undifferentiated)) { - if (TRACE) System.out.println("Inactive Undiff-pop, adding " + m_Undifferentiated.size() + " fun calls..."); - m_Undifferentiated.incrFunctionCallsBy(m_Undifferentiated.size()); - } - if (this.m_Undifferentiated.getFunctionCalls() % this.m_PopulationSize != 0) { - if (TRACE) System.out.println("### mismatching number of funcalls, inactive species? Correcting by " + (m_PopulationSize - (m_Undifferentiated.getFunctionCalls() % m_PopulationSize))); - if (TRACE) System.out.println("### undiff " + ((isActive(m_Undifferentiated)) ? "active!" : "inactive!")); - m_Undifferentiated.incrFunctionCallsBy(m_PopulationSize - (m_Undifferentiated.getFunctionCalls() % m_PopulationSize)); - } else if (TRACE) System.out.println("### undiff active: " + isActive(m_Undifferentiated)); + if ((this.m_Undifferentiated.getFunctionCalls()+(reinitPop==null ? 0 : (reinitPop.size()))) % this.m_PopulationSize != 0) { + if (TRACE) System.out.println("### mismatching number of funcalls, inactive species?");// Correcting by " + (m_PopulationSize - (m_Undifferentiated.getFunctionCalls() % m_PopulationSize))); +// if (TRACE) System.out.println("### undiff " + ((isActive(m_Undifferentiated)) ? "active!" : "inactive!")); +// m_Undifferentiated.incrFunctionCallsBy(m_PopulationSize - (m_Undifferentiated.getFunctionCalls() % m_PopulationSize)); + } //else if (TRACE) System.out.println("### undiff active: " + isActive(m_Undifferentiated)); // possible species differentiation and convergence if (this.m_Undifferentiated.getGeneration()%this.m_SpeciesCycle == 0) { if (TRACE) System.out.println("Species cycle:"); - - if (this.m_UseSpeciesDifferentation) { + this.m_CAForSpeciesDifferentation.initClustering(m_Population); + if (this.m_UseSpeciesDifferentiation) { ///////////////////////////// species differentiation phase - if (TRACE) System.out.println("-Species Differentation:"); - Population[] ClusterResult; + if (TRACE) printState("---Species Differentation", reinitPop); + Population[] clusters; ArrayList newSpecies = new ArrayList(); //cluster the undifferentiated population - ClusterResult = this.m_CAForSpeciesDifferentation.cluster(this.m_Undifferentiated); - this.m_Undifferentiated = ClusterResult[0]; - for (int j = 1; j < ClusterResult.length; j++) { - ClusterResult[j].setUseHistory(true); - ClusterResult[j].setGenerationTo(0); - ClusterResult[j].m_History = new ArrayList(); - newSpecies.add(ClusterResult[j]); + clusters = this.m_CAForSpeciesDifferentation.cluster(this.m_Undifferentiated, m_Population); + if (TRACE) System.out.println("clustered undiff to " + clusters.length); + replaceUndifferentiated(clusters[0]); + for (int j = 1; j < clusters.length; j++) { // loop new clusters + splitFromFirst(m_Undifferentiated, clusters[j], false); + newSpecies.add(clusters[j]); } - for (int i = 0; i < this.m_Species.size(); i++) { + for (int i = 0; i < this.m_Species.size(); i++) { // loop old species curSpecies = this.m_Species.get(i); - if (isActive(curSpecies)) { - // only active populations are clustered - ClusterResult = this.m_CAForSpeciesDifferentation.cluster(curSpecies); - this.m_Undifferentiated.addPopulation(ClusterResult[0]); -// ClusterResult[0].setUseHistory(true); - this.m_Undifferentiated.setTargetSize(this.m_Undifferentiated.getTargetSize() + ClusterResult[0].size()); - for (int j = 1; j < ClusterResult.length; j++) { // set up new species - ClusterResult[j].synchSize(); - ClusterResult[j].setUseHistory(true); -// if (ClusterResult.length > 2) ClusterResult[j].m_History = new ArrayList(); // mk: why min 3? Ill copy the history from the original pop for any j... - ClusterResult[j].m_History = (ArrayList) curSpecies.m_History.clone(); - newSpecies.add(ClusterResult[j]); +// if (curSpecies.size()>m_minGroupSize) { // only active populations are clustered + // check if a species has differentiated any further + clusters = this.m_CAForSpeciesDifferentation.cluster(curSpecies, m_Population); + if (TRACE) System.out.println("clustered " + i + " to " + clusters.length); + if (clusters[0].size()>0) mergeToFirst(m_Undifferentiated, clusters[0], false); + for (int j = 1; j < clusters.length; j++) { // set up new species + // this is treated as a split only if more than one cluster was found + // so if clustering results in a list of size 2: [undiff,spec], the curSpecies only is maintained. + if (clusters.length<=2) clusters[j].addDataFromPopulation(curSpecies); // copy earlier data to corresponding new cluster + else splitFromFirst(curSpecies, clusters[j], true); + newSpecies.add(clusters[j]); + } - } else { - // inactive populations are added directly - newSpecies.add(this.m_Species.get(i)); - } +// } else { +// // small populations are kept directly +// newSpecies.add(curSpecies); +// } } this.m_Species = newSpecies; - if (TRACE) { - System.out.println("--Number of species: " + this.m_Species.size()); - System.out.println("---Undiff size: " + this.m_Undifferentiated.size()); - for (int i = 0; i < this.m_Species.size(); i++) { - System.out.println("---Deme " + i + " size: " + ((Population)this.m_Species.get(i)).size()); - } - } + if (TRACE) printState("---After differentiation", reinitPop); + //if (this.m_Show) this.plot(); + } // end of species differentiation + + // plot the populations + if (this.m_ShowCycle > 0) { + if ((this.m_Undifferentiated.getGeneration() <= 2)) { + this.plot(this.m_Undifferentiated.getGeneration()); + } else { + if (this.m_Undifferentiated.getGeneration()%this.m_ShowCycle == 0) this.plot(this.m_Undifferentiated.getGeneration()); + } } - if (this.m_UseSpeciesMerging) { -///////////////////////////// species convergence phase + if (this.m_mergeSpecies && (m_Species.size()>0)) { +///////////////////////////// species merging phase if (TRACE) { - System.out.println("-Species convergence:"); - System.out.println("-Funcalls: " + m_Undifferentiated.getFunctionCalls()); + System.out.println("-Species merge:"); } - // first test if loners belong to any species - boolean found = false; - for (int i = 0; i < this.m_Undifferentiated.size(); i++) { - int j=0; - while (!found && j=0; i--) { // backwards or die! + if (assocSpec[i]>=0) { + // loner i should be merged to species assocSpec[i] + AbstractEAIndividual tmpIndy = (AbstractEAIndividual)this.m_Undifferentiated.get(i); + if (m_Topology!=null) plotLine(m_Topology, tmpIndy, m_Species.get(assocSpec[i]).getBestEAIndividual()); + this.m_Undifferentiated.remove(i); + m_Species.get(assocSpec[i]).add(tmpIndy); // TODO merge information from loners? + } } - // Now test if species converge + if (TRACE) printState("---After loner-merges", reinitPop); Population spec1, spec2; + // test if species are close to already archived solutions - deactivate them if so + assocSpec = m_CAForSpeciesMerging.associateLoners(m_Archive, m_Species.toArray(new Population[m_Species.size()]), m_Population); + PriorityQueue specToRemove = new PriorityQueue(5,Collections.reverseOrder()); // backwards sorted or DIE! + for (int i=m_Archive.size()-1; i>=0; i--) { + if (assocSpec[i]>=0) { + AbstractEAIndividual aIndy = m_Archive.getEAIndividual(i); + spec1 = (Population)this.m_Species.get(assocSpec[i]); + // archived solution corresponds to an existing species + if (!specToRemove.contains(assocSpec[i])) { + // the species has not yet been deactivated + specToRemove.add(assocSpec[i]); + if (TRACE) System.out.println("Inactive merge - resetting " + spec1.size() + " surplus indies"); + if (spec1.getBestEAIndividual().isDominating(aIndy)) { + // update the archived one with the better one? No rather not - it may happen that a large species is assoctiated which is quite large and spans over several optima - in that case an earlier found may get lost +// m_Archive.set(i, spec1.getBestEAIndividual()); + } + m_doomedPop.addPopulation(spec1); + } + } + } + int lastRemoved = Integer.MAX_VALUE; + while (!specToRemove.isEmpty()) { // backwards sorted or DIE! + int specIndex = specToRemove.poll(); + if (specIndex > lastRemoved) System.err.println("Stupid queue!!!"); + if (TRACE) System.out.println("Removing species at index " + specIndex); + m_Species.remove(specIndex); // warning, dont try to remove Integer object but index i! + lastRemoved = specIndex; + } + if (TRACE) printState("---After archive-merges", reinitPop); + // Now test if species should be merged among each other for (int i1 = 0; i1 < this.m_Species.size(); i1++) { spec1 = (Population)this.m_Species.get(i1); for (int i2 = i1+1; i2 < this.m_Species.size(); i2++) { spec2 = (Population)this.m_Species.get(i2); - if (this.m_CAForSpeciesConvergence.mergingSpecies(spec1, spec2)) { - if (TRACE) System.out.println("--------------------Merging species (" + i1 +", " +i2 +") ["+spec1.size()+"/"+spec2.size()+"]"); -// this.m_CAForSpeciesConvergence.convergingSpecies(spec1, spec2); - if (isActive(spec1) && isActive(spec2)) { - if (TRACE) System.out.println("---Active merge"); - - spec1.addPopulation(spec2); - // keep longer history - if (spec2.m_History.size() > spec1.m_History.size()) spec1.m_History = spec2.m_History; - this.m_Species.remove(i2); - i2--; - } else { - // one of the species is converged, so we interpret the best as the optimum found - if (TRACE) System.out.println("---Inactive merge"); - // save best in singular species and reinit the rest of the individuals - spec1.addPopulation(spec2); - this.m_Species.remove(i2); - i2--; - int reinitCount = spec1.size()-1; - // now reset the converged species to inactivity DEACTIVATE! - deactivateSpecies(spec1, spec1.getBestEAIndividual()); - // reinitialized individuals and add them to undifferentiated - this.m_Undifferentiated.addPopulation(this.initializeIndividuals(reinitCount)); -// m_Undifferentiated.incrFunctionCallsby(reinitCount); - this.m_Undifferentiated.setTargetSize(this.m_Undifferentiated.getTargetSize()+reinitCount); - } + if (this.m_CAForSpeciesMerging.mergingSpecies(spec1, spec2, m_Population)) { + if (TRACE) System.out.println("----Merging species (" + i1 +", " +i2 +") ["+spec1.size()+"/"+spec2.size()+"]"); + mergeToFirst(spec1, spec2, true); + this.m_Species.remove(i2); + i2--; } } } - if (TRACE) System.out.println("--Number of species: " + this.m_Species.size()); + if (TRACE) printState("---After merging", reinitPop); + } /// end of species merging + + if (m_maxSpeciesSize >= m_minGroupSize) { + // reinit worst n individuals from all species which are too large + for (int i=0; im_maxSpeciesSize) { + ArrayList sorted = curSpec.getSorted(reduceSizeComparator); + for (int k=m_maxSpeciesSize; k0)) { + m_Undifferentiated.addPopulation(reinitPop); + m_Undifferentiated.incrFunctionCallsBy(reinitPop.size()); } + m_Undifferentiated.setTargetSize(m_Undifferentiated.size()); // output the result - if (TRACE) System.out.println("-Number of species: " + this.m_Species.size()); if (TRACE) System.out.println("-Funcalls: " + this.m_Undifferentiated.getFunctionCalls()); - - this.m_Population = (Population)this.m_Undifferentiated.clone(); - m_Population.setUseHistory(true); - if (TRACE) System.out.println("initing with " + this.m_Undifferentiated.size()); - for (int i = 0; i < this.m_Species.size(); i++) { - if (TRACE) System.out.println("Adding deme " + i + " with size " + ((Population)this.m_Species.get(i)).size()); - this.m_Population.addPopulation((Population)this.m_Species.get(i)); + + synchronized (m_Population) { // fill the m_Population instance with the current individuals from undiff, spec, etc. + this.m_Population = (Population)this.m_Undifferentiated.clone(); + m_Population.setUseHistory(true); + for (int i = 0; i < this.m_Species.size(); i++) { + this.m_Population.addPopulation((Population)this.m_Species.get(i)); + } + if (m_doomedPop.size()>0) m_Population.addPopulation(m_doomedPop); // this is just so that the numbers match up... + m_Population.synchSize(); + if (TRACE) { + System.out.println("Doomed size: " + m_doomedPop.size()); + System.out.println("Population size: " + this.m_Population.size()); + } + if (m_Population.size()!=m_PopulationSize) { + System.err.println("Warning: Invalid population size in CBNEA! " + m_Population.size()); + } + if (TRACE_STATE) { + printState("---- EoCBN", m_doomedPop); + System.out.println("Archive: " + m_Archive.getStringRepresentation()); + } } - if (TRACE) System.out.println("Population size: " + this.m_Population.size()); // if (TRACE) { +// // this is just a test adding all species centers as distractors with high strength // Distraction distr = new Distraction(5., 0, m_Species); // if (!distr.isEmpty()) { // double[] distVect = distr.calcDistractionFor(m_Undifferentiated.getBestEAIndividual()); // System.out.println("species distract best towards " + BeanInspector.toString(distVect)); // } // } + this.firePropertyChangedEvent(Population.nextGenerationPerformed); } +// +// /** +// * Unite all current species and the undiff. pop and return +// * the merged set. Note that data such as generation, evaluations etc +// * are not copied! +// * +// * @return +// */ +// private Population getCurrentPop() { +// Population pop = new Population(getPopulationSize()); +// pop.addPopulation(m_Undifferentiated); +// for (int i=0; i0) { + sum+=m_Species.get(0).size(); + System.out.print(specTag(m_Species.get(0))); + for (int i=1; i spec1.m_History.size()) spec1.m_History = spec2.m_History; + if (spec2.getGeneration() > spec1.getGeneration()) spec1.setGenerationTo(spec2.getGeneration()); + // possibly notify the optimizer of the merging event to merge population based information + if (m_Optimizer instanceof InterfaceSpeciesAware) ((InterfaceSpeciesAware)m_Optimizer).mergeToFirstPopulationEvent(spec1, spec2); + } /** - * Return true if the given population is considered active. - * - * @param pop a population - * @return true, if pop is considered an active population, else false - */ - protected boolean isActive(Population pop) { - return (pop.size() >= m_actSpecSize); - } - - /** - * Deactivate a given species by removing all individuals and inserting - * only the given survivor, sets the population size to one. + * A split event will reset the new species model so as to have a fresh start. * - * @param spec + * @param parentSp + * @param newSp + * @param startAtP1Gen */ - protected void deactivateSpecies(Population spec, AbstractEAIndividual survivor) { - spec.setTargetSize(1); - spec.clear(); - spec.add(survivor); - } - - - public int countActiveSpec() { - int k = 0; - for (int i=0; i) parentSp.m_History.clone(); + } else { // start anew (from undiff) + newSp.setGenerationTo(0); + newSp.m_History = new ArrayList(); } - return k; - } + + if (m_Optimizer instanceof InterfaceSpeciesAware) ((InterfaceSpeciesAware)m_Optimizer).splitFromFirst(parentSp, newSp); + } + +// /** +// * Return true if the given population is considered active. +// * +// * @param pop a population +// * @return true, if pop is considered an active population, else false +// */ +// protected boolean isActive(Population pop) { +// return (pop.size() >= m_actSpecSize); +// } + +// /** +// * Deactivate a given species by removing all individuals and inserting +// * only the given survivor, sets the population size to one. +// * +// * @param spec +// */ +// protected void deactivateSpecies(Population spec, AbstractEAIndividual survivor, Population collectDoomed) { +// if (!spec.remove(survivor)) System.err.println("WARNING: removing survivor failed in CBN.deactivateSpecies!");; +// if (collectDoomed!=null) collectDoomed.addPopulation(spec); +// spec.clear(); +// spec.add(survivor); +// spec.setPopulationSize(1); +// } + +// public int countActiveSpec() { +// int k = 0; +// for (int i=0; i1) Mathematics.svDiv((double)m_Species.size(), measures, measures); + return measures; + } } + + public int getMaxSpeciesSize() { + return m_maxSpeciesSize; + } + public void setMaxSpeciesSize(int mMaxSpeciesSize) { + m_maxSpeciesSize = mMaxSpeciesSize; + GenericObjectEditor.setShowProperty(this.getClass(), "reduceSizeComparator", (m_maxSpeciesSize >= m_minGroupSize)); + } + public String maxSpeciesSizeTipText() { + return "If >= " + m_minGroupSize + ", larger species are reduced to the given size by reinitializing the worst individuals."; + } + + public String reduceSizeComparatorTipText() { + return "Set the comparator used to define the 'worst' individuals when reducing species size."; + } + public AbstractEAIndividualComparator getReduceSizeComparator() { + return reduceSizeComparator; + } + public void setReduceSizeComparator( + AbstractEAIndividualComparator reduceSizeComparator) { + this.reduceSizeComparator = reduceSizeComparator; + } + + public String[] customPropertyOrder() { + return new String[]{"mergingCA", "differentiationCA"}; + } + } diff --git a/src/eva2/server/go/strategies/DifferentialEvolution.java b/src/eva2/server/go/strategies/DifferentialEvolution.java index 4bc65e64..c9770636 100644 --- a/src/eva2/server/go/strategies/DifferentialEvolution.java +++ b/src/eva2/server/go/strategies/DifferentialEvolution.java @@ -250,8 +250,8 @@ public class DifferentialEvolution implements InterfaceOptimizer, java.io.Serial indy = (AbstractEAIndividual)(pop.getEAIndividual(parentIndex)).getClone(); esIndy = (InterfaceDataTypeDouble)indy; } catch (java.lang.ClassCastException e) { - EVAERROR.errorMsgOnce("Differential Evolution currently requires InterfaceESIndividual as basic data type!"); - return (AbstractEAIndividual)((AbstractEAIndividual)pop.get(RNG.randomInt(0, pop.size()-1))).getClone(); + throw new RuntimeException("Differential Evolution currently requires InterfaceESIndividual as basic data type!"); +// return (AbstractEAIndividual)((AbstractEAIndividual)pop.get(RNG.randomInt(0, pop.size()-1))).getClone(); } double[] nX, vX, oX; oX = esIndy.getDoubleData(); diff --git a/src/eva2/server/go/strategies/EvolutionStrategies.java b/src/eva2/server/go/strategies/EvolutionStrategies.java index 4882ee38..543ae879 100644 --- a/src/eva2/server/go/strategies/EvolutionStrategies.java +++ b/src/eva2/server/go/strategies/EvolutionStrategies.java @@ -239,7 +239,7 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ */ protected Population getReplacePop(Population nextGeneration) { if (forceOrigPopSize && (origPopSize > 0) && (origPopSize < nextGeneration.size())) { - // this is especially for CBN: + // this is especially for CBN: earlier selection to immediately reduce the size of mu+lambda to lambda this.m_EnvironmentSelection.prepareSelection(nextGeneration); Population tmpPop = (Population)nextGeneration.clone(); nextGeneration.clear(); @@ -368,8 +368,9 @@ public class EvolutionStrategies implements InterfaceOptimizer, java.io.Serializ System.err.println("Invalid mu/lambda ratio! Setting mu=lambda="+m_Mu); this.m_Lambda = this.m_Mu; } - if (this.m_UsePlusStrategy) this.m_Population.setTargetSize(this.m_Mu + this.m_Lambda); - else this.m_Population.setTargetSize(this.m_Lambda); +// if (this.m_UsePlusStrategy) this.m_Population.setTargetSize(this.m_Mu + this.m_Lambda); +// else this.m_Population.setTargetSize(this.m_Lambda); + this.m_Population.setTargetSize(this.m_Lambda); origPopSize=m_Population.getTargetSize(); } diff --git a/src/eva2/server/go/strategies/InterfaceSpeciesAware.java b/src/eva2/server/go/strategies/InterfaceSpeciesAware.java new file mode 100644 index 00000000..2b0553f5 --- /dev/null +++ b/src/eva2/server/go/strategies/InterfaceSpeciesAware.java @@ -0,0 +1,32 @@ +package eva2.server.go.strategies; + +import eva2.server.go.populations.Population; + +/** + * An interface for optimizers which are to be notified in case of species + * based optimization; namely merging and split events. + * + * @author mkron + * + */ +public interface InterfaceSpeciesAware { + // these can be used to tag a population as explorer or local search population. + public final static String populationTagKey="specAwarePopulationTag"; + public final static Integer explorerPopTag=23; + public final static Integer localPopTag=42; + + /** + * Two species have been merged to the first one. + * @param p1 + * @param p2 + */ + public void mergeToFirstPopulationEvent(Population p1, Population p2); + + /** + * Notify that a split has occurred separating p2 from p1. + * + * @param p1 + * @param p2 + */ + public void splitFromFirst(Population p1, Population p2); +} diff --git a/src/eva2/server/go/strategies/ParticleSwarmOptimization.java b/src/eva2/server/go/strategies/ParticleSwarmOptimization.java index 53913a03..91f1c9d6 100644 --- a/src/eva2/server/go/strategies/ParticleSwarmOptimization.java +++ b/src/eva2/server/go/strategies/ParticleSwarmOptimization.java @@ -1201,7 +1201,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se } public void optimize() { - +// System.out.println(">>> " + m_Population.getStringRepresentation()); startOptimize(); // Update the individuals @@ -1216,7 +1216,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se // log the best individual of the population logBestIndividual(); -// System.out.println(">>> " + m_Population.getBestEAIndividual().getStringRepresentation()); +// System.out.println("<<< " + m_Population.getStringRepresentation()); // if (doLocalSearch && (m_Population.getGeneration()%localSearchGens==0)) { //// System.out.println("Local search at gen "+m_Population.getGeneration()); diff --git a/src/eva2/server/modules/Processor.java b/src/eva2/server/modules/Processor.java index b7543616..75988d47 100644 --- a/src/eva2/server/modules/Processor.java +++ b/src/eva2/server/modules/Processor.java @@ -343,6 +343,7 @@ public class Processor extends Thread implements InterfaceProcessor, InterfacePo if (this.goParams.getOptimizer() instanceof InterfaceAdditionalPopulationInformer) informerList.add(this.goParams.getOptimizer()); m_Statistics.createNextGenerationPerformed( (PopulationInterface)this.goParams.getOptimizer().getPopulation(), + this.goParams.getOptimizer(), informerList); if (m_ListenerModule != null) { m_ListenerModule.updateProgress( diff --git a/src/eva2/server/stat/AbstractStatistics.java b/src/eva2/server/stat/AbstractStatistics.java index df1b62f3..ac639477 100644 --- a/src/eva2/server/stat/AbstractStatistics.java +++ b/src/eva2/server/stat/AbstractStatistics.java @@ -14,8 +14,10 @@ import eva2.server.go.IndividualInterface; import eva2.server.go.PopulationInterface; import eva2.server.go.individuals.AbstractEAIndividual; import eva2.server.go.operators.distancemetric.InterfaceDistanceMetric; +import eva2.server.go.populations.InterfaceSolutionSet; import eva2.server.go.populations.Population; import eva2.server.go.problems.InterfaceAdditionalPopulationInformer; +import eva2.server.go.strategies.InterfaceOptimizer; import eva2.tools.Mathematics; import eva2.tools.Pair; @@ -77,7 +79,7 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter private ArrayList textListeners; private List lastInformerList = null; - private PopulationInterface lastPop = null; + private PopulationInterface lastSols = null; public AbstractStatistics() { firstPlot = true; @@ -173,7 +175,7 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter currentBestFeasibleFit=null; bestOfRunFeasibleIndy = null; lastInformerList = null; - lastPop = null; + lastSols = null; runIterCnt = 0; if (printRunIntroVerbosity()) printToTextListener("\n****** Multirun "+runNumber); if (params != null) { @@ -578,8 +580,7 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter * @param pop */ private void updateLastAdditionalInfo() { - // TODO Auto-generated method stub - Double[] lastVals = appendAdditionalInfo(lastInformerList, lastPop, null); + Double[] lastVals = appendAdditionalInfo(lastInformerList, lastSols, null); lastAdditionalInfoSums = updateAdditionalInfo(lastAdditionalInfoSums, lastVals); } @@ -602,9 +603,8 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter * */ public synchronized void createNextGenerationPerformed(PopulationInterface - pop, List informerList) { + pop, InterfaceOptimizer opt, List informerList) { lastInformerList = informerList; - lastPop = pop; if (firstPlot) { initPlots(m_StatsParams.getPlotDescriptions()); // if (doTextOutput()) printToTextListener(getOutputHeader(informer, pop)+'\n'); @@ -676,7 +676,7 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter meanCollection.add(means); } else { if (meanCollection.size()<=runIterCnt) {// bad case! - // may happen for dynamic pop-sizes, e.g. in Tribe, when runs do not necessarily send the + // may happen for dynamic pop-sizes, e.g. in Tribes, when runs do not necessarily send the // "generation performed" event the same number of times. // thus: dont do an update for events that are "too late" means = null; @@ -686,8 +686,10 @@ public abstract class AbstractStatistics implements InterfaceTextListener, Inter } // meanCollection.set(pop.getGenerations()-1, means); + lastSols = (opt!=null) ? new Population(opt.getAllSolutions()) : pop; if (doTextOutput()) { - Pair addInfo = getOutputLine(informerList, pop); + Pair addInfo = getOutputLine(informerList, lastSols); + if (printLineByVerbosity(runIterCnt)) printToTextListener(addInfo.head()+'\n'); // updateAdditionalInfo(addInfo.tail()); if (addInfo.tail()!=null) { diff --git a/src/eva2/server/stat/InterfaceStatistics.java b/src/eva2/server/stat/InterfaceStatistics.java index 12391896..e0c0095e 100644 --- a/src/eva2/server/stat/InterfaceStatistics.java +++ b/src/eva2/server/stat/InterfaceStatistics.java @@ -17,6 +17,7 @@ import java.util.List; import eva2.server.go.IndividualInterface; import eva2.server.go.PopulationInterface; import eva2.server.go.problems.InterfaceAdditionalPopulationInformer; +import eva2.server.go.strategies.InterfaceOptimizer; /*==========================================================================* * INTERFACE DECLARATION *==========================================================================*/ @@ -35,7 +36,7 @@ public interface InterfaceStatistics { public void addTextListener(InterfaceTextListener listener); public boolean removeTextListener(InterfaceTextListener listener); public void printToTextListener(String s); - public void createNextGenerationPerformed(PopulationInterface Pop, List informerList); + public void createNextGenerationPerformed(PopulationInterface Pop, InterfaceOptimizer opt, List informerList); public void createNextGenerationPerformed(double[] bestfit,double[] worstfit,int calls); public InterfaceStatisticsParameter getStatisticsParameter(); // called from moduleadapter public IndividualInterface getRunBestSolution(); // return the best fitness of the last run (may not be equal to the last population) diff --git a/src/eva2/server/stat/StatisticsDummy.java b/src/eva2/server/stat/StatisticsDummy.java index 9ab076c2..543b3555 100644 --- a/src/eva2/server/stat/StatisticsDummy.java +++ b/src/eva2/server/stat/StatisticsDummy.java @@ -6,6 +6,7 @@ import eva2.server.go.IndividualInterface; import eva2.server.go.PopulationInterface; import eva2.server.go.individuals.AbstractEAIndividual; import eva2.server.go.problems.InterfaceAdditionalPopulationInformer; +import eva2.server.go.strategies.InterfaceOptimizer; /** * This may be given to a Processor if no further stats are required. It speeds up @@ -36,7 +37,7 @@ public class StatisticsDummy implements InterfaceStatistics, InterfaceTextListen System.err.println("addTextListener not provided!"); } - public void createNextGenerationPerformed(PopulationInterface pop, + public void createNextGenerationPerformed(PopulationInterface pop, InterfaceOptimizer opt, List informerList) { bestCurrentIndividual = (AbstractEAIndividual)pop.getBestIndividual(); if ((bestIndividualAllover == null) || (AbstractStatistics.secondIsBetter(bestIndividualAllover, bestCurrentIndividual))) { diff --git a/src/eva2/server/stat/StatisticsWithGUI.java b/src/eva2/server/stat/StatisticsWithGUI.java index 3f05a8b2..9417bfbc 100644 --- a/src/eva2/server/stat/StatisticsWithGUI.java +++ b/src/eva2/server/stat/StatisticsWithGUI.java @@ -247,23 +247,12 @@ public class StatisticsWithGUI extends AbstractStatistics implements Serializabl int subGraph=0; if (doPlotCurrentBest) plotFitnessPoint(0, subGraph++, functionCalls, currentBestFit[0]); if (doPlotRunBest) plotFitnessPoint(0, subGraph++, functionCalls, bestOfRunIndy.getFitness()[0]); - - if (doPlotWorst) {// schlechteste Fitness plotten - if (currentWorstFit == null) { - System.err.println("m_WorstFitness==null in plotStatisticsPerformed"); - return; - } - plotFitnessPoint(0, subGraph++ , functionCalls, currentWorstFit[0]); - } + if (doPlotWorst) plotFitnessPoint(0, subGraph++ , functionCalls, currentWorstFit[0]); if (doPlotAvgDist) plotFitnessPoint(0, subGraph++, functionCalls, avgPopDist); if (doPlotMaxPopDist) plotFitnessPoint(0, subGraph++, functionCalls, maxPopDist); - - if (doPlotCurBestFeasible && currentBestFeasibleFit!=null) { - plotFitnessPoint(0, subGraph++, functionCalls, currentBestFeasibleFit[0]); - } - if (doPlotRunBestFeasible && bestOfRunFeasibleIndy!=null) { - plotFitnessPoint(0, subGraph++, functionCalls, bestOfRunFeasibleIndy.getFitness()[0]); - } + if (doPlotCurBestFeasible && currentBestFeasibleFit!=null) plotFitnessPoint(0, subGraph++, functionCalls, currentBestFeasibleFit[0]); + if (doPlotRunBestFeasible && bestOfRunFeasibleIndy!=null) plotFitnessPoint(0, subGraph++, functionCalls, bestOfRunFeasibleIndy.getFitness()[0]); + } }