From d557e86cd0e4eacd30a26d518e03b905cea05e21 Mon Sep 17 00:00:00 2001 From: Marcel Kronfeld Date: Tue, 3 May 2011 13:47:07 +0000 Subject: [PATCH] Adding NichePSO and ANPSO from the MModal branch (adaptation of M.Aschoffs implementations) --- .../ConsiderPBestAbsorptionStrategy.java | 42 + .../EuclideanDiversityAbsorptionStrategy.java | 77 + .../InterfaceAbsorptionStrategy.java | 36 + .../StandardAbsorptionStrategy.java | 78 + .../DummyDeactivationStrategy.java | 25 + .../ImprovementDeactivationStrategy.java | 155 ++ .../InterfaceDeactivationStrategy.java | 28 + .../StandardDeactivationStrategy.java | 153 ++ .../merging/InterfaceMergingStrategy.java | 40 + .../merging/ScatterMergingStrategy.java | 96 + .../merging/StandardMergingStrategy.java | 146 ++ .../DummySubswarmCreationStrategy.java | 24 + ...erateNeighborSubswarmCreationStrategy.java | 97 + .../InterfaceSubswarmCreationStrategy.java | 35 + .../StandardSubswarmCreationStrategy.java | 119 + src/eva2/server/go/strategies/ANPSO.java | 1092 ++++++++ src/eva2/server/go/strategies/NicheGraph.java | 130 + src/eva2/server/go/strategies/NichePSO.java | 2199 +++++++++++++++++ .../ParticleSubSwarmOptimization.java | 754 ++++++ .../strategies/ParticleSwarmOptimization.java | 1 + .../ParticleSwarmOptimizationGCPSO.java | 275 +++ src/eva2/server/go/strategies/StarANPSO.java | 39 + 22 files changed, 5641 insertions(+) create mode 100644 src/eva2/server/go/operators/nichepso/absorption/ConsiderPBestAbsorptionStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/absorption/EuclideanDiversityAbsorptionStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/absorption/InterfaceAbsorptionStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/absorption/StandardAbsorptionStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/deactivation/DummyDeactivationStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/deactivation/ImprovementDeactivationStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/deactivation/InterfaceDeactivationStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/deactivation/StandardDeactivationStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/merging/InterfaceMergingStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/merging/ScatterMergingStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/merging/StandardMergingStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/subswarmcreation/DummySubswarmCreationStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/subswarmcreation/GenerateNeighborSubswarmCreationStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/subswarmcreation/InterfaceSubswarmCreationStrategy.java create mode 100644 src/eva2/server/go/operators/nichepso/subswarmcreation/StandardSubswarmCreationStrategy.java create mode 100644 src/eva2/server/go/strategies/ANPSO.java create mode 100644 src/eva2/server/go/strategies/NicheGraph.java create mode 100644 src/eva2/server/go/strategies/NichePSO.java create mode 100644 src/eva2/server/go/strategies/ParticleSubSwarmOptimization.java create mode 100644 src/eva2/server/go/strategies/ParticleSwarmOptimizationGCPSO.java create mode 100644 src/eva2/server/go/strategies/StarANPSO.java diff --git a/src/eva2/server/go/operators/nichepso/absorption/ConsiderPBestAbsorptionStrategy.java b/src/eva2/server/go/operators/nichepso/absorption/ConsiderPBestAbsorptionStrategy.java new file mode 100644 index 00000000..529cbc0b --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/absorption/ConsiderPBestAbsorptionStrategy.java @@ -0,0 +1,42 @@ +package eva2.server.go.operators.nichepso.absorption; + +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.strategies.ParticleSubSwarmOptimization; + +/** + * Particles are absorbed into a subswarm if they move into an area covered by that subswarm. + * To prevent the destabilisation of a subswarm only particles are absorbed which do not know + * a position that is better than the best position known by the subswarm. + */ +public class ConsiderPBestAbsorptionStrategy extends StandardAbsorptionStrategy{ + + + /** @tested + * true if + * the subswarm is active and + * the particle lies in the radius of the subswarm and + * the particles pbest is not better than the subswarms gbest (this would "pull the subswarm away") + * (non-Javadoc) @see javaeva.server.oa.go.Operators.NichePSO.StandardAbsorptionStrategy#shouldAbsorbParticleIntoSubswarm(javaeva.server.oa.go.EAIndividuals.AbstractEAIndividual, javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization) + */ + public boolean shouldAbsorbParticleIntoSubswarm(AbstractEAIndividual indy, ParticleSubSwarmOptimization subswarm, ParticleSubSwarmOptimization mainswarm) { + if (!super.shouldAbsorbParticleIntoSubswarm(indy, subswarm, mainswarm)){ + return false; + } + if (absorbtionConstraintViolation(indy, subswarm)){ + return false; + } + return true; + } + + /** @tested + * @param indy + * @param subswarm + * @return + */ + private boolean absorbtionConstraintViolation(AbstractEAIndividual indy, ParticleSubSwarmOptimization subswarm) { + AbstractEAIndividual indysPBest = (AbstractEAIndividual)indy.getData("PersonalBestKey"); + AbstractEAIndividual subswarmsGBest = subswarm.getGBestIndividual(); + if (indysPBest.isDominating(subswarmsGBest)) return true; + return false; + } +} diff --git a/src/eva2/server/go/operators/nichepso/absorption/EuclideanDiversityAbsorptionStrategy.java b/src/eva2/server/go/operators/nichepso/absorption/EuclideanDiversityAbsorptionStrategy.java new file mode 100644 index 00000000..ee20d4b2 --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/absorption/EuclideanDiversityAbsorptionStrategy.java @@ -0,0 +1,77 @@ +package eva2.server.go.operators.nichepso.absorption; + +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.strategies.ParticleSubSwarmOptimization; + +/** + * A threshold epsilon is proposed in [1] in order to prevent premature absorptions + * of particles into subswarms which cover large parts of the search space. + * A particle is absorbed into a subswarm if it lies within the radius of that subswarm + * and the diversity of this subswarm is below the given threshold epsilon. + * The diversity of a subswarm is defined as the average euclidean distance between + * the particles of that subswarm and the global best position of that subswarm. + * In [1], a threshold value of epsilon = 0.1 produced good results. + * [1] A.P. Engelbrecht and L.N.H. van Loggerenberg. + * Enhancing the nichepso. + * In IEEE Congress on Evolutionary Computation, + * 2007. + */ +public class EuclideanDiversityAbsorptionStrategy extends StandardAbsorptionStrategy{ + + private double epsilon = 0.1; // 0.1 used in "Enhancing the NichePSO" by Engelbrecht et al. +/********************************************************************************************************************** + * ctors + */ + public EuclideanDiversityAbsorptionStrategy() { + } + + public EuclideanDiversityAbsorptionStrategy(EuclideanDiversityAbsorptionStrategy other){ + this.epsilon = other.epsilon; + } + + public EuclideanDiversityAbsorptionStrategy(double eps) { + epsilon = eps; + } + +/********************************************************************************************************************** + * shouldAbsorbParticleIntoSubswarm + */ + /** @tested + * true if + * the subswarm is active and + * the particle lies in the radius of the subswarm and + * the diversity (mean distance from the gbest) of the subswarm < epsilon + * (non-Javadoc) @see javaeva.server.oa.go.Operators.NichePSO.StandardAbsorptionStrategy#shouldAbsorbParticleIntoSubswarm(javaeva.server.oa.go.EAIndividuals.AbstractEAIndividual, javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization) + */ + public boolean shouldAbsorbParticleIntoSubswarm(AbstractEAIndividual indy, ParticleSubSwarmOptimization subswarm, ParticleSubSwarmOptimization mainswarm) { + if (!super.shouldAbsorbParticleIntoSubswarm(indy, subswarm, mainswarm)){ + return false; // + } + if (!diversityIsBelowThreshold(subswarm)){ + return false; + } + return true; + } + + private boolean diversityIsBelowThreshold(ParticleSubSwarmOptimization subswarm) { + double meanDistanceFromGBestPos = subswarm.getEuclideanDiversity(); + if (meanDistanceFromGBestPos < getEpsilon()){ + return true; + } else return false; + } + +/********************************************************************************************************************** + * setter, getter + */ + public void setEpsilon(double epsilon) { + this.epsilon = epsilon; + } + + public double getEpsilon() { + return epsilon; + } + + public String epsilonTipText(){ + return "threshold for the diversity of the subswarm that confines the absorption of main swarm particles"; + } +} diff --git a/src/eva2/server/go/operators/nichepso/absorption/InterfaceAbsorptionStrategy.java b/src/eva2/server/go/operators/nichepso/absorption/InterfaceAbsorptionStrategy.java new file mode 100644 index 00000000..97e54d74 --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/absorption/InterfaceAbsorptionStrategy.java @@ -0,0 +1,36 @@ +package eva2.server.go.operators.nichepso.absorption; + +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.strategies.ParticleSubSwarmOptimization; + +/** + * interface for the absorption strategies used in NichePSO + */ +public interface InterfaceAbsorptionStrategy { + + /** @tested + * decides whether indy should be absorbed into the subswarm according to the absorption strategie + * @param indy + * @param subswarm the swarm indy will be absorbed from + * @param mainswarm the swarm indy currently belongs to + * (population statistics from that swarm may be used to decide whether indy should be absorbed) + * @return + */ + public abstract boolean shouldAbsorbParticleIntoSubswarm( + AbstractEAIndividual indy, + ParticleSubSwarmOptimization subswarm, + ParticleSubSwarmOptimization mainswarm); + + /** @tested + * absorbs indy according to the absorbtion strategy + * @param indy + * @param subswarm the swarm indy will be absorbed from + * @param mainswarm the swarm indy currently belongs to + */ + public abstract void absorbParticle( + AbstractEAIndividual indy, + ParticleSubSwarmOptimization subswarm, + ParticleSubSwarmOptimization mainswarm); + + public abstract Object clone(); +} diff --git a/src/eva2/server/go/operators/nichepso/absorption/StandardAbsorptionStrategy.java b/src/eva2/server/go/operators/nichepso/absorption/StandardAbsorptionStrategy.java new file mode 100644 index 00000000..d7481c63 --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/absorption/StandardAbsorptionStrategy.java @@ -0,0 +1,78 @@ +package eva2.server.go.operators.nichepso.absorption; + +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.strategies.ParticleSubSwarmOptimization; + +/** + * Particles are absorbed into a subswarm when they move into an area + * within the radius of that subswarm. + * This strategy is proposed in + * R. Brits, A. P. Engelbrecht and B. Bergh. + * A Niching Particle Swarm Optimizer + * In Proceedings of the 4th Asia-Pacific Conference on Simulated Evolution and Learning (SEAL'02), + * 2002, 2, 692-696 + */ +public class StandardAbsorptionStrategy implements InterfaceAbsorptionStrategy, java.io.Serializable { + +/********************************************************************************************************************** + * ctors, init, clone + */ + public Object clone(){ + return (Object) new StandardAbsorptionStrategy(); + } + + public String globalInfo(){ + return "Strategy to absorb main swarm particles into a subswarm"; + } + +/********************************************************************************************************************** + * shouldAbsorbParticleIntoSubswarm + */ + + /** @tested + * true if + * the subswarm is active and + * the particle lies in the radius of the subswarm + * (non-Javadoc) @see javaeva.server.oa.go.Operators.NichePSO.InterfaceAbsorptionStrategy#shouldAbsorbParticleIntoSubswarm(javaeva.server.oa.go.EAIndividuals.AbstractEAIndividual, javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization) + */ + public boolean shouldAbsorbParticleIntoSubswarm(AbstractEAIndividual indy, ParticleSubSwarmOptimization subswarm, ParticleSubSwarmOptimization mainswarm) { + if (!subswarm.isActive()){ + return false; // no interaction between active mainswarmparticle and inactive subswarm + } + if (!particleLiesInSubswarmRadius(indy, subswarm)) { + return false; + } + return true; + } + + private boolean particleLiesInSubswarmRadius(AbstractEAIndividual indy, ParticleSubSwarmOptimization subswarm) { + + double R = subswarm.getBoundSwarmRadius(); // uses euclidean distance + AbstractEAIndividual gbest = subswarm.getGBestIndividual(); + double dist = subswarm.distance(indy,gbest); // euclidean distance + if (dist <= R){ + return true; + }else return false; + } + + +/********************************************************************************************************************** + * absorbParticle + */ + + /** @tested junit + * adds indy to an active subswarm, then removes indy from the mainswarm. + * (non-Javadoc) @see javaeva.server.oa.go.Operators.NichePSO.InterfaceAbsorptionStrategy#absorbParticle(javaeva.server.oa.go.EAIndividuals.AbstractEAIndividual, javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization, javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization) + */ + public void absorbParticle(AbstractEAIndividual indy, ParticleSubSwarmOptimization subswarm, ParticleSubSwarmOptimization mainswarm) { + if (!subswarm.isActive()){ + System.out.println("absorbParticle: trying to absorb a particle into an inactive subswarm."); + return; + } + subswarm.add(indy); + subswarm.populationSizeHasChanged(); + mainswarm.removeSubIndividual(indy); + mainswarm.populationSizeHasChanged(); + } + +} diff --git a/src/eva2/server/go/operators/nichepso/deactivation/DummyDeactivationStrategy.java b/src/eva2/server/go/operators/nichepso/deactivation/DummyDeactivationStrategy.java new file mode 100644 index 00000000..d355af8c --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/deactivation/DummyDeactivationStrategy.java @@ -0,0 +1,25 @@ +package eva2.server.go.operators.nichepso.deactivation; + +import eva2.server.go.strategies.ParticleSubSwarmOptimization; + +/** + * dummy strategy does not deactivate anything + * + */ +public class DummyDeactivationStrategy implements InterfaceDeactivationStrategy, java.io.Serializable { + + public Object clone(){ + return (Object) new DummyDeactivationStrategy(); + } + + public int[] deactivateSubswarm(ParticleSubSwarmOptimization subswarm, + ParticleSubSwarmOptimization mainswarm) { + return null; + } + + public boolean shouldDeactivateSubswarm( + ParticleSubSwarmOptimization subswarm) { + return false; + } + +} diff --git a/src/eva2/server/go/operators/nichepso/deactivation/ImprovementDeactivationStrategy.java b/src/eva2/server/go/operators/nichepso/deactivation/ImprovementDeactivationStrategy.java new file mode 100644 index 00000000..61d14f82 --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/deactivation/ImprovementDeactivationStrategy.java @@ -0,0 +1,155 @@ +package eva2.server.go.operators.nichepso.deactivation; + +import java.util.List; +import java.util.Vector; + +import eva2.server.go.InterfaceTerminator; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.operators.terminators.HistoryConvergenceTerminator; +import eva2.server.go.populations.Population; +import eva2.server.go.strategies.NichePSO; +import eva2.server.go.strategies.ParticleSubSwarmOptimization; +import eva2.tools.EVAERROR; + +/** + * A subswarm is deactivated if all its particles are converged. + * A particle is considered converged if the standard deviation of its fitness values + * over the last 3 iterations is less or equal a given threshold epsilon + * Experiments showed good results using epsilon = 0.0001. + * + */ +public class ImprovementDeactivationStrategy implements InterfaceDeactivationStrategy, java.io.Serializable { + + private double epsilon = 0.0001; + private int haltingWindow = 15; + +/********************************************************************************************************************** + * ctors + */ + public ImprovementDeactivationStrategy(){ + } + + public ImprovementDeactivationStrategy(double thresh, int hwLen) { + epsilon=thresh; + haltingWindow=hwLen; + } + + public ImprovementDeactivationStrategy(ImprovementDeactivationStrategy other){ + this.epsilon = other.epsilon; + this.haltingWindow=other.haltingWindow; + } + + public ImprovementDeactivationStrategy(double eps) { + this.epsilon = eps; + } + + public Object clone(){ + return (Object) new ImprovementDeactivationStrategy(this); + } + + public String globalInfo(){ + return "Strategy to deactivate subswarms"; + } + +/********************************************************************************************************************** + * shouldDeactivateSubswarm + */ + + public boolean isConverged(Population pop){ +// Vector bests = new Vector(pop.size()); + + Vector bests = (Vector)pop.getEAIndividual(0).getData(NichePSO.fitArchiveKey); + if (bests.size() lst = bests.subList(bests.size()-haltingWindow, bests.size()); + bests = new Vector(haltingWindow); + bests.addAll(lst); + for (int i=1; i fitArch = (Vector)pop.getEAIndividual(i).getData(NichePSO.fitArchiveKey); + int archIndex=fitArch.size()-haltingWindow+k; // index within the fitness archive of the current particle, which may be larger than the bests list - the tail is important + if (archIndex>=0 && (fitArch.get(archIndex) getEpsilon()){ +// return false; // particle not converged... +// } +// } +// return true; +// } + public boolean areAllConverged(Population pop){ + for (int i = 0; i < pop.size(); ++i){ + AbstractEAIndividual currentindy = pop.getEAIndividual(i); + double value; + if (stdDevHorizon == NichePSO.defaultFitStdDevHorizon) { + value = ((Double)currentindy.getData(NichePSO.stdDevKey)).doubleValue(); + } else { + Vector fitArch = (Vector)currentindy.getData(NichePSO.fitArchiveKey); + value = ParticleSubSwarmOptimization.stdDev(fitArch,stdDevHorizon); + } + if (value > getEpsilon()){ + return false; // particle not converged... + } + + } + return true; + } + /** @tested + * true if the subswarm is active and all particles are completely converged + * (i.e. the stddev over the past 3 iterations is < epsilson) + * (non-Javadoc) @see javaeva.server.oa.go.Operators.NichePSO.InterfaceDeactivationStrategy#shouldDeactivateSubswarm(javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization) + */ + public boolean shouldDeactivateSubswarm(ParticleSubSwarmOptimization subswarm) { + if (!subswarm.isActive()){ + return false; + } + if (subswarm.getFitnessArchiveSize() subSwarms, + ParticleSubSwarmOptimization mainSwarm); + + public abstract Object clone(); +} diff --git a/src/eva2/server/go/operators/nichepso/merging/ScatterMergingStrategy.java b/src/eva2/server/go/operators/nichepso/merging/ScatterMergingStrategy.java new file mode 100644 index 00000000..d6b72c8d --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/merging/ScatterMergingStrategy.java @@ -0,0 +1,96 @@ +package eva2.server.go.operators.nichepso.merging; + +import java.util.Vector; + +import eva2.server.go.strategies.ParticleSubSwarmOptimization; + + +/** + * Two subswarms are merged if their radii overlap. + * In case both radii equal zero the subswarms are merged if their distance is below a given threshold mu. + * During merging, the particles of one of these subswarms are reinitialized into the main swarm. + * This improves exploration compared to the StandardMergingStrategy. + * This strategy is proposed in [1] and a small value, such as mu = 0.001, is suggested. + * [1] A.P. Engelbrecht and L.N.H. van Loggerenberg. + * Enhancing the nichepso. + * In IEEE Congress on Evolutionary Computation, + * 2007. + */ +public class ScatterMergingStrategy extends StandardMergingStrategy{ + + public ScatterMergingStrategy() { + super(); + } + + public ScatterMergingStrategy(double theMu) { + super(theMu); + } + + public String globalInfo(){ + return "Strategy to merge subswarms"; + } + +/********************************************************************************************************************** + * mergeSubswarms + */ + + /** @tested + * if both active: reinitializes subswarm j back into the main swarm and deletes it from the subswarms. + * if both inactive: adds population of subswarm j to population of subswarm i, then deletes subswarm j. + * @param i + * @param j + */ + public void mergeSubswarms( + int i, + int j, + Vector subSwarms, + ParticleSubSwarmOptimization mainSwarm) + { + ParticleSubSwarmOptimization borg= subSwarms.get(i); + ParticleSubSwarmOptimization others= subSwarms.get(j); + + if (borg.isActive() && others.isActive()){ + mergeActiveSubswarms(i,j,subSwarms,mainSwarm); + return; + } + if (!borg.isActive() && !others.isActive()){ + mergeInactiveSubswarms(i,j,subSwarms,mainSwarm); + return; + } + System.out.print("ScatterMergingStrategy.mergeSubswarms problem: subswarms not of equal state."); + } + + private void mergeInactiveSubswarms( + int i, + int j, + Vector subSwarms, + ParticleSubSwarmOptimization mainSwarm) { + ParticleSubSwarmOptimization borg = subSwarms.get(i); + ParticleSubSwarmOptimization others= subSwarms.get(j); + + borg.addPopulation(others); + borg.populationSizeHasChanged(); + + subSwarms.remove(j); + } + + /** @tested + * subswarm j is reinited into the mainswarm and deleted, the function calls are added to the main swarm + * @param i + * @param j + * @param subSwarms + * @param mainSwarm + */ + private void mergeActiveSubswarms( + int i, + int j, + Vector subSwarms, + ParticleSubSwarmOptimization mainSwarm) { + mainSwarm.reinitIndividuals(subSwarms.get(j).getPopulation().size()); // add to the mainswarm + //mainSwarm.populationSizeHasChanged(); // already called in addNewParticlesToPopulation + // transfer functioncalls from the subswarm to the mainswarm before deleting it: + int calls = subSwarms.get(j).getPopulation().getFunctionCalls(); + mainSwarm.getPopulation().incrFunctionCallsBy(calls); + subSwarms.remove(j); + } +} diff --git a/src/eva2/server/go/operators/nichepso/merging/StandardMergingStrategy.java b/src/eva2/server/go/operators/nichepso/merging/StandardMergingStrategy.java new file mode 100644 index 00000000..12247929 --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/merging/StandardMergingStrategy.java @@ -0,0 +1,146 @@ +package eva2.server.go.operators.nichepso.merging; + +import java.util.Vector; + +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.individuals.InterfaceESIndividual; +import eva2.server.go.operators.distancemetric.EuclideanMetric; +import eva2.server.go.operators.distancemetric.PhenotypeMetric; +import eva2.server.go.strategies.ParticleSubSwarmOptimization; + +/** + * Two subswarms are merged if their radii overlap. + * In case both radii equal zero the subswarms are merged if their distance is below a given threshold mu. + * This strategy is proposed in [1] and a small value, such as mu = 0.001, is suggested. + * [1] R. Brits, A. P. Engelbrecht and B. Bergh. + * A Niching Particle Swarm Optimizer + * In Proceedings of the 4th Asia-Pacific Conference on Simulated Evolution and Learning (SEAL'02), + * 2002, 2, 692-696 + */ +public class StandardMergingStrategy implements InterfaceMergingStrategy, java.io.Serializable { + + private double mu = 0.001; // "experimentally found to be effective" according to "a niching particle swarm optimizer" by Brits et al. + + public String globalInfo(){ + return "Strategy to merge subswarms"; + } + +/********************************************************************************************************************** + * ctors + */ + public StandardMergingStrategy(){ + + } + + public StandardMergingStrategy(double theMu){ + mu = theMu; + } + + public StandardMergingStrategy(StandardMergingStrategy other){ + this.mu = other.mu; + } + + public Object clone(){ + return (Object) new StandardMergingStrategy(this); + } + +/********************************************************************************************************************** + * shouldMergeSubswarms + */ + /** @tested + * the subswarms are merged, if they overlap (or are very close) and if they are of equal state + * (non-Javadoc) @see javaeva.server.oa.go.Operators.NichePSO.InterfaceMergingStrategie#shouldMergeSubswarms(javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization, javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization) + */ + public boolean shouldMergeSubswarms(ParticleSubSwarmOptimization subswarm1, ParticleSubSwarmOptimization subswarm2) { + // check for equal state + if (subswarm1.isActive() && !subswarm2.isActive()) return false; + if (!subswarm1.isActive() && subswarm2.isActive()) return false; + + if (!subswarmsOverlapOrAreVeryClose(subswarm1,subswarm2)){ + return false; + } + + + return true; + } + + private boolean subswarmsOverlapOrAreVeryClose(ParticleSubSwarmOptimization subswarm1,ParticleSubSwarmOptimization subswarm2) { + // check if they overlap + AbstractEAIndividual gbesti = subswarm1.getGBestIndividual(); + AbstractEAIndividual gbestj = subswarm2.getGBestIndividual(); + InterfaceESIndividual i1=null, i2=null; + + double dist; + if (gbesti instanceof InterfaceESIndividual) { + i1=(InterfaceESIndividual)gbesti; + i2=(InterfaceESIndividual)gbestj; + } + + if (i1 != null) dist = EuclideanMetric.euclideanDistance(i1.getDGenotype(), i2.getDGenotype()); + else dist = subswarm1.distance(gbesti, gbestj); // euclidean distance +// System.out.println("dist is " + dist); + + if (dist < (subswarm1.getMaxAllowedSwarmRadiusAbs() + subswarm2.getMaxAllowedSwarmRadiusAbs())) { + // only then is the next (expensive) test feasible + double Ri = subswarm1.getBoundSwarmRadius(); // uses euclidean distance + double Rj = subswarm2.getBoundSwarmRadius(); // uses euclidean distance + + if (dist < Ri+Rj ){ // all in euclidean metric + return true; + } + } + + // check if they are "very close" + double dist_norm; + if (i1 != null) { + dist_norm = EuclideanMetric.normedEuclideanDistance(i1.getDGenotype(), i1.getDoubleRange(), + i2.getDGenotype(), i2.getDoubleRange()); + } else dist_norm = PhenotypeMetric.dist(gbesti, gbestj); // normalised distance + + //if (Ri == 0 && Rj == 0 && dist_norm < getEpsilon()){ // see "Enhancing the NichePSO" paper + if (dist_norm < getMu()){ // Ri und Rj auf null testen sinvoll ? + return true; + } + return false; + } + +/********************************************************************************************************************** + * mergeSubswarms + */ + + /** @tested junit + * adds population of subswarm j to population of subswarm i, then deletes subswarm j. + * @param i + * @param j + */ + public void mergeSubswarms( + int i, + int j, + Vector subSwarms, + ParticleSubSwarmOptimization mainSwarm) + { + ParticleSubSwarmOptimization borg = subSwarms.get(i); + ParticleSubSwarmOptimization others= subSwarms.get(j); +// System.out.println("merging " + (borg.isActive() ? " active " : " inactive ") + " with " + (others.isActive() ? "active" : "inactive")); + borg.addPopulation(others); + borg.populationSizeHasChanged(); + + subSwarms.remove(j); // ok: function calls added to borg swarm... + } + +/********************************************************************************************************************** + * getter, setter + */ + + public void setMu(double mu) { + this.mu = mu; + } + + public double getMu() { + return mu; + } + + public String muTipText(){ + return "threshold used to merge subswarms that lie very close but have no spatial extent"; + } +} diff --git a/src/eva2/server/go/operators/nichepso/subswarmcreation/DummySubswarmCreationStrategy.java b/src/eva2/server/go/operators/nichepso/subswarmcreation/DummySubswarmCreationStrategy.java new file mode 100644 index 00000000..55e6f71d --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/subswarmcreation/DummySubswarmCreationStrategy.java @@ -0,0 +1,24 @@ +package eva2.server.go.operators.nichepso.subswarmcreation; + +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.strategies.ParticleSubSwarmOptimization; + +public class DummySubswarmCreationStrategy implements InterfaceSubswarmCreationStrategy { + + public Object clone(){ + return (Object) new DummySubswarmCreationStrategy(); + } + + public void createSubswarm(ParticleSubSwarmOptimization preparedSubswarm, + AbstractEAIndividual indy, ParticleSubSwarmOptimization mainSwarm) { + // TODO Auto-generated method stub + + } + + public boolean shouldCreateSubswarm(AbstractEAIndividual indy, + ParticleSubSwarmOptimization mainswarm) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/src/eva2/server/go/operators/nichepso/subswarmcreation/GenerateNeighborSubswarmCreationStrategy.java b/src/eva2/server/go/operators/nichepso/subswarmcreation/GenerateNeighborSubswarmCreationStrategy.java new file mode 100644 index 00000000..f9247521 --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/subswarmcreation/GenerateNeighborSubswarmCreationStrategy.java @@ -0,0 +1,97 @@ +package eva2.server.go.operators.nichepso.subswarmcreation; + +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.individuals.ESIndividualDoubleData; +import eva2.server.go.operators.mutation.MutateESFixedStepSize; +import eva2.server.go.populations.Population; +import eva2.server.go.strategies.ParticleSubSwarmOptimization; + +/** + * The standard deviation in the fitness of each main swarm particle over the last 3 iterations is calculated. + * If this standard deviation falls below a given threshold delta it is assumed that the particle is converging + * on an optimum and a subswarm is created with that particle and a generated neighbor. + * This neighbor is generated by mutating the converged particle using the mutation step size mu. + * delta = 0.0001 and mu = 0.1 could experimentally produce acceptable results + * but further effort to obtain appropriate values for mu may significantly improve the performance of this strategy. + */ +public class GenerateNeighborSubswarmCreationStrategy extends + StandardSubswarmCreationStrategy { + + private double mu = 0.1; + +/********************************************************************************************************************** + * shouldCreateSubswarm + */ + + // same as in StandardSubswarmCreationStrategy + +/********************************************************************************************************************** + * createSubswarm + */ + + /** @tested + * creates a subswarm from the given particle and its neighbor in the mainswarm. + * If the neighbors pbest is better than the particles pbest, a new neighbor is generated. + * (non-Javadoc) @see javaeva.server.oa.go.Operators.NichePSO.StandardSubswarmCreationStrategy#createSubswarm(javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization, javaeva.server.oa.go.EAIndividuals.AbstractEAIndividual, javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization) + */ + public void createSubswarm(ParticleSubSwarmOptimization preparedSubswarm, AbstractEAIndividual indy, ParticleSubSwarmOptimization mainSwarm) { + // get the neighbor in the mainswarm + AbstractEAIndividual neighbor = mainSwarm.getMemberNeighbor(indy); + AbstractEAIndividual worst; + // check if neighbor would "pull the indy away from its niche" because it has a better pbest + AbstractEAIndividual indypbest = (AbstractEAIndividual)indy.getData("PersonalBestKey"); + AbstractEAIndividual neighpbest = (AbstractEAIndividual)neighbor.getData("PersonalBestKey"); + + if (true){//neighpbest.isDominating(indypbest)) { + neighbor = generateNeighborFrom(indy,mainSwarm); // neighbor wouldnt help with indies niche + worst = mainSwarm.getParticleWithWorstPBestButNot(indy); // delete another particle for the gnerated neighbor + }else{ + worst = neighbor; // use the neighbor particle and delete it from the mainswarm + } + + Population pop = new Population(2); + pop.add(indy); + pop.add(neighbor); + preparedSubswarm.setPopulation(pop); + preparedSubswarm.populationSizeHasChanged(); + + // remove particles from the main swarm: + mainSwarm.removeSubIndividual(indy); + mainSwarm.removeSubIndividual(worst); + mainSwarm.populationSizeHasChanged(); + } + + private AbstractEAIndividual generateNeighborFrom(AbstractEAIndividual indy, ParticleSubSwarmOptimization mainswarm) { + // generate a neighbor + ESIndividualDoubleData neighbor = (ESIndividualDoubleData)indy.clone(); + MutateESFixedStepSize mutator = new MutateESFixedStepSize(); + mutator.setSigma(getMu()); + neighbor.setMutationOperator(mutator); + neighbor.setMutationProbability(1); + neighbor.mutate(); + //TODO more stuff: stddev ... from indy + //TODO mutate velocity? evaluate? + neighbor.putData("BestFitness", neighbor.getFitness()); + neighbor.putData("BestPosition", neighbor.getDGenotype()); + return neighbor; + } + +/********************************************************************************************************************** + * getter, setter + */ + + public void setMu( + double generateNeighborWithMutationStep) { + this.mu = generateNeighborWithMutationStep; + } + + public double getMu() { + return mu; + } + + public String muTipText(){ + return "mutation step size used to generate a neighbor"; + } + + +} diff --git a/src/eva2/server/go/operators/nichepso/subswarmcreation/InterfaceSubswarmCreationStrategy.java b/src/eva2/server/go/operators/nichepso/subswarmcreation/InterfaceSubswarmCreationStrategy.java new file mode 100644 index 00000000..dadf3763 --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/subswarmcreation/InterfaceSubswarmCreationStrategy.java @@ -0,0 +1,35 @@ +package eva2.server.go.operators.nichepso.subswarmcreation; + +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.strategies.ParticleSubSwarmOptimization; + +/** + * interface for the subswarm creation strategies used in NichePSO + */ +public interface InterfaceSubswarmCreationStrategy { + + /** @tested + * decides whether a subswarm should be created for the given indy and mainswarm according to the creation strategie + * @param indy + * @param mainswarm + * @return + */ + public abstract boolean shouldCreateSubswarm( + AbstractEAIndividual indy, + ParticleSubSwarmOptimization mainswarm); + + /** @tested + * creates a subswarm from indy, the details depend on the concrete strategy. + * @param preparedSubswarm a subswarm which is appropriatly prepared + * (ie its problem, optimization strategy etc. are set correctly from the "meta-optimizer") + * Afterwards the subswarm containes the generated particles + * @param indy a particle from which a subswarm should be created + * @param mainSwarm the main swarm which contains indy + */ + public abstract void createSubswarm( + ParticleSubSwarmOptimization preparedSubswarm, + AbstractEAIndividual indy, + ParticleSubSwarmOptimization mainSwarm); + + public abstract Object clone(); +} diff --git a/src/eva2/server/go/operators/nichepso/subswarmcreation/StandardSubswarmCreationStrategy.java b/src/eva2/server/go/operators/nichepso/subswarmcreation/StandardSubswarmCreationStrategy.java new file mode 100644 index 00000000..048b18c7 --- /dev/null +++ b/src/eva2/server/go/operators/nichepso/subswarmcreation/StandardSubswarmCreationStrategy.java @@ -0,0 +1,119 @@ +package eva2.server.go.operators.nichepso.subswarmcreation; + +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.populations.Population; +import eva2.server.go.strategies.NichePSO; +import eva2.server.go.strategies.ParticleSubSwarmOptimization; + +/** + * The standard deviation in the fitness of each main swarm particle over the last 3 iterations is calculated. + * If this standard deviation falls below a given threshold delta it is assumed + * that the particle is converging on an optimum and a subswarm is created with that particle and its topological neighbor. + * The strategy is proposed in [1] suggesting a value of delta = 0.0001. + * [1] R. Brits, A. P. Engelbrecht and B. Bergh. + * A Niching Particle Swarm Optimizer + * In Proceedings of the 4th Asia-Pacific Conference on Simulated Evolution and Learning (SEAL'02), + * 2002, 2, 692-696 + */ +public class StandardSubswarmCreationStrategy implements InterfaceSubswarmCreationStrategy, java.io.Serializable { + + protected double delta = 0.0001; // "experimentally found to be effective" according to "a niching particle swarm optimizer" by Brits et al. + + public StandardSubswarmCreationStrategy(double theDelta) { + delta = theDelta; + } + + public StandardSubswarmCreationStrategy() { + delta = 0.0001; + } + + public Object clone(){ + return (Object) new StandardSubswarmCreationStrategy(delta); + } + + public String globalInfo(){ + return "Strategy to create subswarms from the main swarm"; + } + +/********************************************************************************************************************** + * shouldCreateSubswarm + */ + /** @tested junit + * true if the stddev of the particles fitness < delta and no constraints are violated + * @param indy main swarm particle + * @return + */ + public boolean shouldCreateSubswarm(AbstractEAIndividual indy, ParticleSubSwarmOptimization mainswarm) { + if (createSubswarmConstraintViolation(indy, mainswarm)){ + return false; + } + + // check for stddev < delta condition + double stddev = (((Double)indy.getData(NichePSO.stdDevKey))).doubleValue(); + if (stddev >= getDelta()){ + return false; + } + + return true; + } + + /** @tested junit + * true, if reasons exist why no subswarm should be created from indy. + * Reasons like: + * poor fitness (not implemented), + * convergence on plateau (not implemented), + * indy is the only particle in the mainswarm and therefor has no neighbor + * @param indy main swarm particle + * @return + */ + public boolean createSubswarmConstraintViolation(AbstractEAIndividual indy, ParticleSubSwarmOptimization mainswarm){ + boolean result = false; + + // check for MainSwarm-Size + if (mainswarm.getPopulation().size() < 2){ + //if (verbose) System.out.print("createSubswarmConstraintViolation: MainSwarm too small, no subswarm can be created\n"); + result = true; + } + + return result; + } + +/********************************************************************************************************************** + * createSubswarm + */ + + /** @tested + * creates a subswarm from the given particle and its neighbor in the mainswarm, + * then deletes the two particles from the mainswarm. + * (non-Javadoc) @see javaeva.server.oa.go.Operators.NichePSO.InterfaceSubswarmCreationStrategy#createSubswarm(javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization, javaeva.server.oa.go.EAIndividuals.AbstractEAIndividual, javaeva.server.oa.go.Strategies.ParticleSubSwarmOptimization) + */ + public void createSubswarm(ParticleSubSwarmOptimization preparedSubswarm, AbstractEAIndividual indy, ParticleSubSwarmOptimization mainSwarm) { + + // get the neighbor to create the subswarm + AbstractEAIndividual neighbor = mainSwarm.getMemberNeighbor(indy); + + Population pop = new Population(2); + pop.add(indy); + pop.add(neighbor); + preparedSubswarm.setPopulation(pop); + preparedSubswarm.populationSizeHasChanged(); + + // remove particles from the main swarm: + mainSwarm.removeSubIndividual(indy); + mainSwarm.removeSubIndividual(neighbor); + mainSwarm.populationSizeHasChanged(); + } + + public double getDelta() { + return delta; + } + + public void setDelta(double delta) { + this.delta = delta; + } + + public String deltaTipText(){ + return "threshold used to identify converging particles which lead to the creation of subswarms"; + } + +} diff --git a/src/eva2/server/go/strategies/ANPSO.java b/src/eva2/server/go/strategies/ANPSO.java new file mode 100644 index 00000000..a19c9b9b --- /dev/null +++ b/src/eva2/server/go/strategies/ANPSO.java @@ -0,0 +1,1092 @@ +package eva2.server.go.strategies; + +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.Vector; + +import eva2.OptimizerFactory; +import eva2.gui.GenericObjectEditor; +import eva2.server.go.InterfaceTerminator; +import eva2.server.go.PopulationInterface; +import eva2.server.go.enums.PSOTopologyEnum; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.individuals.InterfaceDataTypeDouble; +import eva2.server.go.operators.nichepso.deactivation.StandardDeactivationStrategy; +import eva2.server.go.operators.paramcontrol.LinearParamAdaption; +import eva2.server.go.operators.paramcontrol.ParamAdaption; +import eva2.server.go.operators.terminators.EvaluationTerminator; +import eva2.server.go.populations.Population; +import eva2.server.go.problems.AbstractOptimizationProblem; +import eva2.server.go.problems.Interface2DBorderProblem; +import eva2.server.go.problems.InterfaceAdditionalPopulationInformer; +import eva2.server.modules.GOParameters; +import eva2.tools.ToolBox; +import eva2.tools.chart2d.DPoint; +import eva2.tools.chart2d.DPointSet; + +/** + * The Adaptive Niching PSO(ANPSO)[1] extends the particle swarm optimizer (PSO) + * by Kennedy and Eberhart to locate multiple optima of a multimodal objective function. + * The Algorithm uses similar concepts as the NichePSO such as a main swarm to explore + * the search space and subswarms to refine and represent single niches. + * The implemented version uses the "inertness weight" PSO to train the main swarm. + * mainSwarmInertness sets the inertia weight omega and weights the particles tendency to follow its former movement. + * This controls exploration (favored by larger values) against exploitation (favored by smaller values). + * mainSwarmPhi1 sets Phi1 and weights the cognitive component. + * The term corresponds to the particles tendency to return to its personal best position. + * mainSwarmPhi2 sets Phi2 and weights the social component. + * The term corresonds to the particles tendency to be attracted towards its neighborhood best position. + * A small value for mainSwarmPhi2 reduces the influence of the neighborhood and each particle tend to + * perfom a local search on its own. This results in a high exploration ability of the main swarm and + * potentially leads to a good amount of identified optima. + * Larger values for mainSwarmPhi2 on the other hand might help to concentrate on fewer optima with superior fitness values. + * + * To avoid further parameters and the need to specify adequate values, which are often difficult to decide, + * the following adaption mechanism is employed: + * ANPSO adaptively determines a threshold parameter r during every generation by computing the average + * distance a particle has to its neighbor. Subsequently, a so called s-matrix is calculated that keeps + * track of how long any two particles are close (i.e. within r) to each other. + * The s-matrix is used to build a niche graph that represents particles as vertices and connects all particles + * that have been close to each other for at least two consecutive generations. + * Particles that are connected in the niche graph form a subswarm. + * The implemented version uses a strategy to deactivate subswarms when all containing particles converged on a solution. + * Furthermore, different neighborhood topologies can be choosen for the main swarm. + * In case the Multi-Swarm topology is used, the species radius is adaptively determined as well. + * + * [1] S. Bird and X. Li: + * Adaptively choosing niching parameters in a PSO. + * In: GECCO '06: Proceedings of the 8th annual conference on Genetic and evolutionary computation, + * Seiten 3--10, New York, NY, USA, 2006. ACM + * + * @author aschoff, mkron + */ +public class ANPSO extends NichePSO implements InterfaceOptimizer, InterfaceAdditionalPopulationInformer, java.io.Serializable { + + +/********************************************************************************************************************** + * members + */ + // for ANPSO it is necessary to keep an own archiv of inactive subswarms, because the standard set of + // subswarms is completely renewed every iteration. + public Vector inactiveSubSwarms = new Vector(); + + // the s matrix keeps track of how long particles are close to each other + int[][] s = new int[mainSwarmSize][mainSwarmSize]; + + // the niche graph represents particles as vertices and connects all particles that + // have been close to each other for at least two consecutive generations + protected NicheGraph nicheGraph = new NicheGraph(); + + // defines the minimal distance for neighboring particles at which they form a subswarm + // (this is proposed by Bird and Lee for further investigation) + protected double minimalR = 0; + private double updateRadius = 0.; + // maximum subswarm size + private int maxInitialSubSwarmSize = 0; + + private int maxNeighborCntNicheGraph = 4; // maximum for neighborhood matrix + private int minNeighborCntNicheGraph = 0; // minimum for neighborhood matrix + private int neighborCntNicheGraphForEdge = 2; // number of steps req. to build an edge + +/********************************************************************************************************************** + * ctors, clone + */ + public ANPSO() { +// NichePSO.stdNPSO(anpso, problem, randSeed, evalCnt); +// NichePSO.stdNPSO((ANPSO)this, (AbstractOptimizationProblem)this.m_Problem, 0, 1000); + + /////////// from NichePSO +// super.initMainSwarm(); // not really necessary if init is called before optimization but this way init doesnt change the parameters of a newly constructed object +// super.initSubswarmOptimizerTemplate(); +// setMergingStrategy(new StandardMergingStrategy(0.001)); +// setAbsorptionStrategy(new StandardAbsorptionStrategy()); +// setSubswarmCreationStrategy(new StandardSubswarmCreationStrategy(0.0001)); +// +// setMaxAllowedSwarmRadius(0.0001); // formally limits the swarm radius of the subswarms + + // Parameter for the mainswarm +// npso.getMainSwarm().setSpeedLimit(avgRange/2.); +// npso.getMainSwarm().setCheckSpeedLimit(true); + + // parameter for the subswarms +// System.out.println(BeanInspector.niceToString(getSubswarmOptimizerTemplate())); +// getSubswarmOptimizerTemplate().setGcpso(true); +// getSubswarmOptimizerTemplate().setRho(0.1); // on 2D Problems empirically better than default value 1 +// getSubswarmOptimizerTemplate().setAlgoType(new SelectedTag("Constriction")); +// getSubswarmOptimizerTemplate().setConstriction(2.05, 2.05); +// System.out.println(BeanInspector.niceToString(getSubswarmOptimizerTemplate())); + + ///////////end from NichePSO + getMainSwarm().setPhi1(2.05); + getMainSwarm().setPhi2(2.05); + getMainSwarm().setInertnessOrChi(0.7298437881283576); +// setMainSwarmInertness(new NoParameterAging(0.7298437881283576)); + setMainSwarmAlgoType(getMainSwarm().getAlgoType().setSelectedTag("Constriction")); // constriction + setMaxInitialSubSwarmSize(0); // deactivate early reinits + setMainSwarmTopology(PSOTopologyEnum.grid); + setMainSwarmTopologyRange(1); + setDeactivationStrategy(new StandardDeactivationStrategy(0.000001, 8)); + setMainSwarmSize(100); + } + + /*public ANPSO(){ + // Parameter for the mainswarm +// //Earlier standard settings: +// this.setMainSwarmAlgoType(getMainSwarm().getAlgoType().setSelectedTag("Inertness")); +// this.mainSwarmPhi1 = 1.2; +// this.mainSwarmPhi2 = 0.6; // ANPSO uses communication in the main swarm +// this.mainSwarmTopology = PSOTopologyEnum.multiSwarm; //"Multi-Swarm" favors the formation of groups in the main swarm +// this.mainSwarmTopologyRange = 2; // range for topologies like random, grid etc. (does not affect "Multi-Swarm") +// this.setMainSwarmInertness(new NoParameterAging(0.73)); + this.setMainSwarmPhi1(2.05); + this.setMainSwarmPhi2(2.05); + this.setMainSwarmInertness(new NoParameterAging(0.7298437881283576)); + this.setMainSwarmAlgoType(getMainSwarm().getAlgoType().setSelectedTag("Constriction")); // constriction + this.setMaxInitialSubSwarmSize(0); // deactivate early reinits + this.setMainSwarmTopology(PSOTopologyEnum.grid); + this.setMainSwarmTopologyRange(1); + this.setDeactivationStrategy(new StandardDeactivationStrategy(0.000001, 8)); + + hideHideable(); + initMainSwarm(); + }*/ + + public ANPSO(int mainSwarmSize, double phi1, double phi2, PSOTopologyEnum mainSwarmTopo, int mainSwarmTopoRange, int maxInitialSubSwarmSize) { + this(); + setMainSwarmSize(mainSwarmSize); + getMainSwarm().setPhi1(phi1); + getMainSwarm().setPhi2(phi2); +// setMainSwarmPhi1(phi1); +// setMainSwarmPhi2(phi2); + setMainSwarmTopologyRange(mainSwarmTopoRange); + setMainSwarmTopology(mainSwarmTopo); + setMaxInitialSubSwarmSize(maxInitialSubSwarmSize); + } + + /** + * Take care that all properties which may be hidden (and currently are) send a "hide" message to the Java Bean properties. + * This is called by PropertySheetPanel in use with the GenericObjectEditor. + */ + public void hideHideable() { + // hide the following unused properties from the GUI + GenericObjectEditor.setHideProperty(getClass(), "subswarmCreationStrategy", true); + GenericObjectEditor.setHideProperty(getClass(), "mergingStrategy", true); + GenericObjectEditor.setHideProperty(getClass(), "absorptionStrategy", true); + GenericObjectEditor.setHideProperty(getClass(), "maxAllowedSwarmRadius", true); + GenericObjectEditor.setHideProperty(getClass(), "mainSwarmTopologyRange", mainSwarmTopology == PSOTopologyEnum.multiSwarm); // "Multi-Swarm" has no topologyRange + + // population size is set via setMainSwarmSize + GenericObjectEditor.setHideProperty(getClass(), "population", true); +// setGOEShowProperties(getClass()); + } + + public ANPSO(ANPSO o){ + super(o); + this.inactiveSubSwarms = (Vector)o.inactiveSubSwarms.clone(); + this.s = new int[mainSwarmSize][mainSwarmSize]; + for (int i = 0; i < s.length; ++i){ + System.arraycopy(o.s[i], 0, s[i], 0, s[i].length); + } + + this.nicheGraph = (NicheGraph)nicheGraph.clone(); + this.minimalR = o.minimalR; + this.minNeighborCntNicheGraph = o.minNeighborCntNicheGraph; + this.maxNeighborCntNicheGraph = o.maxNeighborCntNicheGraph; + this.neighborCntNicheGraphForEdge = o.neighborCntNicheGraphForEdge; + } + + public Object clone(){ + return (Object) new ANPSO(this); + } + +/********************************************************************************************************************** + * inits + */ + public void init() { // MOE: wird vor Optimierung / n�chstem multirun 1x aufgerufen + super.init(); + initMainSwarm(); + initSTo(0); + initNicheGraph(); + + inactiveSubSwarms = new Vector(); // dont want to use subswarms from old optimization run (especially not in multiruns)... + } + + /** + * resets all entries of the s matrix that correspond to any + * particle in the given subswarm + * @param subswarm + */ + private void resetSMatrixEntriesFor(ParticleSubSwarmOptimization subswarm) { + Population pop = subswarm.getPopulation(); + for (int i = 0; i < pop.size(); ++i){ + //Integer index = pop.getEAIndividual(i).getIndividualIndex();(Integer)pop.getEAIndividual(i).getData("particleIndex"); + resetSMatrixForIndex(pop.getEAIndividual(i).getIndividualIndex(),0); + } + } + + /** + * sets the given row and column to the given value + * (i.e. all entries corresponding to a specific particle) + * @param index + * @param val + */ + private void resetSMatrixForIndex(int index, int val) { + for (int i = 0 ; i < s.length; ++i){ + for (int j = 0; j < s[i].length; ++j){ + if (i == index || j == index){ + s[i][j] = val; + } + } + } + } + + /** + * sets every entry of the s matrix to the given value + * @param val + */ + private void initSTo(int val) { + for (int i = 0 ; i < s.length; ++i){ + for (int j = 0; j < s[i].length; ++j){ + s[i][j] = val; + } + } + } + + /** + * this inits the "niche graph". + * Every particle is represented as a vertex in the "niche graph". + */ + private void initNicheGraph(){ + nicheGraph = new NicheGraph(); + Population activePop = getActivePopulation(); + for (int i = 0; i < activePop.size(); ++i){ + //Integer index = activePop.getEAIndividual(i).getParticleIndex();//(Integer)activePop.getEAIndividual(i).getData("particleIndex"); + String vertex = ""+activePop.getEAIndividual(i).getIndividualIndex(); + nicheGraph.addVertex(vertex); + } + } + +/********************************************************************************************************************** + * ANPSO core + +// /** +// * @param pop +// * @param normalized use a normalized metric to compute distances? +// * @return ave distance to neighbor in the given population +// */ +// public double getAveDistToClosestNeighbor(Population pop, boolean normalized){ +// PhenotypeMetric metric = new PhenotypeMetric(); +//// ArrayList distances = new ArrayList(pop.size()); +// double sum = 0; +// double d=0; +// for (int i = 0; i < pop.size(); ++i){ +// AbstractEAIndividual neighbor, indy = pop.getEAIndividual(i); +// int neighborIndex = pop.getNeighborIndex(indy); +// if (neighborIndex >= 0) neighbor = pop.getEAIndividual(neighborIndex); +// else return -1; +// if (normalized){ +// d = metric.distance(indy, neighbor); +// } else { +// d = PhenotypeMetric.euclidianDistance(AbstractEAIndividual.getDoublePosition(indy), +// AbstractEAIndividual.getDoublePosition(neighbor)); +// } +//// distances.add(d); +// sum += d; +// } +// double avg = sum/(double)pop.size(); +//// if (normalized && (pop.getGeneration()==1)) { +//// double var = 0; +//// for (int i=0; imaxNeighborCntNicheGraph) s[i][j]=maxNeighborCntNicheGraph; + + // if i and j had been close to each other for at least two generations + // they are connected by an edge + if (s[i][j] >= neighborCntNicheGraphForEdge){ + String pi = ""+i; + String pj = ""+j; + nicheGraph.addEdge(pi, pj); + } + }else{ + // decrement entry that counts the number of generations + // i and j have been close to each other + --s[i][j]; + if (s[i][j] < minNeighborCntNicheGraph) s[i][j] = minNeighborCntNicheGraph; + } + } + } + } + + /** + * The returned array may contain null entries (for indies scheduled for reinitialization). + * @param pop + * @return an array of references sorted according to the particle indices + * (i.e. returnedArray[i] = individual with individualIndex i) + */ + protected AbstractEAIndividual[] sortActivePopByParticleIndex() { + Population pop = getActivePopulation(); + AbstractEAIndividual[] sorted; + if (pop.size() setOfSubswarms){ + Vector newSubSwarms = new Vector(); + + for (int i = 0; i < setOfSubswarms.size(); ++i){ + Population pop = setOfSubswarms.get(i); + ParticleSubSwarmOptimization subswarm = getNewSubSwarmOptimizer(); + subswarm.getPopulation().clear(); + subswarm.getPopulation().addAll(pop); + subswarm.populationSizeHasChanged(); + newSubSwarms.add(subswarm); + getMainSwarm().removeSubPopulation(pop, true); // the new subswarm can also come from an earlier subswarm + getMainSwarm().populationSizeHasChanged(); + } + if (isVerbose()) { + System.out.println(); + for (int i=0; i do not count them in getPopulation a second time + int calls = 0; + for (int i = 0; i < getSubSwarms().size(); ++i){ + ParticleSubSwarmOptimization subswarm = getSubSwarms().get(i); + calls += subswarm.getPopulation().getFunctionCalls(); + } + getMainSwarm().getPopulation().incrFunctionCallsBy(calls); + + this.SetSubSwarms(newSubSwarms); + } + + /** + * uses the population as the mainswarm + * @param pop + */ + public void useAsMainSwarm(Population pop){ + int generations = getMainSwarm().getPopulation().getGeneration(); + int calls = getMainSwarm().getPopulation().getFunctionCalls(); + getMainSwarm().setPopulation(pop); + getMainSwarm().populationSizeHasChanged(); + getMainSwarm().getPopulation().setGenerationTo(generations); + getMainSwarm().getPopulation().SetFunctionCalls(calls); + } + + /** + * creates subswarms from all particles that correspond to connected vertices in the niche graph. + * Particles corresponding to unconnected vertices belong to the mainswarm. + */ + public void createSubswarmsFromNicheGraph(){ + // get all sets of vertices that are connected in the niche graph... + //(subSwarms = new Vector(); // too early, particles would be lost... + List> connectedComps = nicheGraph.getConnectedComponents(); + + Population tmpPop = new Population(), newMainPop = new Population(); + Vector setOfSubswarms = new Vector(); + boolean reinitSuperfl = true; + boolean TRACEMTHD = false; + + // ... and use the corresponding particles to create the subswarms + if (TRACEMTHD) System.out.println("---------"); + for (Set connSet : connectedComps){ + if (connSet.size() > 1){// create niche + Population pop = new Population(connSet.size()); + for (String indexStr : connSet){ + Integer index = Integer.valueOf(indexStr); + AbstractEAIndividual indy = getIndyByParticleIndex(index.intValue()); // may be taken from a main swarm or current subwarm + if (indy == null){ + System.err.println("createNichesFromNicheGraph problem -> getIndyByParticleIndex returned null"); + } + pop.add(indy); + } + if (TRACEMTHD) System.out.print(" subswarm size ssize " + pop.size()); + if (maxInitialSubSwarmSize > 0 && (pop.size() > maxInitialSubSwarmSize)) { + if (TRACEMTHD) System.out.print(" removing " + (pop.size()-maxInitialSubSwarmSize)); + tmpPop = pop.getWorstNIndividuals(pop.size()-maxInitialSubSwarmSize, -1); + tmpPop.synchSize(); +// Population testPop=(Population)pop.clone(); + pop.removeMembers(tmpPop, true); + if (reinitSuperfl) { + for (int i=0; i it = connSet.iterator(); + Integer index = Integer.valueOf(it.next()); + AbstractEAIndividual indy = getIndyByParticleIndex(index.intValue()); + newMainPop.add(indy); + } + } +// for (int i=0; i 1)) { //Multi-Swarm + double aveDistToNeighInMain = getMainSwarm().getPopulation().getAvgDistToClosestNeighbor(true, false)[0]; + getMainSwarm().setSubSwarmRadius(aveDistToNeighInMain); + } + + if (isVerbose()) { + System.out.println(); + } + firePropertyChangedEvent("NextGenerationPerformed"); // calls Listener that sth changed... + + /** plotting **********************************************************************************/ + if (isPlot()){ + doPlot(); + } +// System.out.println(); + /** end plotting *******************************************************************************/ + + // reset flags etc for: + // deactivation + deactivationOccured = false; + deactivatedSwarm = new Vector(); + //reinitedSwarm = new Vector(); + // merging + mergingOccurd = false; + borg = new Vector(); + others = new Vector(); + borgbest = new Vector(); + othersbest = new Vector(); + // absorbtion + absorbtionOccurd = false; + indytoabsorb = new Vector(); + // subswarmcreation + creationOccurd = false; + indyconverged = new Vector(); + convergedneighbor = new Vector(); + //clearing - deprecated + //reinitoccurd = false; + + } + + +/********************************************************************************************************************** + * Deactivation + */ + + protected void deactivationEventFor(ParticleSubSwarmOptimization subswarm) { + super.deactivationEventFor(subswarm); + resetSMatrixEntriesFor(subswarm); + inactiveSubSwarms.add(subswarm); // ANPSO will later remove the inactive subswarm from the standard set of subswarms... + } + +/********************************************************************************************************************** + * setter, getter + */ + /** @tested ps + * sets the !initial! size of the mainswarm population + * use this instead of getPopulation.setPopulationSize() + * @param size + */ + public void setMainSwarmSize(int size){ + // set member + this.mainSwarmSize = size; + // pass on to the mainswarm optimizer + getMainSwarm().getPopulation().setTargetSize(size); + // update s + s = new int[size][size]; + initSTo(0); + initNicheGraph(); + } + + /** + * @param includeInactive + * @return a population with clones from all subswarms + */ + public Population getSubswarmMetapop(boolean includeInactive){ + // construct a metapop with clones from all subswarms + Population metapop = new Population(); + for (int i = 0; i < getSubSwarms().size(); ++i){ + ParticleSubSwarmOptimization currentsubswarm = getSubSwarms().get(i); + if (includeInactive || currentsubswarm.isActive()){ + Population currentsubswarmpop = (Population)currentsubswarm.getPopulation().clone(); + metapop.addPopulation(currentsubswarmpop); + } + } + return metapop; + } + + /** @tested junit + * returns a population consisting of copies from the mainswarm and all subswarms + * (active and inactive, so the size of this Population is not necessarily constant). + * Especially important for the call back regarding the output file... + * Beware: getPopulation().getPopulationSize() returns the !initial! size of the main swarm, + * the actual size of the complete population is accessed via getPopulation().size() + * @return a population consisting of copies from the mainswarm and all subswarms. + */ + public Population getPopulation() { + // construct a metapop with clones from the mainswarm and all subswarms + Population metapop = (Population)getMainSwarm().getPopulation().clone(); + Population currentsubswarm = new Population(); + for (int i = 0; i < getSubSwarms().size(); ++i){ + currentsubswarm = (Population)getSubSwarms().get(i).getPopulation().clone(); + metapop.addPopulation(currentsubswarm); + } + for (int i = 0; i < inactiveSubSwarms.size(); ++i){ // in the case of ANPSO + currentsubswarm = (Population)inactiveSubSwarms.get(i).getPopulation().clone(); + metapop.addPopulation(currentsubswarm); + } + // add the best pbest particle to the population +// if (metapop.size() != 0){ +// AbstractEAIndividual hero = (AbstractEAIndividual)metapop.getEAIndividual(0).getData("PersonalBestKey"); +// for (int i = 0; i < metapop.size(); ++i){ +// AbstractEAIndividual currentPBest = (AbstractEAIndividual)metapop.getEAIndividual(i).getData("PersonalBestKey"); +// if (currentPBest.isDominating(hero)){ +// hero = currentPBest; +// } +// } +// metapop.add(hero); +// } + + // set correct number of generations + metapop.setGenerationTo(getMainSwarm().getPopulation().getGeneration()); + + // set correct number of function calls + int calls = getMainSwarm().getPopulation().getFunctionCalls(); + for (int i = 0; i < getSubSwarms().size(); ++i){ + ParticleSubSwarmOptimization subswarm = getSubSwarms().get(i); + // if (subswarm.isActive()){ + calls += subswarm.getPopulation().getFunctionCalls(); + // } + } + // calls from inactivated subswarms were transfered to the mainswarm, see useAsSubSwarms method + + metapop.SetFunctionCalls(calls); + + return metapop; + } + + /** @tested junit + * returns the cloned global best individuals (ie best of all time) from every subswarm + * @return array with copies of the gbest individuals + */ + public Population getSubswarmRepresentatives(){ + //boolean includeMainSwarm = false; + int mainSize = 0; + //if (includeMainSwarm) mainSize = getMainSwarm().getPopulation().size(); + Population elitePop = new Population(getSubSwarms().size()+inactiveSubSwarms.size()+mainSize); +// if (includeMainSwarm){ +// for (int i = 0; i < mainSize; ++i){ +// elite[i] = getMainSwarm().getPopulation().getEAIndividual(i); +// } +// } + for (int i = 0; i < getSubSwarms().size(); ++i){ + AbstractEAIndividual bestSS = ((ParticleSubSwarmOptimization)getSubSwarms().get(i)).getBestIndividual(); + elitePop.addIndividual((AbstractEAIndividual)((ParticleSubSwarmOptimization)getSubSwarms().get(i)).m_BestIndividual.clone()); + } + for (int i = 0; i < inactiveSubSwarms.size(); ++i){ + elitePop.addIndividual((AbstractEAIndividual)((ParticleSubSwarmOptimization)inactiveSubSwarms.get(i)).m_BestIndividual.clone()); + } + return elitePop; + } + + /** @tested emp + * returns a string that lists the global best individuals (ie best of all time) from every subswarm + * @return descriptive string of the elite + */ + public String getSubswarmRepresentativesAsString(){ + String result = "\nSubswarmRepresentatives: \n"; + Population elite = getSubswarmRepresentatives(); + for (int i = 0; i < getSubSwarms().size()+inactiveSubSwarms.size(); ++i){ + result += elite.getEAIndividual(i).getStringRepresentation() + "\n"; + } + //result += "\n"; + return result; + } + + /** @tested + * plots all subswarms as connected lines to their respective best individual + */ + protected void plotSubSwarms() { + if (this.m_Problem instanceof Interface2DBorderProblem) { + //DPointSet popRep = new DPointSet(); + InterfaceDataTypeDouble tmpIndy1; + + //cleanPlotSubSwarms(); + + // for all inactive SubSwarms from ANPSO... + for (int i = 0; i < this.inactiveSubSwarms.size(); i++) { + ParticleSubSwarmOptimization currentsubswarm = this.inactiveSubSwarms.get(i); + InterfaceDataTypeDouble best = (InterfaceDataTypeDouble)currentsubswarm.m_BestIndividual; + plotCircleForIndy((AbstractEAIndividual)best,"[I]"); + } + + // for all SubSwarms... + for (int i = 0; i < this.getSubSwarms().size(); i++) { + ParticleSubSwarmOptimization currentsubswarm = this.getSubSwarms().get(i); + Population currentsubswarmpop = (Population)currentsubswarm.getPopulation(); + //InterfaceDataTypeDouble best = (InterfaceDataTypeDouble)currentsubswarmpop.getBestIndividual(); + InterfaceDataTypeDouble best = (InterfaceDataTypeDouble)currentsubswarm.m_BestIndividual; + DPointSet popRep = new DPointSet(); + + //...draw SubSwarm as points + for (int j = 0; j < currentsubswarmpop.size(); j++) { + popRep.setConnected(false); + tmpIndy1 = (InterfaceDataTypeDouble)currentsubswarmpop.get(j); + popRep.addDPoint(new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1])); + } + this.m_TopologySwarm.getFunctionArea().addDElement(popRep); // time consuming + + //...draw circle for best + if (!currentsubswarm.isActive()){ + plotCircleForIndy((AbstractEAIndividual)best,"[I]"); + }else{ + if (!getSubswarmOptimizerTemplate().isGcpso()){ + //plotCircleForIndy((AbstractEAIndividual)best,getMaxStdDevFromSwarmAsString(currentsubswarm)); + } + if (getSubswarmOptimizerTemplate().isGcpso()){ + String rhoAsString = String.format("%6.3f", currentsubswarm.getRho()); + //plotCircleForIndy((AbstractEAIndividual)best,rhoAsString); + if (currentsubswarm.gbestParticle != null){ + //plotCircleForIndy((AbstractEAIndividual)currentsubswarm.gbestParticle,"gbest"); + } + } + } + + //...draw SubSwarm as connected lines to best + popRep = new DPointSet(); + for (int j = 0; j < currentsubswarmpop.size(); j++) { + //popRep.setConnected(false); + tmpIndy1 = (InterfaceDataTypeDouble)currentsubswarmpop.get(j); + //popRep.addDPoint(new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1])); + + 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_TopologySwarm.getFunctionArea().addDElement(popRep); // time consuming + } + } // endif + } + + /** @tested + * method not used any more + * @param index + * @return inactive particles with given index + * (may return more than one particle for a given index because indizes are reused during deactivation + * and the reinitialized particle may be deactivated again...) + */ + public Vector getInactiveIndiesByParticleIndex(Integer index){ + Vector indies = null; + AbstractEAIndividual indy = null; + for (int i = 0; i < inactiveSubSwarms.size(); ++i){ + Population pop = inactiveSubSwarms.get(i).getPopulation(); + indy = getIndyByParticleIndexAndPopulation(pop, index); // fix if needed: only returns the first occurence... + if (indy != null){ + indies.add(indy); + } + } + return indies; + } + + /** @tested nn + * This method will return a naming String + * @return The name of the algorithm + */ + public String getName() { + return "ANPSO-"+getMainSwarmSize(); + } + +// +// public double getMinimalR() { +// return minimalR; +// } + + + public void SetMinimalR(double minimalR) { + this.minimalR = minimalR; + } + + public int getMaxInitialSubSwarmSize() { + return maxInitialSubSwarmSize; + } + public String maxInitialSubSwarmSizeTipText() { + return "The maximum size of sub swarms at creation time."; + } + public void setMaxInitialSubSwarmSize(int maxSubSwarmSize) { + this.maxInitialSubSwarmSize = maxSubSwarmSize; + } + +// public void setMainSwarmPhi2(double mainSwarmPhi2) { +// super.SetMainSwarmPhi2(mainSwarmPhi2); +// } +// public String mainSwarmPhi2TipText(){ +// return "weights the social component for the PSO used to train the main swarm"; +// } + +// /** This method allows you to choose the topology type. +// * @param s The type. +// */ +// public void setMainSwarmTopology(SelectedTag s) { +// mainSwarm.m_Topology = s; +// this.mainSwarmTopologyTag = s.getSelectedTagID(); +// GenericObjectEditor.setHideProperty(getClass(), "mainSwarmTopologyRange", mainSwarmTopologyTag == 3); // "Multi-Swarm" has no topologyRange +// } + + public String mainSwarmTopologyTipText(){ + return "sets the topology type used to train the main swarm"; + } + + public String mainSwarmTopologyRangeTipText(){ + return "sets the range of the neighborhood topology for the main swarm"; + } + + public static final GOParameters aNichePSO(AbstractOptimizationProblem problem, long randSeed, InterfaceTerminator term) { + ANPSO anpso = new ANPSO(); + anpso.setMainSwarmSize(75); + + return OptimizerFactory.makeParams(anpso, 75, problem, randSeed, term); + } + + /** + * Creates a standard ANPSO variant with default constricted PSO parameters and a grid topology. + * + * @param problem + * @param randSeed + * @param evalCnt + * @return + */ + public static final GOParameters stdANPSO(AbstractOptimizationProblem problem, long randSeed, int evalCnt) { + ANPSO anpso = new ANPSO(); + NichePSO.stdNPSO(anpso, problem, randSeed, evalCnt); + + anpso.getMainSwarm().setPhi1(2.05); + anpso.getMainSwarm().setPhi2(2.05); + anpso.getMainSwarm().setInertnessOrChi(0.7298437881283576); + anpso.setMainSwarmAlgoType(anpso.getMainSwarm().getAlgoType().setSelectedTag("Constriction")); // constriction + anpso.setMaxInitialSubSwarmSize(0); // deactivate early reinits + anpso.setMainSwarmTopology(PSOTopologyEnum.grid); + anpso.setMainSwarmTopologyRange(1); + anpso.setDeactivationStrategy(new StandardDeactivationStrategy(0.000001, 8)); + +// es gibt kein species size limit wie im orig-paper, aber sie berichten dort, dass sie für +// höhere dimensionsn (3,4), eh keines benutzen. + + return OptimizerFactory.makeParams(anpso, anpso.getMainSwarmSize(), problem, randSeed, new EvaluationTerminator(evalCnt)); + } + + public static final GOParameters starANPSO(AbstractOptimizationProblem problem, long randSeed, int evalCnt) { + ANPSO anpso = new ANPSO(); + NichePSO.starNPSO(anpso, problem, randSeed, evalCnt); + + anpso.getMainSwarm().setParameterControl(new ParamAdaption[]{new LinearParamAdaption("inertnessOrChi", 0.7, 0.2)}); +// anpso.setMainSwarmInertness(new LinearParameterAging(0.7, 0.2, evalCnt/anpso.getMainSwarmSize())); + + anpso.setMainSwarmAlgoType(anpso.getMainSwarm().getAlgoType().setSelectedTag("Inertness")); + anpso.getMainSwarm().setPhi1(1.2); + anpso.getMainSwarm().setPhi2(0.6); // ANPSO uses communication in the main swarm + //Possible topologies are: "Linear", "Grid", "Star", "Multi-Swarm", "Tree", "HPSO", "Random" in that order starting by 0. + anpso.SetMainSwarmTopologyTag(3); //"Multi-Swarm" favors the formation of groups in the main swarm + anpso.setMainSwarmTopologyRange(2); // range for topologies like random, grid etc. (does not affect "Multi-Swarm") + anpso.setMaxInitialSubSwarmSize(0); // deactivate early reinits + +// es gibt kein species size limit wie im orig-paper, aber sie berichten dort, dass sie für +// höhere dimensionsn (3,4), eh keines benutzen. + + return OptimizerFactory.makeParams(anpso, anpso.getMainSwarmSize(), problem, randSeed, new EvaluationTerminator(evalCnt)); + } + + public static final GOParameters gmakANPSO(AbstractOptimizationProblem problem, long randSeed, int evalCnt) { + ANPSO anpso = new ANPSO(); + NichePSO.starNPSO(anpso, problem, randSeed, evalCnt); + + anpso.getMainSwarm().setParameterControl(new ParamAdaption[]{new LinearParamAdaption("inertnessOrChi", 0.7, 0.2)}); + + anpso.setMainSwarmAlgoType(anpso.getMainSwarm().getAlgoType().setSelectedTag("Inertness")); + anpso.getMainSwarm().setPhi1(1.2); + anpso.getMainSwarm().setPhi2(1.2); // ANPSO uses communication in the main swarm + //Possible topologies are: "Linear", "Grid", "Star", "Multi-Swarm", "Tree", "HPSO", "Random" in that order starting by 0. + anpso.SetMainSwarmTopologyTag(3); //"Multi-Swarm" favors the formation of groups in the main swarm + anpso.setMainSwarmTopologyRange(4); // range for topologies like random, grid etc. (does not affect "Multi-Swarm") + +// es gibt kein species size limit wie im orig-paper, aber sie berichten dort, dass sie für +// höhere dimensionsn (3,4), eh keines benutzen. + + anpso.getSubswarmOptimizerTemplate().setRho(1); + anpso.getSubswarmOptimizerTemplate().SetRhoIncreaseFactor(2); + anpso.getSubswarmOptimizerTemplate().SetRhoDecreaseFactor(0.5); + + return OptimizerFactory.makeParams(anpso, anpso.getMainSwarmSize(), problem, randSeed, new EvaluationTerminator(evalCnt)); + } + + /** + * Create a grid-star-ANPSO with range 2. + * @param problem + * @param randSeed + * @param evalCnt + * @return + */ + public static final GOParameters sgANPSO(AbstractOptimizationProblem problem, long randSeed, int evalCnt) { + return starTopoANPSO(problem, randSeed, evalCnt, 1, 2); + } + + /** + * Create a starANPSO with a given main swarm topology. + * + * @param problem + * @param randSeed + * @param evalCnt + * @param topology + * @param topologyRange + * @return + */ + public static final GOParameters starTopoANPSO(AbstractOptimizationProblem problem, long randSeed, int evalCnt, int topology, int topologyRange) { + GOParameters params = starANPSO(problem, randSeed, evalCnt); + ((ANPSO)params.getOptimizer()).SetMainSwarmTopologyTag(topology); + ((ANPSO)params.getOptimizer()).setMainSwarmTopologyRange(topologyRange); + ((ANPSO)params.getOptimizer()).getMainSwarm().setInertnessOrChi(0.73); + + return params; + } + + @Override + public String[] getAdditionalDataHeader() { + return ToolBox.appendArrays(super.getAdditionalDataHeader(), new String[] {"mainSwarmBestFit", "swarmRad"}); + } + + @Override + public Object[] getAdditionalDataValue(PopulationInterface pop) { + return ToolBox.appendArrays(super.getAdditionalDataValue(pop), new Object[] {getMainSwarm().getPopulation().getBestFitness()[0],updateRadius}); + } + + @Override + public String[] getAdditionalDataInfo() { + return ToolBox.appendArrays(super.getAdditionalDataInfo(), new String[]{"The best fitness within the main swarm", "The current value of the adapted swarm radius"}); + } + + @Override + public Population getSubswarmRepresentatives(boolean onlyInactive){ + + Population representatives = super.getSubswarmRepresentatives(onlyInactive); + // this vector does not yet contain the archived solutions + for (int i=0; i swarms) { + Population pop = new Population(swarms.size()); + for (int i=0; i swarms) { + Population pop = new Population(swarms.size()); + for (int i=0; i> graphTable; + + // set of visited vertices in bfs + protected HashSet set; + +/********************************************************************************************************************** + * ctor + */ + public NicheGraph(){ + graphTable = new TreeMap>(); + set = new HashSet(); + } + + + public NicheGraph(NicheGraph o){ + this.graphTable = (TreeMap>)o.graphTable.clone(); + this.set = (HashSet)o.set.clone(); + } + + public Object clone(){ + return (Object) new NicheGraph(this); + } +/********************************************************************************************************************** + * vertices and edges + */ + /** + * adds a new vertex without neighbors + * @param v + */ + public void addVertex(String v){ + if (!containsVertex(v)) graphTable.put(v, new TreeSet()); + } + + /** + * adds an edge to the graph (previously adds the vertices if necessary) + * @param v1 + * @param v2 + */ + public void addEdge(String v1, String v2){ + if (!containsVertex(v1)) addVertex(v1); + if (!containsVertex(v2)) addVertex(v2); + // mutually add the vertices as neighbors + graphTable.get(v1).add(v2); + graphTable.get(v2).add(v1); + } + + public boolean containsVertex(String v) { + return graphTable.containsKey(v); + } + + // return iterator over all vertices in graph + public Iterable getVertexIterator() { + return graphTable.keySet(); + } + + // return an iterator over the neighbors of vertex v + public Iterable getNeighborIterator(String v) { + return graphTable.get(v); + } + +/********************************************************************************************************************** + * BFS, getConnectedComponents + */ + // run BFS from given root vertex r + public void runBFS(String r) { + set = new HashSet(); + + // put root on the queue + java.util.Queue q = new LinkedList(); + q.offer(r); + set.add(r); + + // remove next vertex and put all neighbors on queue (if not visited)... + while (!q.isEmpty()) { + String v = q.poll(); + for (String w : getNeighborIterator(v)) { + if (!set.contains(w)){ + q.offer(w); + set.add(w); + } + } + } + } + + /** + * @return connected components of the graph + */ + public List> getConnectedComponents(){ + ArrayList> l = new ArrayList>(); + + for (String v : getVertexIterator()){ + if (!isComponent(v,l)){ + // use current vertex to start a bfs + runBFS(v); + // add visited vertices to the set of connected components + l.add(set); + } + } + return l; + } + + private boolean isComponent(String v, ArrayList> l) { + for (Set set : l){ + if (set.contains(v)) return true; + } + return false; + } + +} diff --git a/src/eva2/server/go/strategies/NichePSO.java b/src/eva2/server/go/strategies/NichePSO.java new file mode 100644 index 00000000..ea2757a3 --- /dev/null +++ b/src/eva2/server/go/strategies/NichePSO.java @@ -0,0 +1,2199 @@ +package eva2.server.go.strategies; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Vector; + +import eva2.OptimizerFactory; +import eva2.gui.GenericObjectEditor; +import eva2.gui.TopoPlot; +import eva2.server.go.InterfacePopulationChangedEventListener; +import eva2.server.go.InterfaceTerminator; +import eva2.server.go.PopulationInterface; +import eva2.server.go.enums.PSOTopologyEnum; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.individuals.InterfaceDataTypeDouble; +import eva2.server.go.operators.nichepso.absorption.EuclideanDiversityAbsorptionStrategy; +import eva2.server.go.operators.nichepso.absorption.InterfaceAbsorptionStrategy; +import eva2.server.go.operators.nichepso.absorption.StandardAbsorptionStrategy; +import eva2.server.go.operators.nichepso.deactivation.InterfaceDeactivationStrategy; +import eva2.server.go.operators.nichepso.deactivation.StandardDeactivationStrategy; +import eva2.server.go.operators.nichepso.merging.InterfaceMergingStrategy; +import eva2.server.go.operators.nichepso.merging.ScatterMergingStrategy; +import eva2.server.go.operators.nichepso.merging.StandardMergingStrategy; +import eva2.server.go.operators.nichepso.subswarmcreation.InterfaceSubswarmCreationStrategy; +import eva2.server.go.operators.nichepso.subswarmcreation.StandardSubswarmCreationStrategy; +import eva2.server.go.operators.paramcontrol.LinearParamAdaption; +import eva2.server.go.operators.paramcontrol.ParamAdaption; +import eva2.server.go.operators.paramcontrol.ParameterControlManager; +import eva2.server.go.operators.terminators.EvaluationTerminator; +import eva2.server.go.populations.Population; +import eva2.server.go.populations.SolutionSet; +import eva2.server.go.problems.AbstractOptimizationProblem; +import eva2.server.go.problems.FM0Problem; +import eva2.server.go.problems.Interface2DBorderProblem; +import eva2.server.go.problems.InterfaceAdditionalPopulationInformer; +import eva2.server.go.problems.InterfaceMultimodalProblem; +import eva2.server.go.problems.InterfaceMultimodalProblemKnown; +import eva2.server.go.problems.InterfaceOptimizationProblem; +import eva2.server.modules.GOParameters; +import eva2.tools.SelectedTag; +import eva2.tools.chart2d.Chart2DDPointIconCircle; +import eva2.tools.chart2d.Chart2DDPointIconContent; +import eva2.tools.chart2d.Chart2DDPointIconCross; +import eva2.tools.chart2d.Chart2DDPointIconPoint; +import eva2.tools.chart2d.Chart2DDPointIconText; +import eva2.tools.chart2d.DElement; +import eva2.tools.chart2d.DPoint; +import eva2.tools.chart2d.DPointIcon; +import eva2.tools.chart2d.DPointSet; + + +/** + * The NichePSO extends the particle swarm optimizer (PSO) by Kennedy and Eberhart + * to locate multiple optima of a multimodal objective function. + * The original algorithm is proposed in [1] and uses a main swarm to explore the search space. + * Subswarms are formed from that main swarm to refine and represent single niches + * which are assumed to correspond to local or global optima. + * + * Different strategies are employed in order to: + * create subswarms from the main swarm + * merge subswarms if they converge to the same solution + * absorb main swarm particles into a subswarm in case a particle enters the area covered by the subswarm + * deactivate subswarms when all containing particles converged on a solution + * + * Some implementations of these strategies and the deactivation strategy itself extend the original algorithm. + * As proposed in [1], NichePSO uses the "cognition only" model of the "inertness weight" PSO to train the main swarm. + * + * mainSwarmInertness sets the inertia weight omega and weights the particles tendency to follow its former movement. + * This controls exploration (favored by larger values) against exploitation (favored by smaller values). + * mainSwarmPhi1 sets Phi1 and weights the cognitive component. + * The term corresponds to the particles tendency to return to its personal best position. + * The combination of a typical value of mainSwarmInertness = 0.7 linearly decreasing to 0.2 + * and a typical value of mainSwarmPhi1 = 1.2 produces good results. + * maxAllowedSwarmRadius defines the maximal radius a subswarm can formally have, but it does not affect the actual radius. + * This adjustment is proposed in [2] in order to improve the performance of the NichePSO. + * Experiments showed a good performance for relatively small values of maxAllowedSwarmRadius <= 0.0001 + * on lower dimensional problems. For higher dimensional problems, larger values may be preferable. + * + * [1] R. Brits, A. P. Engelbrecht and B. Bergh. + * A Niching Particle Swarm Optimizer + * In Proceedings of the 4th Asia-Pacific Conference on Simulated Evolution and Learning (SEAL'02), + * 2002, 2, 692-696 + * [2] E. �zcan and M. Yilmaz. + * Particle Swarms for Multimodal Optimization. + * In: ICANNGA (1), Seiten 366�375, 2007 + * + */ +public class NichePSO implements InterfaceAdditionalPopulationInformer, InterfaceOptimizer, java.io.Serializable { + +/** + * + */ + private static final long serialVersionUID = 2036532085674554490L; +/********************************************************************************************************************** + * members + */ + // nichePSO Parameter + protected int mainSwarmSize = 75; + protected double maxAllowedSwarmRadius = 0.0001; // formally limits the swarm radius of the subswarms + + // Parameter for the mainswarm +// protected double mainSwarmPhi1 = 1.2; +// protected double mainSwarmPhi2 = 0; // by default no communication in the mainswarm + protected PSOTopologyEnum mainSwarmTopology = PSOTopologyEnum.grid; // = 1; + protected int mainSwarmTopologyRange = 0; + private int mainSwarmAlgoType = 0; // 0: inertness, 1: constriction +// private InterfaceParameterAging mainSwarmParamAging = new LinearParameterAging(); + protected ParameterControlManager paramControl = new ParameterControlManager(); + + boolean returnRepresentativeSolutionsOnly = true; // if true only the representatives of every subswarm are returned, else every particles pbest + boolean partlyInactive = false; // used to inactivate parts of the optimizer to see the effect on the performance + private boolean verbose = false; // print events on the console + transient boolean log = false; // for debugging: produce the NichePSO-file and FinalSuggestedOptima-plot with the elite + transient boolean plotFinal = false; // plot finalSuggestedOptima + protected boolean plot = false; // produce plots + protected boolean useSinglePlotWindow = true; + transient boolean savePlots = false; // save produced plots as jpegs (turn off for many multiruns...) + protected int showCycle = 10; // produce a plot every n generations + protected transient String dirForCurrentExperiment = "unset"; + + // the main swarm and the subswarms + protected ParticleSubSwarmOptimization mainSwarm = new ParticleSubSwarmOptimization(); + protected Vector subSwarms = new Vector(); + protected ParticleSubSwarmOptimization subswarmOptimizerTemplate = new ParticleSubSwarmOptimization(); + // individuals to be reinitialized in the next iteration + protected Vector indicesToReinit = null; + + // the strategies + protected InterfaceDeactivationStrategy deactivationStrategy = new StandardDeactivationStrategy(); + protected InterfaceMergingStrategy mergingStrategy = new StandardMergingStrategy(); + protected InterfaceAbsorptionStrategy absorptionStrategy = new StandardAbsorptionStrategy(); + protected InterfaceSubswarmCreationStrategy subswarmCreationStrategy = new StandardSubswarmCreationStrategy(); + + // the problem + protected InterfaceOptimizationProblem m_Problem = new FM0Problem(); + + // only used by island model ? + protected String m_Identifier = ""; + + // eventListener + transient protected InterfacePopulationChangedEventListener m_Listener; + + // for debugging: file containing the output + transient protected BufferedWriter outputFile = null; + + // for debugging and plotting ----------------------------------------------- + transient protected TopoPlot m_TopologySwarm; + transient protected boolean m_shownextplot = false; + transient protected boolean deactivationOccured = false; + transient protected boolean mergingOccurd = false; + transient protected boolean absorbtionOccurd = false; + transient protected boolean creationOccurd = false; + // deactivation + transient protected Vector deactivatedSwarm; + // merging + transient protected Vector borg; + transient protected Vector others; + transient protected Vector borgbest; + transient protected Vector othersbest; + // absorbtion + transient protected Vector indytoabsorb; + // subswarmcreation + transient protected Vector indyconverged; + transient protected Vector convergedneighbor; + //----------------------------------------------------------------------------- + public static final String stdDevKey = "StdDevKey"; + public static final String fitArchiveKey = "FitnessArchiveKey"; + // by default, calculate the individuals fitness std dev using this number of past fitness values + public static final int defaultFitStdDevHorizon = 3; + +/********************************************************************************************************************** + * ctors, clone + */ + /** @tested + * + */ + public NichePSO(){ + if (log) initLogFile(); + initMainSwarm(); // not really necessary if init is called before optimization but this way init doesnt change the parameters of a newly constructed object + initSubswarmOptimizerTemplate(); + + hideHideable(); + } + + /** + * Take care that all properties which may be hidden (and currently are) send a "hide" message to the Java Bean properties. + * This is called by PropertySheetPanel in use with the GenericObjectEditor. + */ + public void hideHideable() { + // the following properties are hidden from the GUI in the ANPSO ctor but should be shown for the NichePSO + GenericObjectEditor.setHideProperty(getClass(), "subswarmCreationStrategy", false); + GenericObjectEditor.setHideProperty(getClass(), "mergingStrategy", false); + GenericObjectEditor.setHideProperty(getClass(), "absorptionStrategy", false); + GenericObjectEditor.setHideProperty(getClass(), "maxAllowedSwarmRadius", false); + } + + /** @tested + * @param a + */ + public NichePSO(NichePSO a){ + this.mainSwarmSize = a.mainSwarmSize; + this.maxAllowedSwarmRadius = a.maxAllowedSwarmRadius; + +// this.mainSwarmPhi1 = a.mainSwarmPhi1; +// this.mainSwarmPhi2 = a.mainSwarmPhi2; + this.mainSwarmTopology = a.mainSwarmTopology; + this.mainSwarmTopologyRange = a.mainSwarmTopologyRange; + this.mainSwarmAlgoType = a.mainSwarmAlgoType; +// this.mainSwarmParamAging = (InterfaceParameterAging)a.mainSwarmParamAging.clone(); + this.paramControl = (ParameterControlManager)a.paramControl.clone(); + + this.returnRepresentativeSolutionsOnly = a.returnRepresentativeSolutionsOnly; + this.partlyInactive = a.partlyInactive; + this.verbose = a.verbose; + this.log = a.log; + this.useSinglePlotWindow = a.useSinglePlotWindow; + this.savePlots = a.savePlots; + this.showCycle = a.showCycle; + this.SetDirForCurrentExperiment(a.getDirForCurrentExperiment()); + + this.setMainSwarm((ParticleSubSwarmOptimization)a.getMainSwarm().clone()); + this.SetSubSwarms((Vector)a.getSubSwarms().clone()); + this.setSubswarmOptimizerTemplate((ParticleSubSwarmOptimization)a.getSubswarmOptimizerTemplate().clone()); + + this.deactivationStrategy = (InterfaceDeactivationStrategy)a.deactivationStrategy.clone(); + this.mergingStrategy = (InterfaceMergingStrategy)a.mergingStrategy.clone(); + this.absorptionStrategy = (InterfaceAbsorptionStrategy)a.absorptionStrategy.clone(); + this.subswarmCreationStrategy = (InterfaceSubswarmCreationStrategy)a.subswarmCreationStrategy.clone(); + + this.m_Problem = (InterfaceOptimizationProblem)a.m_Problem.clone(); + + this.m_Identifier = a.m_Identifier; + } + + /** @tested + * (non-Javadoc) @see java.lang.Object#clone() + */ + public Object clone(){ + return (Object) new NichePSO(this); + } + +/********************************************************************************************************************** + * inits + */ + /** @tested ps + * sets the mainswarm according to the NichePSO Parameters, + * called via init() + */ + protected void initMainSwarm(){ + // pass NichePSO parameter on to the mainswarmoptimzer + setMainSwarmSize(mainSwarmSize); // (particles are initialized later via init) + getMainSwarm().SetProblem(m_Problem); + getMainSwarm().SetMaxAllowedSwarmRadius(maxAllowedSwarmRadius); + getMainSwarm().getPopulation().setGenerationTo(0); + + // choose PSO-type for the mainswarmoptimizer + getMainSwarm().setGcpso(false); +// getMainSwarm().setAlgoType(new SelectedTag("Inertness")); + getMainSwarm().setParameterControl(new ParamAdaption[]{getDefaultInertnessAdaption()}); + setMainSwarmAlgoType(getMainSwarm().getAlgoType().setSelectedTag(mainSwarmAlgoType)); // set algo type, may influence aging + +// getMainSwarm().setPhi1(mainSwarmPhi1); // cognitive component "tendency to return to the best position visited so far" +// getMainSwarm().setPhi2(mainSwarmPhi2); // social component "tendency to be attracted towards the best position found in its neighbourhood." + + getMainSwarm().setTopology(mainSwarmTopology); + getMainSwarm().setTopologyRange(mainSwarmTopologyRange); + } + + public static ParamAdaption getDefaultInertnessAdaption() { + return new LinearParamAdaption("inertnessOrChi", 0.7, 0.2); + } + + /** @tested + * inits the template used for creating subswarms + * this is only called in the ctor not via init() + * (would overwrite changes set from outside for the next run) + * + */ + protected void initSubswarmOptimizerTemplate(){ + // pass on the parameters set via NichePSO (done in the analogous nichePSO-Setters as well -> no init() necessary) + getSubswarmOptimizerTemplate().SetProblem(m_Problem); + getSubswarmOptimizerTemplate().SetMaxAllowedSwarmRadius(maxAllowedSwarmRadius); + + // choose PSO-type for the subswarmoptimizer + getSubswarmOptimizerTemplate().setGcpso(true); + getSubswarmOptimizerTemplate().setRho(0.1); // on 2D Problems empirically better than default value 1 + getSubswarmOptimizerTemplate().getAlgoType().setSelectedTag("Constriction");//setAlgoType(new SelectedTag("Inertness")); + + //"Several studies propose different values for these parameters" (http://tracer.uc3m.es/tws/pso/parameters.html) + //Bergh2002 p.87 + //Particle Swarm Optimization - an introduction and its recent developments slide 22 P6 (in the constriction variant) + getSubswarmOptimizerTemplate().setInertnessOrChi(0.7298437881283576); + getSubswarmOptimizerTemplate().setPhi1(2.05); + getSubswarmOptimizerTemplate().setPhi2(2.05); + + //subswarmOptimizerTemplate.initGCPSOMember(); +// getSubswarmOptimizerTemplate().getPopulation().setMaxHistoryLength(25); + } + + /** @tested + * returns the optimizer that should be used to create a new subswarm + * @return an optimizer with parameters set according to the nichePSO + */ + public ParticleSubSwarmOptimization getNewSubSwarmOptimizer(){ + //initSubswarmOptimizerTemplate(); + ParticleSubSwarmOptimization template = (ParticleSubSwarmOptimization)getSubswarmOptimizerTemplate().clone(); // this implicitely clones the problem but does not initialize it again... + template.SetProblem(this.m_Problem); //... let all subswarms use the same correct initialised problem instance + return template; + } + + /** @tested junit, junit&, emp, ... + * (non-Javadoc) @see javaeva.server.oa.go.Strategies.InterfaceOptimizer#init() + */ + public void init() { // (called right before next optimize/mutltirun) + // initialize main swarm + initMainSwarm(); // MOE: auch bei multirun: m�gliche �nderungen an Gr��e, AlgoType, maxrad, delta etc. aus letzter Optimierung zur�cksetzen + // mainSwarm.init(): + // - place all indys rndly in search space (depends on: mainSwarmSize, problem) + // - use rnd init velocity vector + // - evaluate (depends on: problem) + // - init fit-archive,stddev, pbest, PBestImprovementsInARow + // - update mbestindividual, maxposdist + // - set particleIndexCounter + getMainSwarm().init(); + + // initialize subswarms + //initSubswarmOptimizerTemplate(); //only in ctor, would change parameters for the next multirun + //subwarmOptimizerTemplate.init(); // dont init and evaluate individuals ! + SetSubSwarms(new Vector()); // dont want to use subswarms from old optimization run (especially not in multiruns)... + indicesToReinit=null; + // show in plot + //MainSwarm.setShow(true); + if (isPlot()) initPlotSwarm(); + } + + /** @tested + * (non-Javadoc) + * uses the given population and basically sets rnd velocity vectors (if reset == false) + */ + public void initByPopulation(Population pop, boolean reset) { + // initByPopulation(...): + // - use indys from pop + // - use rnd init velocity vector + // - evaluate (depends on: problem) + // - init fit-archive,stddev and pbest + getMainSwarm().initByPopulation(pop, reset); + + initSubswarmOptimizerTemplate(); + } + +/********************************************************************************************************************** + * Optimization + */ + /** @tested + * (non-Javadoc) @see javaeva.server.oa.go.Strategies.InterfaceOptimizer#optimize() + */ + public void optimize() { +// System.out.println(BeanInspector.toString(getMainSwarm())); + if (isVerbose()) { + Population pop = getPopulation(); + System.out.println("pop bef: " + pop.size() + " " + pop.getFunctionCalls()); + } + // main swarm: + if (getMainSwarm().getPopulation().size() == 0){// || mainSwarm.getPopulation().size() == 1){ + if (isVerbose()) System.out.print("MainSwarm size is 0\n"); + // increment the generationcount for the terminator: + // 1 generation equals one optimize call including the optimization of the + // (possibly empty) mainswarm and all subswarms + getMainSwarm().getPopulation().incrGeneration(); + } + else getMainSwarm().optimize(); + + maybeReinitIndies(); + + // subswarms: + for (int i = 0; i < getSubSwarms().size(); ++i) { + ParticleSubSwarmOptimization subswarm = getSubSwarms().get(i); + if (subswarm.isActive()) subswarm.optimize(); +// System.out.println(i + " " + subswarm.getPopulation().getFunctionCalls()); + } + + // deactivation: + deactivateSubSwarmsIfPossible(); + + // merging: + mergeSubswarmsIfPossible(); + + // absorption: + absorbParticlesIfPossible(); + + // create new subswarms: + createSubswarmIfPossible(); + + firePropertyChangedEvent("NextGenerationPerformed"); // calls Listener that sth changed... + if (isVerbose()) { + Population pop = getPopulation(); + System.out.println("pop aft: " + pop.size() + " " + pop.getFunctionCalls()); + } + + /** plotting **********************************************************************************/ + if (isPlot()){ + doPlot(); + } + /** end plotting *******************************************************************************/ + + // reset flags etc for: + // deactivation + deactivationOccured = false; + deactivatedSwarm = new Vector(); +// reinitedSwarm = new Vector(); + // merging + mergingOccurd = false; + borg = new Vector(); + others = new Vector(); + borgbest = new Vector(); + othersbest = new Vector(); + // absorbtion + absorbtionOccurd = false; + indytoabsorb = new Vector(); + // subswarmcreation + creationOccurd = false; + indyconverged = new Vector(); + convergedneighbor = new Vector(); + } + + /** + * Check if lone individuals are scheduled for reinitialization into + * the main swarm. This happens after subswarm deactivation. + * Should be called only directly after the main swarm optimization call. + */ + protected void maybeReinitIndies() { + if (indicesToReinit!=null && (indicesToReinit.size()>0)) { // add new individuals + getMainSwarm().reinitIndividuals(indicesToReinit); + indicesToReinit.clear(); + } + } + + /** + * Schedule new particles to be added to this swarm, rndly inited over the search space by the problem + * @param size number of particles to be created + * @param particleIndices set of indices that should be used for the added particles, if null new indices are created + */ + public void scheduleNewParticlesToPopulation(int[] particleIndices) { + if (particleIndices != null) { + if (indicesToReinit==null) indicesToReinit = new Vector(); + indicesToReinit.add(particleIndices); + } + } + + protected void doPlot() { + m_shownextplot = (deactivationOccured || mergingOccurd || absorbtionOccurd || creationOccurd);// repopoccurd || reinitoccurd); + if (this.getMainSwarm().getPopulation().getGeneration()%this.getShowCycle() == 0){// || m_shownextplot){ + // plot merging step + if (mergingOccurd){ + plotMainSwarm(false); + plotMergingCondition(); + if (savePlots){ + String generation = String.valueOf(getMainSwarm().getPopulation().getGeneration()); + // saveCurrentPlotAsJPG(getCurrentDateAsString()+generation+"a"); + } else{ + try { + Thread.sleep(1000); + } catch (InterruptedException e) {} + } + } + // plot main step + synchronized(m_TopologySwarm.getClass()){ + plotMainSwarm(false); + plotSubSwarms(); + //plotAdditionalInfo(); + //plotAllStdDevsInMainSwarm(); + //plotBoundStdDevInMainSwarm(0.03); + } + if (savePlots){ + String gen = String.valueOf(getMainSwarm().getPopulation().getGeneration()); + // saveCurrentPlotAsJPG(getCurrentDateAsString()+gen+"b"); + }else{ + try { + Thread.sleep(1000); + } catch (InterruptedException e) {} + } + + //plotBoundStdDevInMainSwarm(0.5); + m_shownextplot = false; + } + } + + +/********************************************************************************************************************** + * Deactivation + */ + protected void deactivationEventFor(ParticleSubSwarmOptimization subswarm) { + if (isVerbose()) System.out.println("deactivating subswarm"); + deactivatedSwarm.add(subswarm); // only for plotting + deactivationOccured = true; + } + + /** @tested junit + * deactivates the subswarms according to the decativation strategy + */ + protected void deactivateSubSwarmsIfPossible(){ + // check for every subswarm... + for (int i = 0; i < getSubSwarms().size(); ++i){ + ParticleSubSwarmOptimization currentsubswarm = getSubSwarms().get(i); + //.. if it meets the criterion of the deactivation strategy + if (getDeactivationStrategy().shouldDeactivateSubswarm(currentsubswarm)){ + if (isVerbose()) System.out.println("deactivation in NPSO!"); + deactivationEventFor(currentsubswarm); + scheduleNewParticlesToPopulation(getDeactivationStrategy().deactivateSubswarm(currentsubswarm, getMainSwarm())); + } + } + } + + protected double getAvgActiveSubSwarmSize(){ + double avgSize = 0; + int actCnt = 0; + // check for every subswarm... + for (int i = 0; i < getSubSwarms().size(); ++i){ + ParticleSubSwarmOptimization currentsubswarm = getSubSwarms().get(i); + if (currentsubswarm.isActive()) { + actCnt++; + avgSize+=currentsubswarm.m_Population.size(); + } + } + if (actCnt>0) return (avgSize/actCnt); + else return 0; + } + + protected int countActiveSubswarms(){ + int actCnt = 0; + // check for every subswarm... + for (int i = 0; i < getSubSwarms().size(); ++i){ + ParticleSubSwarmOptimization currentsubswarm = getSubSwarms().get(i); + if (currentsubswarm.isActive()) actCnt++; + } + return actCnt; + } +/********************************************************************************************************************** + * Merging + */ + protected void mergingEventFor(int i, int j){ + if (isVerbose()) System.out.print("merge condition \n"); + ParticleSubSwarmOptimization borg = getSubSwarms().get(i); + ParticleSubSwarmOptimization others= getSubSwarms().get(j); + this.borg.add((ParticleSubSwarmOptimization)borg.clone()); // for plotting only + this.others.add((ParticleSubSwarmOptimization)others.clone()); // for plotting only + mergingOccurd = true; + this.borgbest.add(borg.m_BestIndividual); // for plotting only + this.othersbest.add(others.m_BestIndividual); // for plotting only + } + + /** @tested junit + * merges the subswarms according to the merging strategy + */ + protected void mergeSubswarmsIfPossible(){ + boolean runagain = false; + if (isVerbose()) System.out.println("possibly merging " + getSubSwarms().size() + " subswarms..."); + // check for every two subswarms... + for (int i = 0; i < getSubSwarms().size(); ++i){ +// System.out.print(" " + getSubSwarms().get(i).getPopulation().size()); + for (int j = i+1; j < getSubSwarms().size(); ++j){ + //... if they should be merged according to the merging strategy + if (getMergingStrategy().shouldMergeSubswarms(getSubSwarms().get(i), getSubSwarms().get(j))){ + if (isVerbose()) System.out.println("Merging in NPSO!"); + mergingEventFor(i,j); // for plotting + getMergingStrategy().mergeSubswarms(i, j, getSubSwarms(), getMainSwarm()); + runagain = true; // merged subswarm may overlap with another swarm now. This might not have been considered in this run... + --j; // subSwarms.size() has decreased and all elements >=j were shifted one position to the left + } + } + } +// System.out.println(); + if (runagain) mergeSubswarmsIfPossible(); + } + +/********************************************************************************************************************** + * Absorbtion + */ + /** @tested + * adds indy to an active subswarm, then removes indy from the mainswarm. + * @param indy + * @param subswarm + * @return + */ + protected void absorbtionEventFor(AbstractEAIndividual indy, ParticleSubSwarmOptimization subswarm){ + if (isVerbose()) System.out.print("Absorbtion \n"); + absorbtionOccurd = true; + this.indytoabsorb.add(indy); + } + + /** @tested junit + * absorbs the mainswarm particles into the subswarm according to the absorbtion strategy + */ + protected void absorbParticlesIfPossible(){ + boolean runagain = false; + // check for every particle in the main swarm... + for (int i = 0; i < getMainSwarm().getPopulation().size(); ++i){ + AbstractEAIndividual currentindy = getMainSwarm().getPopulation().getEAIndividual(i); + // ...if it matches the absorption-criterion for any subswarm: + for (int j = 0; j < getSubSwarms().size(); ++j){ + ParticleSubSwarmOptimization currentsubwarm = getSubSwarms().get(j); + if (getAbsorptionStrategy().shouldAbsorbParticleIntoSubswarm(currentindy, currentsubwarm, this.getMainSwarm())){ + if (isVerbose()) System.out.println("Absorbing particle (NPSO)"); + absorbtionEventFor(currentindy, currentsubwarm); + getAbsorptionStrategy().absorbParticle(currentindy, currentsubwarm, this.getMainSwarm()); + --i; // ith particle is removed, all indizes shift one position to the left + runagain = true; // if the absorbed particle provides a new best position, the radius of the swarm will change -> run absorption again + break; // dont try to absorb this particle again into another subswarm + } + } + } + if (runagain) absorbParticlesIfPossible(); + } + +/********************************************************************************************************************** + * Subswarm Creation + */ + protected void subswarmCreationEventFor(AbstractEAIndividual currentindy, ParticleSubSwarmOptimization subswarm) { + if (isVerbose()) System.out.print("creating subswarm\n"); + creationOccurd = true; + this.indyconverged.add(currentindy); + for (int i = 0; i < subswarm.getPopulation().size(); ++i){ + AbstractEAIndividual indy = subswarm.getPopulation().getEAIndividual(i); + if (indy.getIndyID()!=currentindy.getIndyID()){ + this.convergedneighbor.add(indy); + } + } + } + + /** @tested junit + * creates a subswarm from every particle in the mainswarm that meets the convergence-criteria of the creation strategy + */ + protected void createSubswarmIfPossible(){ + // for every particle... + for (int i = 0; i < getMainSwarm().getPopulation().size(); ++i){ + AbstractEAIndividual currentindy = getMainSwarm().getPopulation().getEAIndividual(i); + //... that meets the convergence-criteria of the creation strategie + if (getSubswarmCreationStrategy().shouldCreateSubswarm(currentindy,getMainSwarm())){ + if (isVerbose()) System.out.println("Creating sub swarm (NPSO)"); + // use an optimizer according to the template + ParticleSubSwarmOptimization newSubswarm = getNewSubSwarmOptimizer(); + // and create a subswarm from the given particle + getSubswarmCreationStrategy().createSubswarm(newSubswarm,currentindy,getMainSwarm()); + subswarmCreationEventFor(currentindy,newSubswarm); + // add the subswarm to the set of subswarms: + this.getSubSwarms().add(newSubswarm); + i=0; // start again because indizes changed and we dont know how... + } + } + } + +/********************************************************************************************************************** + * event listening + */ + /** @tested + * Something has changed + */ + protected void firePropertyChangedEvent (String name) { + if (this.m_Listener != null) this.m_Listener.registerPopulationStateChanged(this, name); + } + + /** @tested + * This method allows you to add the LectureGUI as listener to the Optimizer + * @param ea + */ + public void addPopulationChangedEventListener( + InterfacePopulationChangedEventListener ea) { + this.m_Listener = ea; + } + public boolean removePopulationChangedEventListener( + InterfacePopulationChangedEventListener ea) { + if (m_Listener==ea) { + m_Listener=null; + return true; + } else return false; + } + /** @tested nn + * This method is required to free the memory on a RMIServer, + * but there is nothing to implement. + */ + public void freeWilly() { + + } + +/********************************************************************************************************************** + * setter, getter: population and solutions + */ + /** @tested nn + * (non-Javadoc) @see eva2.server.go.strategies.InterfaceOptimizer#setPopulation(javaeva.server.oa.go.Populations.Population) + */ + public void setPopulation(Population pop) { + //pass on to mainswarm optimizer + getMainSwarm().setPopulation(pop); + } + + /** @tested junit, junit& + * @return a population consisting of copies from the mainswarm and all active subswarms + */ + public Population getActivePopulation(){ + // construct a metapop with clones from the mainswarm and all active subswarms + Population metapop = (Population)getMainSwarm().getPopulation().clone(); + for (int i = 0; i < getSubSwarms().size(); ++i){ + ParticleSubSwarmOptimization currentsubswarm = getSubSwarms().get(i); + if (currentsubswarm.isActive()){ + Population currentsubswarmpop = (Population)currentsubswarm.getPopulation().clone(); + metapop.addPopulation(currentsubswarmpop); + } + } + + // set correct number of generations + metapop.setGenerationTo(getMainSwarm().getPopulation().getGeneration()); + + // set correct number of function calls + int calls = getMainSwarm().getPopulation().getFunctionCalls(); + for (int i = 0; i < getSubSwarms().size(); ++i){ + ParticleSubSwarmOptimization currentsubswarm = getSubSwarms().get(i); + // calls from inactive populations have to be counted as well... + calls += currentsubswarm.getPopulation().getFunctionCalls(); + } + metapop.SetFunctionCalls(calls); + // care for consistent size: + metapop.synchSize(); + return metapop; + } + + /** @tested junit + * returns a population consisting of copies from the mainswarm and all subswarms + * (active and inactive, so the size of this Population is not necessarily constant). + * (Especially important for the call back regarding the output file... ) + * Beware: getPopulation().getPopulationSize() returns the !initial! size of the main swarm, + * the actual size of the complete population is accessed via getPopulation().size() + * @return a population consisting of copies from the mainswarm and all subswarms. + */ + public Population getPopulation() { + boolean activeOnly = true; // true makes problems if all subswarms are deactivated at the same time! + // construct a metapop with clones from the mainswarm and all subswarms + Population metapop = (Population)getMainSwarm().getPopulation().cloneWithoutInds(); + metapop.ensureCapacity(getMainSwarmSize()); + metapop.addPopulation(getMainSwarm().getPopulation()); + int activeCnt = 0; +// Population currentsubswarm; + for (int i = 0; i < getSubSwarms().size(); ++i){ +// currentsubswarm = (Population)getSubSwarms().get(i).getPopulation().clone(); + if (getSubSwarms().get(i).isActive()) { + activeCnt++; + metapop.addPopulation(getSubSwarms().get(i).getPopulation()); + } else if (!activeOnly) { + metapop.addPopulation(getSubSwarms().get(i).getPopulation()); + } + } + + if (isVerbose()) System.out.println("Active populations: " + activeCnt); + // set correct number of generations + metapop.setGenerationTo(getMainSwarm().getPopulation().getGeneration()); + + // set correct number of function calls + int calls = getMainSwarm().getPopulation().getFunctionCalls(); + for (int i = 0; i < getSubSwarms().size(); ++i){ + calls += getSubSwarms().get(i).getPopulation().getFunctionCalls(); + } +// System.out.println("metapop size " + metapop.size()); + metapop.SetFunctionCalls(calls); + + if (metapop.size()==0) { + System.err.println("NichePSO ERROR! " + metapop.getFunctionCalls()); + + int i=getSubSwarms().size()-1; + while (i>=0 && (metapop.size() subSwarms = getSubSwarms(); +// AbstractEAIndividual[] representatives = new AbstractEAIndividual[getSubSwarms().size()+1]; + for (int i = 0; i < getSubSwarms().size(); ++i){ + if (!onlyInactive || (!subSwarms.get(i).isActive())) + representatives.add((AbstractEAIndividual)(subSwarms.get(i)).m_BestIndividual.clone()); + } + if (!onlyInactive && (getMainSwarm().getPopulation().size() != 0)) { + representatives.add((AbstractEAIndividual)getMainSwarm().m_BestIndividual.clone()); // assures at least one solution, even if no subswarm has been created + } + return representatives; + } + +/********************************************************************************************************************** + * setter, getter: members + */ + + public String globalInfo(){ + return "A Niching Particle Swarm Optimizer"; + } + + /** @tested ps + * sets the !initial! size of the mainswarm population + * use this instead of getPopulation.setPopulationSize() + * @param size + */ + public void setMainSwarmSize(int size){ + // set member + this.mainSwarmSize = size; + // pass on to the mainswarm optimizer + getMainSwarm().getPopulation().setTargetSize(size); + } + + /** @tested nn + * returns the !initial! size of the mainswarm population + * @return the !initial! size of the mainswarm population + */ + public int getMainSwarmSize(){ + return this.mainSwarmSize; + } + + public String mainSwarmSizeTipText(){ + return "sets the initial size of the mainswarm population"; + } + + /** @tested ps + * defines the maximal allowed subswarm radius for absorption and merging + * @param val + */ + public void setMaxAllowedSwarmRadius(double val){ + // set member + this.maxAllowedSwarmRadius = val; + // pass on to the main- and subswarm optimizers + getMainSwarm().SetMaxAllowedSwarmRadius(val); + for (int i = 0; i < getSubSwarms().size(); ++i){ + getSubSwarms().get(i).SetMaxAllowedSwarmRadius(val); + } + getSubswarmOptimizerTemplate().SetMaxAllowedSwarmRadius(val); + } + + /** @tested nn + * @return + */ + public double getMaxAllowedSwarmRadius(){ + return this.maxAllowedSwarmRadius; + } + + public String maxAllowedSwarmRadiusTipText(){ + return "no subswarm radius is allowed to (formally) exceed this threshold (see help for details)"; + } + +// public double getMainSwarmPhi1() { +// return mainSwarmPhi1; +// } +// +// public void setMainSwarmPhi1(double mainSwarmPhi1) { +// this.mainSwarmPhi1 = mainSwarmPhi1; +// double inertChi = getMainSwarm().getInertnessOrChi(); +// getMainSwarm().setPhi1(mainSwarmPhi1); +// // if constriction calc. changed the inertness, update it here, else dont. +//// if (getMainSwarm().getInertnessOrChi() != inertChi) mainSwarmParamAging.setStartValue(getMainSwarm().getInertnessOrChi()); +// if (getMainSwarm().getInertnessOrChi() != inertChi) getMainSwarm().setInertnessOrChi(mainSwarmPhi1); +// } +// +// public double getMainSwarmPhi2() { +// return mainSwarmPhi2; +// } + + public double getMainSwarmInitialVelocity() { + return mainSwarm.getInitialVelocity(); + } + public void setMainSwarmInitialVelocity(double v) { + mainSwarm.setInitialVelocity(v); + } + public String mainSwarmInitialVelocityTipText() { + return "The initial velocity (normed by search range) for the main swarm."; + } + + public String mainSwarmPhi1TipText(){ + return "weights the cognitive component for the PSO used to train the main swarm"; + } + +// public void setMainSwarmPhi2(double p2) { +// this.SetMainSwarmPhi2(p2); +// } +// +// public void setMainSwarmPhi2(double mainSwarmPhi2) { +// this.mainSwarmPhi2 = mainSwarmPhi2; +// double inertChi = getMainSwarm().getInertnessOrChi(); +// getMainSwarm().setPhi2(mainSwarmPhi2); +//// mainSwarmParamAging.setStartValue(getMainSwarm().getInertnessOrChi()); +// // if constriction calc. changed the inertness, update it here, else dont. +//// if (getMainSwarm().getInertnessOrChi() != inertChi) mainSwarmParamAging.setStartValue(getMainSwarm().getInertnessOrChi()); +// if (getMainSwarm().getInertnessOrChi() != inertChi) getMainSwarm().setInertnessOrChi(mainSwarmPhi2); +// } + +// public int getMainSwarmTopologyTag() { +// return mainSwarmTopologyTag; +// } + + public void SetMainSwarmTopologyTag(int mainSwarmTopologyTag) { + // Possible topologies are: "Linear", "Grid", "Star", "Multi-Swarm", "Tree", "HPSO", "Random" in that order starting by 0. + this.mainSwarmTopology = PSOTopologyEnum.translateOldID(mainSwarmTopologyTag); + } + + public PSOTopologyEnum getMainSwarmTopology() { + return mainSwarm.topology; + } + + /** This method allows you to choose the topology type. + * @param t The type. + */ + public void setMainSwarmTopology(PSOTopologyEnum t) { + mainSwarm.topology = t; + this.mainSwarmTopology = t; + GenericObjectEditor.setHideProperty(getClass(), "mainSwarmTopologyRange", mainSwarmTopology == PSOTopologyEnum.multiSwarm); // "Multi-Swarm" has no topologyRange + } + + public int getMainSwarmTopologyRange() { + return mainSwarmTopologyRange; + } + + public void setMainSwarmTopologyRange(int mainSwarmTopologyRange) { + this.mainSwarmTopologyRange = mainSwarmTopologyRange; + } + + public SelectedTag getMainSwarmAlgoType() { + if (mainSwarmAlgoType != getMainSwarm().getAlgoType().getSelectedTagID()) System.err.println("Error in NichePSO:getMainSwarmAlgoType() !!"); + return getMainSwarm().getAlgoType(); + } + + public void setMainSwarmAlgoType(SelectedTag st) { + getMainSwarm().setAlgoType(st); + mainSwarmAlgoType = st.getSelectedTagID(); +// mainSwarmParamAging.setStartValue(getMainSwarm().getInertnessOrChi()); + } + + /** + * Allow GOE/PropertySheetPanel to know about change references in sub-objects. + * + * @return + */ + public String[] getGOEPropertyUpdateLinks() { + return new String[] {"mainSwarmAlgoType", "mainSwarmInertness", "mainSwarmPhi1", "mainSwarmInertness", "mainSwarmPhi2", "mainSwarmInertness"}; + } + + public boolean isReturnRepresentativeSolutionsOnly() { + return returnRepresentativeSolutionsOnly; + } + + public void SetReturnRepresentativeSolutionsOnly(boolean returnRepresentativeSolutionsOnly) { + this.returnRepresentativeSolutionsOnly = returnRepresentativeSolutionsOnly; + } + + /** @tested nn + * @param val + */ + public void SetPartlyInactive(boolean val){ + this.partlyInactive = val; + } + + /** @tested nn + * @return + */ + public boolean isPartlyInactive(){ + return partlyInactive; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + public boolean isVerbose() { + return verbose; + } + + public String verboseTipText(){ + return "activate to print additional information to the console during optimization"; + } + + public boolean isLog() { + return log; + } + + public void SetLog(boolean log) { + this.log = log; + } + + public boolean isPlotFinal() { + return plotFinal; + } + + public void SetPlotFinal(boolean plotFinal) { + this.plotFinal = plotFinal; + } + + public void setPlot(boolean plot) { + this.plot = plot; + } + + public boolean isPlot() { + return plot; + } + + public String plotTipText(){ + return "toggles the plot window"; + } + + public boolean isUseSinglePlotWindow() { + return useSinglePlotWindow; + } + + public void setUseSinglePlotWindow(boolean useSinglePlotWindow) { + this.useSinglePlotWindow = useSinglePlotWindow; + } + + public String useSinglePlotWindowTipText(){ + return "deactivate to open a new window for every plot"; + } + + public boolean isSavePlots() { + return savePlots; + } + + public void SetSavePlots(boolean savePlots) { + this.savePlots = savePlots; + } + + public void setShowCycle(int showCycle) { + this.showCycle = showCycle; + } + + public int getShowCycle() { + return showCycle; + } + + public String showCycleTipText(){ + return "sets the interval (in generations) used to update the plot window"; + } + + /** + * @return + */ + public String getDirForCurrentExperiment() { + return dirForCurrentExperiment; + } + + /** sets the base directory for any output. + * Output produced: + * - if isLog(), a log file is written + * - if isPlot and isSavePlots, pictures are produced + * @param dirForCurrentExperiment + */ + public void SetDirForCurrentExperiment(String dirForCurrentExperiment) { + this.dirForCurrentExperiment = dirForCurrentExperiment; + } + + public void setMainSwarm(ParticleSubSwarmOptimization mainSwarm) { + this.mainSwarm = mainSwarm; + } + + public ParticleSubSwarmOptimization getMainSwarm() { + return mainSwarm; + } + +// public InterfaceParameterAging getMainSwarmInertness(){ +// return mainSwarmParamAging; +//// return this.mainSwarm.getInertnessAging(); +// } +// +// public void setMainSwarmInertness(InterfaceParameterAging pa){ +// mainSwarmParamAging = pa; +// this.mainSwarm.setInertnessAging(pa); +// getMainSwarm().setInertnessOrChi(pa.getStartValue()); +// } + + public String mainSwarmInertnessTipText(){ + return "sets the inertness weight used for the PSO to train the main swarm (see help for details)"; + } + + public void SetSubSwarms(Vector subSwarms) { + this.subSwarms = subSwarms; + } + + public Vector getSubSwarms() { + return subSwarms; + } + + public void setSubswarmOptimizerTemplate(ParticleSubSwarmOptimization subswarmOptimizerTemplate) { + this.subswarmOptimizerTemplate = subswarmOptimizerTemplate; + } + + public ParticleSubSwarmOptimization getSubswarmOptimizerTemplate() { + return subswarmOptimizerTemplate; + } + + public String subswarmOptimizerTemplateTipText(){ + return "sets the optimizer used to train the subswarms"; + } + + public void setDeactivationStrategy(InterfaceDeactivationStrategy deactivationStrategy) { + this.deactivationStrategy = deactivationStrategy; + } + + public InterfaceDeactivationStrategy getDeactivationStrategy() { + return deactivationStrategy; + } + + public String deactivationStrategyTipText(){ + return "sets the strategy used to deactivate subswarms"; + } + + public void setMergingStrategy(InterfaceMergingStrategy mergingStrategy) { + this.mergingStrategy = mergingStrategy; + } + + public InterfaceMergingStrategy getMergingStrategy() { + return mergingStrategy; + } + + public String mergingStrategyTipText(){ + return "sets the strategy used to merge subswarms"; + } + + public void setAbsorptionStrategy(InterfaceAbsorptionStrategy absorptionStrategy) { + this.absorptionStrategy = absorptionStrategy; + } + + public InterfaceAbsorptionStrategy getAbsorptionStrategy() { + return absorptionStrategy; + } + + public String absorptionStrategyTipText(){ + return "sets the strategy used to absorb main swarm particles into a subswarm"; + } + + public void setSubswarmCreationStrategy(InterfaceSubswarmCreationStrategy subswarmCreationStrategy) { + this.subswarmCreationStrategy = subswarmCreationStrategy; + } + + + public InterfaceSubswarmCreationStrategy getSubswarmCreationStrategy() { + return subswarmCreationStrategy; + } + + public String subswarmCreationStrategyTipText(){ + return "sets the strategy to create subswarms from the main swarm"; + } + + /** @tested nn + * (non-Javadoc) @see javaeva.server.oa.go.Strategies.InterfaceOptimizer#getProblem() + */ + public InterfaceOptimizationProblem getProblem() { + return this.m_Problem; + } + + /** @tested ps + * This method will set the problem that is to be optimized + * @param problem + */ + public void SetProblem(InterfaceOptimizationProblem problem) { + // set member + this.m_Problem = problem; + // pass on to the main- and subswarm optimizers + getMainSwarm().SetProblem(problem); + for (int i = 0; i < getSubSwarms().size(); ++i){ + getSubSwarms().get(i).SetProblem(problem); + } + getSubswarmOptimizerTemplate().SetProblem(problem); + } + + /** @tested nn + * This method allows you to set an identifier for the algorithm + * @param name The indenifier + */ + public void SetIdentifier(String name) { + this.m_Identifier = name; + } + + /** @tested nn + * (non-Javadoc) @see javaeva.server.oa.go.Strategies.InterfaceOptimizer#getIdentifier() + */ + public String getIdentifier() { + return this.m_Identifier; + } + +/********************************************************************************************************************** + * getter: "descriptive parameters" for the mainswarm and subswarms + */ + public double getAveDistToNeighborInMainswarm(){ + return getMainSwarm().getAveDistToNeighbor(); + } + + public double[] getFitDevsInMain(){ + double[] res = new double[getMainSwarm().getPopulation().size()]; + for (int i = 0; i < getMainSwarm().getPopulation().size(); ++i){ + AbstractEAIndividual indy = getMainSwarm().getPopulation().getEAIndividual(i); + res[i] = ((Double)indy.getData(NichePSO.stdDevKey)).doubleValue(); + } + return res; + } + + /** @tested junit + * @param vals + * @return + */ + public double getMedian(double[] vals) { + java.util.Arrays.sort(vals); + double result; + if (vals.length % 2 == 0){ // even + int mid1 = (vals.length/2)-1; + int mid2 = (vals.length/2); + result = 1.0/2.0*(vals[mid1]+vals[mid2]); + + }else { // odd + int mid = ((vals.length+1)/2)-1; + result = vals[mid]; + } + return result; + } + + public double getMedianSubswarmSize() { + if (getSubSwarms().size() == 0) return 0; + double[] size = new double[getSubSwarms().size()]; + for (int i = 0; i < getSubSwarms().size(); ++i){ + if (getSubSwarms().get(i) == null) { // happend once - cant reproduce... + System.out.println("getMedianSubswarmSize: subSwarms has null objects - why ?"); + break; + } + size[i] = getSubSwarms().get(i).getPopulation().size(); + } + return getMedian(size); + } + + public double getMeanSubswarmSize() { + double mean = 0; + for (int i = 0; i < getSubSwarms().size(); ++i){ + mean += getSubSwarms().get(i).getPopulation().size(); + } + mean = mean/getSubSwarms().size(); + return mean; + } + + public double getMaxSubswarmSize() { + double max = 0; + for (int i = 0; i < getSubSwarms().size(); ++i){ + if (getSubSwarms().get(i).getPopulation().size() > max){ + max = getSubSwarms().get(i).getPopulation().size(); + } + } + return max; + } + + public double getMeanSubswarmDistanceNormalised(){ + double meanDist = 0; + int pairs = 0; + for (int i = 0; i < getSubSwarms().size(); ++i){ + for (int j = i+1; j < getSubSwarms().size(); ++j){ + ParticleSubSwarmOptimization sub1 = getSubSwarms().get(i); + ParticleSubSwarmOptimization sub2 = getSubSwarms().get(j); + meanDist += getMainSwarm().distance(sub1.getGBestIndividual(), sub2.getGBestIndividual()); + ++pairs; + } + } + meanDist = meanDist / pairs; + meanDist = meanDist / getMainSwarm().maxPosDist; + return meanDist; + } + + public double getMeanSubswarmDiversityNormalised() { + double meanDiv = 0; + for (int i = 0; i < getSubSwarms().size(); ++i){ + ParticleSubSwarmOptimization currentSubswarm = getSubSwarms().get(i); + meanDiv += currentSubswarm.getEuclideanDiversity(); + } + meanDiv = meanDiv/(double)getSubSwarms().size(); + meanDiv = meanDiv/getMainSwarm().maxPosDist; + return meanDiv; + } + +/********************************************************************************************************************** + * setter, getter: infostrings + */ + /** @tested nn + * This method will return a naming String + * @return The name of the algorithm + */ + public String getName() { + return "NichePSO-"+getMainSwarmSize(); + } + + /** @tested nn + * This method will return a string describing all properties of the optimizer + * and the applied methods. + * @return A descriptive string + */ + public String getStringRepresentation() { + String result = ""; + result += "niching particle swarm optimization." + + " This algorithm optimizes multiple optima of an multimodal objective function in parallel.\n"; + return result; + } + + /** @tested emp + * returns a string that lists the global best individuals (ie best of all time) from every subswarm + * @return descriptive string of the elite + */ + public String getSubswarmRepresentativesAsString(boolean onlyInactive){ + String result = "\nSubswarmRepresentatives: \n"; + Population reps = getSubswarmRepresentatives(onlyInactive); + for (int i = 0; i < getSubSwarms().size(); ++i){ + result += reps.getEAIndividual(i).getStringRepresentation() + "\n"; + } + //result += "\n"; + return result; + } + + /** @tested emp + * @return + */ + public String getPerformanceAsString(){ + if (!(m_Problem instanceof InterfaceMultimodalProblem)){ + System.out.println("getPerformanceAsString: problem not instanceof InterfaceMultimodalProblem"); + return ""; + } + + String result = "Performance (#Optima found, Max Peak Ratio, which optima are found): \n"; + + // construct an elite-population (with the gbest individual from every subswarm) + Population elitepop = getSubswarmRepresentatives(false); + + // use elite population to compute performance + if (m_Problem instanceof InterfaceMultimodalProblem){ + result += ((InterfaceMultimodalProblemKnown)m_Problem).getNumberOfFoundOptima(elitepop); + result += "(" + ((InterfaceMultimodalProblemKnown)m_Problem).getRealOptima().size() + ")\t"; + result += ((InterfaceMultimodalProblemKnown)m_Problem).getMaximumPeakRatio(elitepop) + "\t"; + //boolean[] opts = ((InterfaceMultimodalProblem)m_Problem).whichOptimaAreFound(elitepop); + //result += "Optima:"; + //for (int i = 0; i < opts.length; ++i){ + //result += String.valueOf(opts[i])+" "; + //} + result += "\n"; + } + return result; + } + + public String getReport(){ + String result = new String(); + result = "Generations: " + getPopulation().getGeneration(); + result += " FunctionCalls: " + getPopulation().getFunctionCalls(); + result += " MainSwarmSize: " + getMainSwarm().getPopulation().size(); + result += " Subswarms: "; + for (int i = 0; i < getSubSwarms().size(); ++i){ + result += "("+i+")"+getSubSwarms().get(i).getPopulation().size() + " "; + } + result += "SwarmSize: " + getPopulation().size(); + result +="\n"; + + return result; + } + +/********************************************************************************************************************** + * for the logfile + */ + /** @tested emp + * generates the NichePSO_date file + */ + protected void initLogFile(){ + // opening output file... + if (getDirForCurrentExperiment().equals("unset")) { + System.out.println("initLogFile: no directory for output specified, please use setDirForCurrentExperiment first"); + return; + } + + // path + File outputPath = new File(getDirForCurrentExperiment()+"\\NichePSO-LogFiles\\"); + if (!outputPath.exists()) outputPath.mkdirs(); + + //String outputPath = getDirForCurrentExperiment()+"/NichePSO-LogFiles/"; + //OutputPath = OutputPath + dirForCurrentExperiment+"\\NichePSO-LogFiles\\"; + + // file name + SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd'_'HH.mm.ss'_'E"); + String m_StartDate = formatter.format(new Date()); + String name ="NichePSO-LogFile"+"__"+m_StartDate+".dat"; + + File f = new File(outputPath,name); // plattform independent representation... + + try { + if (outputFile != null) outputFile.close(); // close old file + outputFile = new BufferedWriter(new OutputStreamWriter (new FileOutputStream (f))); + } catch (FileNotFoundException e) { + System.out.println("Could not open output file! Filename: " + name); + }catch (IOException e) { + System.out.println("Could not close old output file! Filename: " + name); + } + } + + /** @tested emp + * writes something to the LogFile + * @param line string to be written + */ + protected void writeToLogFile(String line) { + String write = line + "\n"; + if (outputFile == null) return; + try { + outputFile.write(write, 0, write.length()); + outputFile.flush(); + } catch (IOException e) { + System.out.println("Problems writing to output file!"); + } + } + +/**************************************************- plotting analysing debugging -************************************ +/********************************************************************************************************************** + * getter for debugging and analysing + */ + /** @tested + * @param pop + * @param index + * @return particle with given index + */ + public AbstractEAIndividual getIndyByParticleIndexAndPopulation(Population pop, Integer index){ + for (int i = 0; i < pop.size(); ++i) + { + AbstractEAIndividual indy = pop.getEAIndividual(i); + //Integer tmp = (Integer)indy.getData("particleIndex"); // here getData was a cpu-time hotspot -> AbstractEAIndividual now has an index as "direct member" + //if (index.equals(tmp)) return indy; + if (index.intValue() == indy.getIndividualIndex()) return indy; + } + return null; + } + + /** @tested + * @param index + * @return main swarm particle with given index + */ + public AbstractEAIndividual getIndyByParticleIndex(Integer index){ + AbstractEAIndividual indy = null; + Population pop = getMainSwarm().getPopulation(); + indy = getIndyByParticleIndexAndPopulation(pop, index); + if (indy != null) return indy; + for (int i = 0; i < getSubSwarms().size(); ++i){ + pop = getSubSwarms().get(i).getPopulation(); + indy = getIndyByParticleIndexAndPopulation(pop, index); + if (indy != null) return indy; + } + return null; + } + + /** @tested + * @return particle with minimal stddev in fitness over the last 3 iterations + */ + protected AbstractEAIndividual getIndyWithMinStdDev(){ + Population mainpop = getMainSwarm().getPopulation(); + if (mainpop.size() == 0) return null; + + double min = Double.POSITIVE_INFINITY; + int minindex = 0; + AbstractEAIndividual tmpIndy1; + for (int i = 0; i < mainpop.size(); ++i){ + tmpIndy1 = (AbstractEAIndividual)mainpop.get(i); + Double da = (Double)((tmpIndy1).getData(NichePSO.stdDevKey)); + if (da.doubleValue() < min){ + min = da.doubleValue(); + minindex = i; + } + } + return (AbstractEAIndividual)mainpop.get(minindex); + } + +/********************************************************************************************************************** + * plotting + */ + + /** @tested + * inits a new Topoplot + */ + protected void initPlotSwarm(){ + double[] a = new double[2]; + a[0] = 0.0; + a[1] = 0.0; + this.m_TopologySwarm = new TopoPlot("NichePSO-MainSwarm","x","y",a,a); + this.m_TopologySwarm.setParams(60,60); + if (m_Problem instanceof Interface2DBorderProblem) this.m_TopologySwarm.setTopology((Interface2DBorderProblem)this.m_Problem); // draws colored plot + } + + /** @tested + * clean everything except topology colors + */ + protected void cleanPlotSwarm(){ + // delete all previous points + DElement[] elements = this.m_TopologySwarm.getFunctionArea().getDElements(); + int lastIndex = elements.length-1; + DElement last = elements[lastIndex]; + while (last instanceof DPointSet || last instanceof DPoint || last instanceof DPointIcon){ + this.m_TopologySwarm.getFunctionArea().removeDElement(last); +// elements = this.m_TopologySwarm.getFunctionArea().getDElements(); + lastIndex--; + last = elements[lastIndex]; + } + } + + /** @tested + * plots the std dev of all particles in the main swarm + */ + protected void plotAllStdDevsInMainSwarm(){ + //add further information to MainSwarm-Plot point by point + InterfaceDataTypeDouble tmpIndy1; + Population mainpop = getMainSwarm().getPopulation(); + for (int i = 0; i < mainpop.size(); ++i){ + // add particle index to plot so it can be tracked over time + AbstractEAIndividual indy = mainpop.getEAIndividual(i); + Integer index= indy.getIndividualIndex();//(Integer)indy.getData("particleIndex"); + String id = "("+index.toString()+") "; + + tmpIndy1 = (InterfaceDataTypeDouble)mainpop.get(i); + DPoint point = new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1]); + Double da = (Double)(((AbstractEAIndividual)tmpIndy1).getData(NichePSO.stdDevKey)); + double d = da.doubleValue(); + String ds = String.format("%6.2f", d); + DPointIcon icon = new Chart2DDPointIconText(id+ds); + ((Chart2DDPointIconText)icon).setIcon(new Chart2DDPointIconCircle()); + point.setIcon(icon); + this.m_TopologySwarm.getFunctionArea().addDElement(point); + } + + //try to add further information to MainSwarm-Plot at once + /* popRep = new DPointSet(); + for (int i = 0; i < mainpop.size(); ++i){ + tmpIndy1 = (InterfaceDataTypeDouble)mainpop.get(i); + DPoint point = new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1]); + double[] da = (double[])(((AbstractEAIndividual)tmpIndy1).getData("StdDevKey"));//Math.round(100*((AbstractEAIndividual)tmpIndy1).getFitness(0))/(double)100; + double d = da[0]; + String ds = String.format("%6.2f", d); + DPointIcon icon = new Chart2DDPointIconText(ds); + ((Chart2DDPointIconText)icon).setIcon(new Chart2DDPointIconCircle()); + point.setIcon(icon); + popRep.addDPoint(point); + } + this.m_TopologyMainSwarm.m_PlotArea.addDElement(popRep); */ + } + + /** @tested + * plots only the minimal std dev for the respective particle + */ + protected void plotMinStdDevInMainSwarm(){ + //add further information to MainSwarm-Plot (minimal stddev) + InterfaceDataTypeDouble tmpIndy1; + AbstractEAIndividual indy = getIndyWithMinStdDev(); + tmpIndy1 = (InterfaceDataTypeDouble)indy; + Double da = (Double)((indy).getData(NichePSO.stdDevKey)); + double min = da.doubleValue(); + DPoint point = new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1]); + String ds = String.format("%6.2f", min); + DPointIcon icon = new Chart2DDPointIconText(ds); + ((Chart2DDPointIconText)icon).setIcon(new Chart2DDPointIconCircle()); + point.setIcon(icon); + this.m_TopologySwarm.getFunctionArea().addDElement(point); + } + + /** @tested + * plots all std devs < boundary for the respective particles + * @param boundary + */ + protected void plotBoundStdDevInMainSwarm(double boundary){ + InterfaceDataTypeDouble tmpIndy1; + Population mainpop = getMainSwarm().getPopulation(); + for (int i = 0; i < mainpop.size(); ++i){ + // add particle index to plot so it can be tracked over time + AbstractEAIndividual indy = mainpop.getEAIndividual(i); + Integer index= indy.getIndividualIndex();//(Integer)indy.getData("particleIndex"); + String id = "("+index.toString()+") "; + + tmpIndy1 = (InterfaceDataTypeDouble)mainpop.get(i); + DPoint point = new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1]); + Double da = (Double)(((AbstractEAIndividual)tmpIndy1).getData(NichePSO.stdDevKey)); + double d = da.doubleValue(); + String ds = String.format("%6.2f", d); + DPointIcon icon = new Chart2DDPointIconText(id+ds); + ((Chart2DDPointIconText)icon).setIcon(new Chart2DDPointIconCircle()); + point.setIcon(icon); + if (d < boundary) this.m_TopologySwarm.getFunctionArea().addDElement(point); + } + } + + /** @tested + * plots a circle around the individual and adds some information + * @param index index of the particle + * @param text information to be added + */ + protected void plotCircleForIndy(int index, String text){ + AbstractEAIndividual indy = getIndyByParticleIndex(new Integer(index)); + InterfaceDataTypeDouble tmpIndy1 = (InterfaceDataTypeDouble)indy; + DPoint point = new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1]); + DPointIcon icon = new Chart2DDPointIconText(text); + ((Chart2DDPointIconText)icon).setIcon(new Chart2DDPointIconCircle()); + point.setIcon(icon); + this.m_TopologySwarm.getFunctionArea().addDElement(point); + } + + /** @tested + * plots a circle around the individual and adds some information + * @param indy invidual + * @param text information to be added + */ + protected void plotCircleForIndy(AbstractEAIndividual indy, String text){ + InterfaceDataTypeDouble tmpIndy1 = (InterfaceDataTypeDouble)indy; + DPoint point = new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1]); + DPointIcon icon = new Chart2DDPointIconText(text); + ((Chart2DDPointIconText)icon).setIcon(new Chart2DDPointIconCircle()); + point.setIcon(icon); + this.m_TopologySwarm.getFunctionArea().addDElement(point); + } + + /** @tested + * cleans the previous plot and plots the mainswarm as points + */ + protected void plotMainSwarm(boolean withIDs) { + if (this.m_Problem instanceof Interface2DBorderProblem) { + DPointSet popRep = new DPointSet(); + InterfaceDataTypeDouble tmpIndy1; + + cleanPlotSwarm(); + + //draw MainSwarm + Population mainpop = getMainSwarm().getPopulation(); + for (int i = 0; i < mainpop.size(); i++) { + tmpIndy1 = (InterfaceDataTypeDouble)mainpop.get(i); + popRep.addDPoint(new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1])); + } + this.m_TopologySwarm.getFunctionArea().addDElement(popRep); // time consuming + + // identify every particle in the main swarm + if (withIDs){ + for (int i = 0; i < getMainSwarm().getPopulation().size(); ++i){ + AbstractEAIndividual currentindy = getMainSwarm().getPopulation().getEAIndividual(i); + int particleindex = currentindy.getIndividualIndex();//((Integer)currentindy.getData("particleIndex")).intValue(); // should be unique and constant + + AbstractEAIndividual leader = (AbstractEAIndividual)currentindy.getData("MultiSwarmType"); + int leaderIndex = 0; + if (leader != null) leaderIndex = leader.getIndividualIndex(); + + if (currentindy.getData("newParticleFlag")!=null){ + plotCircleForIndy(currentindy,String.valueOf(particleindex)+" reinit"); + currentindy.putData("newParticleFlag", null); + }else{ + String info = String.valueOf(particleindex)+" ("+String.valueOf(leaderIndex)+")"; + plotCircleForIndy(currentindy,info); + } + } + } + + //plotBoundStdDevInMainSwarm(MainSwarm.getDelta()+0.05); + //plotMinStdDevInMainSwarm(); + //plotAllStdDevsInMainSwarm(); + } + } + + protected void plotSubSwarmsWithIndizes(boolean plotActive,boolean plotInactive){ + for (int i = 0; i < this.getSubSwarms().size(); ++i){ + ParticleSubSwarmOptimization currentsub = this.getSubSwarms().get(i); + if (!currentsub.isActive() && plotInactive){ + plotCircleForIndy(currentsub.m_BestIndividual, String.valueOf(i)+"[I]"); + } + if (currentsub.isActive() && plotActive){ + plotCircleForIndy(currentsub.m_BestIndividual,String.valueOf(i)); + } + } + } + + protected void plotAbsorptionCondition(){ + for (int i = 0; i < indytoabsorb.size(); ++i){ + AbstractEAIndividual indy = indytoabsorb.get(i); + int particleIndex = indy.getIndividualIndex();//((Integer)indy.getData("particleIndex")).intValue(); + plotCircleForIndy(indytoabsorb.get(i), String.valueOf(particleIndex)+" absorption"); + } + } + + protected void plotMergingCondition(){ + for (int i = 0; i < this.borg.size(); ++i){ + plotSwarmToMerge(borg.get(i),i); + plotSwarmToMerge(others.get(i),i); + } + plotAbsorptionCondition(); + } + + protected void plotSwarmToMerge(ParticleSubSwarmOptimization swarm,int index) { + InterfaceDataTypeDouble tmpIndy1; + Population swarmpop = (Population)swarm.getPopulation(); + InterfaceDataTypeDouble best = (InterfaceDataTypeDouble)swarm.m_BestIndividual; + DPointSet popRep = new DPointSet(); + + //...draw SubSwarm as points + for (int j = 0; j < swarmpop.size(); j++) { + popRep.setConnected(false); + tmpIndy1 = (InterfaceDataTypeDouble)swarmpop.get(j); + popRep.addDPoint(new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1])); + } + this.m_TopologySwarm.getFunctionArea().addDElement(popRep); // time consuming + + //...draw circle for best + if (!swarm.isActive()){ + plotCircleForIndy((AbstractEAIndividual)best,"[I]-Merging "+String.valueOf(index)); + }else + plotCircleForIndy((AbstractEAIndividual)best,getMaxStdDevFromSwarmAsString(swarm)+"-Merging "+String.valueOf(index)); + + //...draw SubSwarm as connected lines to best + popRep = new DPointSet(); + for (int j = 0; j < swarmpop.size(); j++) { + tmpIndy1 = (InterfaceDataTypeDouble)swarmpop.get(j); + 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_TopologySwarm.getFunctionArea().addDElement(popRep); // time consuming + + } + + /** @tested + * plots all subswarms as connected lines to their respective best individual + */ + protected void plotSubSwarms() { + if (this.m_Problem instanceof Interface2DBorderProblem) { + //DPointSet popRep = new DPointSet(); + InterfaceDataTypeDouble tmpIndy1; + + //cleanPlotSubSwarms(); + + // for all SubSwarms... + for (int i = 0; i < this.getSubSwarms().size(); i++) { + ParticleSubSwarmOptimization currentsubswarm = this.getSubSwarms().get(i); + Population currentsubswarmpop = (Population)currentsubswarm.getPopulation(); + //InterfaceDataTypeDouble best = (InterfaceDataTypeDouble)currentsubswarmpop.getBestIndividual(); + InterfaceDataTypeDouble best = (InterfaceDataTypeDouble)currentsubswarm.m_BestIndividual; + DPointSet popRep = new DPointSet(); + + //...draw SubSwarm as points + for (int j = 0; j < currentsubswarmpop.size(); j++) { + popRep.setConnected(false); + tmpIndy1 = (InterfaceDataTypeDouble)currentsubswarmpop.get(j); + popRep.addDPoint(new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1])); + } + this.m_TopologySwarm.getFunctionArea().addDElement(popRep); // time consuming + + //...draw circle for best + if (!currentsubswarm.isActive()){ + plotCircleForIndy((AbstractEAIndividual)best,"[I]"); + }else{ + if (!getSubswarmOptimizerTemplate().isGcpso()){ + //plotCircleForIndy((AbstractEAIndividual)best,getMaxStdDevFromSwarmAsString(currentsubswarm)); + } + if (getSubswarmOptimizerTemplate().isGcpso()){ + String rhoAsString = String.format("%6.3f", currentsubswarm.getRho()); + //plotCircleForIndy((AbstractEAIndividual)best,rhoAsString); + if (currentsubswarm.gbestParticle != null){ + //plotCircleForIndy((AbstractEAIndividual)currentsubswarm.gbestParticle,"gbest"); + } + } + } + + //...draw SubSwarm as connected lines to best + popRep = new DPointSet(); + for (int j = 0; j < currentsubswarmpop.size(); j++) { + //popRep.setConnected(false); + tmpIndy1 = (InterfaceDataTypeDouble)currentsubswarmpop.get(j); + //popRep.addDPoint(new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1])); + + 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_TopologySwarm.getFunctionArea().addDElement(popRep); // time consuming + } + } // endif + } + + protected String getMaxStdDevFromSwarmAsString(ParticleSubSwarmOptimization swarm) { + double max = -1; + for (int i = 0; i < swarm.getPopulation().size(); ++i){ + AbstractEAIndividual currentindy = swarm.getPopulation().getEAIndividual(i); + Double da = (Double)((currentindy).getData(NichePSO.stdDevKey)); + double d = da.doubleValue(); + if (d > max){ + max = d; + } + } + String ds = String.format("%6.3f", max); + return ds; + } + + /** @tested + * plots information about merging, absorbtion and subswarm-creation + */ + protected void plotAdditionalInfo(){ + // from merging + if (mergingOccurd){ + for (int i = 0; i < borgbest.size(); ++i){ + plotCircleForIndy(borgbest.get(i), "merging "+String.valueOf(i)); + plotCircleForIndy(othersbest.get(i), "merging "+String.valueOf(i)); + } + } + + // from absorbtion + if (absorbtionOccurd){ + for (int i = 0; i < indytoabsorb.size(); ++i){ + AbstractEAIndividual indy = indytoabsorb.get(i); + int particleIndex = indy.getIndividualIndex();//((Integer)indy.getData("particleIndex")).intValue(); + plotCircleForIndy(indy, String.valueOf(particleIndex)+" absorbed"); + } + } + + // from subswarm-creation + if (creationOccurd){ + for (int i = 0; i < indyconverged.size(); ++i){ + int convergedIndex = indyconverged.get(i).getIndividualIndex();//((Integer)indyconverged.get(i).getData("particleIndex")).intValue(); + int convergedneighborIndex = convergedneighbor.get(i).getIndividualIndex();//((Integer)convergedneighbor.get(i).getData("particleIndex")).intValue(); + plotCircleForIndy(indyconverged.get(i),"converged "+convergedIndex); + plotCircleForIndy(convergedneighbor.get(i),"neighbor "+convergedneighborIndex); + } + } + + // from deactivation and reinit + if (deactivationOccured){ + for (int i = 0; i < deactivatedSwarm.size(); ++i){ + plotCircleForIndy(deactivatedSwarm.get(i).m_BestIndividual," deac"); + } +// for (int i = 0; i < reinitedSwarm.size(); ++i){ +// plotSwarm(reinitedSwarm.get(i)," reinit"); +// } + } + } + + protected void plotSwarm(ParticleSubSwarmOptimization swarm, String text) { + for (int i = 0; i < swarm.getPopulation().size(); ++i){ + AbstractEAIndividual currentindy = swarm.getPopulation().getEAIndividual(i); + plotCircleForIndy(currentindy, text); + } + } + + /** @tested + * @param particleIndex + */ + protected void plotTraceIndy(int particleIndex){ + AbstractEAIndividual indy = getIndyByParticleIndex(new Integer(particleIndex)); + + // collect Information to be printed + String text = new String(); + double[] vel = (double[])indy.getData("velocity"); //beware: curVel -> newPos -> plot (not curVel -> plot -> newPos) + String xv = String.format("%6.2f", vel[0]); + String yv = String.format("%6.2f", vel[1]); + text = xv + " " + yv; + + // mark indy and add information + plotCircleForIndy(indy, text); + } + + /** @tested + * plots the old position, new position, personal best position and neighborhood best position for a given individual + * @param indy + */ + protected void plotStatusForIndy(AbstractEAIndividual indy){ + //plot newPos + InterfaceDataTypeDouble tmpIndy1 = (InterfaceDataTypeDouble)indy; + DPoint point = new DPoint(tmpIndy1.getDoubleData()[0], tmpIndy1.getDoubleData()[1]); + DPointIcon icon = new Chart2DDPointIconText(""); + ((Chart2DDPointIconText)icon).setIcon(new Chart2DDPointIconPoint()); + point.setIcon(icon); + this.m_TopologySwarm.getFunctionArea().addDElement(point); + + //plot oldPos + if (!(indy.getData("oldPosition") == null)){ + double[] oldpos = (double[])indy.getData("oldPosition"); + point = new DPoint(oldpos[0], oldpos[1]); + icon = new Chart2DDPointIconText(""); + ((Chart2DDPointIconText)icon).setIcon(new Chart2DDPointIconCross()); + point.setIcon(icon); + this.m_TopologySwarm.getFunctionArea().addDElement(point); + } + + //plot personalBestPos + double[] pbestpos = (double[])indy.getData("BestPosition"); + point = new DPoint(pbestpos[0], pbestpos[1]); + icon = new Chart2DDPointIconText(""); + ((Chart2DDPointIconText)icon).setIcon(new Chart2DDPointIconCircle()); + point.setIcon(icon); + this.m_TopologySwarm.getFunctionArea().addDElement(point); + + //plot neighbourBestPos + double[] neighbourBestPos = (double[])indy.getData("neighbourBestPos"); + point = new DPoint(neighbourBestPos[0], neighbourBestPos[1]); + icon = new Chart2DDPointIconText(""); + ((Chart2DDPointIconText)icon).setIcon(new Chart2DDPointIconContent()); + point.setIcon(icon); + this.m_TopologySwarm.getFunctionArea().addDElement(point); + } + +// protected void saveCurrentPlotAsJPG(String filename){ +// if (getDirForCurrentExperiment().equals("unset")) { +// System.out.println("saveCurrentPlotAsJPG: no directory for output specified, please use setDirForCurrentExperiment first"); +// return; +// } +// +// try { +// Thread.sleep(1000); // last plot may not be saved completely...synchrosleep +// } catch (InterruptedException e) {} +// +// // path +// File outputPath = new File(getDirForCurrentExperiment()+"\\Bilder\\"); // plattform independent representation... +// if (!outputPath.exists()) outputPath.mkdirs(); +// +// // file name +// String name = filename+".jpeg"; +// +// File f = new File(outputPath,name); +// +// synchronized(m_TopologySwarm){ +// try { +// JFrame frame = m_TopologySwarm.m_Frame; +// Robot robot = new Robot(); +// Rectangle area; +// area = frame.getBounds(); +// BufferedImage bufferedImage = robot.createScreenCapture(area); +// +// // JFileChooser fc = new JFileChooser(); +// // if (fc.showSaveDialog(m_TopologySwarm.m_Frame) != JFileChooser.APPROVE_OPTION) return; +// System.out.println("Name " + f.getName()); +// try { +// FileOutputStream fos = new FileOutputStream(f); +// BufferedOutputStream bos = new BufferedOutputStream(fos); +// JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bos); +// encoder.encode(bufferedImage); +// bos.close(); +// } catch (Exception eee) {} +// +// +// } catch (AWTException ee) { +// ee.printStackTrace(); +// } +// } +// +// try { +// Thread.sleep(1000); // nichts l�schen vor speichern...synchrosleep +// } catch (InterruptedException e) {} +// } + + protected String getCurrentDateAsString(){ + SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd'_'HH.mm.ss'_'E"); + String date = formatter.format(new Date()); + return date; + } + + public static final GOParameters nichePSO(AbstractOptimizationProblem problem, long randSeed, InterfaceTerminator term) { + NichePSO npso = new NichePSO(); + npso.setMainSwarmSize(75); + + return OptimizerFactory.makeParams(npso, 75, problem, randSeed, term); + } + + /** + * Create a Niche PSO with parameters as to Brits, Engelbrecht & Bergh: A Niching Particle Swarm Optimizer. SEAL 2002. + * Exeption: the swarm size is 200 by default, because 30 (of the orig. paper) seems way too low. + * + * The evaluation count is required currently due to the generation-dependent intertness decay used by the std. variant. + * To alter the terminator, use GOParameters.setTerminator(), and mind the intertness behavior of the NichePSO, + * which can be altered by using getMainSwarm().setInertnessAging(InterfaceParameteraging) + * + * @param problem + * @param randSeed + * @param evalCnt + * @return + */ + public static final GOParameters stdNPSO(AbstractOptimizationProblem problem, long randSeed, int evalCnt) { + return stdNPSO(null, problem, randSeed, evalCnt); + } + + public static final GOParameters starNPSO(AbstractOptimizationProblem problem, long randSeed, int evalCnt) { + return starNPSO(null, problem, randSeed, evalCnt); + } + + /** + * Set parameters as to Brits, Engelbrecht & Bergh: A Niching Particle Swarm Optimizer. SEAL 2002. + * Exeption: the swarm size is 100 by default, because 30 (of the orig. paper) seems way too low. + * + * @see #stdNPSO(AbstractOptimizationProblem, long, int) + * @param an already existing NichePSO instance or null to create a new one + * @param problem + * @param randSeed + * @param evalCnt + * @return + */ + public static final GOParameters stdNPSO(NichePSO npso, AbstractOptimizationProblem problem, long randSeed, int evalCnt) { + if (npso == null) npso = new NichePSO(); + int popSize = 100; + npso.setMainSwarmSize(popSize); +// double avgRange = Mathematics.getAvgRange(((InterfaceDataTypeDouble)problem.getIndividualTemplate()).getDoubleRange()); + + // set strategies + npso.setDeactivationStrategy(new StandardDeactivationStrategy(0.00001)); + npso.setMergingStrategy(new StandardMergingStrategy(0.001)); + npso.setAbsorptionStrategy(new StandardAbsorptionStrategy()); + npso.setSubswarmCreationStrategy(new StandardSubswarmCreationStrategy(0.0001)); + + npso.setMaxAllowedSwarmRadius(0.0001); // formally limits the swarm radius of the subswarms + + // Parameter for the mainswarm + npso.getMainSwarmAlgoType().setSelectedTag("Inertness"); + npso.getMainSwarm().setPhi1(1.2); + npso.getMainSwarm().setPhi2(0); // by default no communication in the mainswarm + npso.SetMainSwarmTopologyTag(0); // this doesnt have any effect due to no communication + npso.setMainSwarmTopologyRange(0); + npso.mainSwarmAlgoType = 0; + npso.getMainSwarm().setParameterControl(new ParamAdaption[]{getDefaultInertnessAdaption()}); +// npso.getMainSwarm().setSpeedLimit(avgRange/2.); +// npso.getMainSwarm().setCheckSpeedLimit(true); + + // parameter for the subswarms + npso.getSubswarmOptimizerTemplate().setGcpso(true); + npso.getSubswarmOptimizerTemplate().setRho(0.1); // on 2D Problems empirically better than default value 1 +// npso.getSubswarmOptimizerTemplate().setAlgoType(new SelectedTag("Constriction")); + npso.getSubswarmOptimizerTemplate().setAlgoType(npso.getSubswarmOptimizerTemplate().getAlgoType().setSelectedTag("Constriction")); // constriction + npso.getSubswarmOptimizerTemplate().setConstriction(2.05, 2.05); +// npso.getSubswarmOptimizerTemplate().setInertnessAging(new LinearParameterAging(0.7, 0.2, evalCnt/(10*popSize))); // expect shorter + + return OptimizerFactory.makeParams(npso, popSize, problem, randSeed, new EvaluationTerminator(evalCnt)); + } + + /** + * Set parameters as to Brits, Engelbrecht & Bergh: A Niching Particle Swarm Optimizer. SEAL 2002. + * Exeption: the swarm size is 200 by default, because 30 (of the orig. paper) seems way too low. + * + * @see #stdNPSO(AbstractOptimizationProblem, long, int) + * @param an already existing NichePSO instance or null to create a new one + * @param problem + * @param randSeed + * @param evalCnt + * @return + */ + public static final GOParameters starNPSO(NichePSO npso, AbstractOptimizationProblem problem, long randSeed, int evalCnt) { + starNPSO(npso, evalCnt); + return OptimizerFactory.makeParams(npso, npso.getMainSwarmSize(), problem, randSeed, new EvaluationTerminator(evalCnt)); + } + + public static final NichePSO starNPSO(NichePSO npso, int evalCnt) { + if (npso == null) npso = new NichePSO(); + int popSize = 200; + npso.setMainSwarmSize(popSize); +// double avgRange = Mathematics.getAvgRange(((InterfaceDataTypeDouble)problem.getIndividualTemplate()).getDoubleRange()); + + // set strategies + npso.setDeactivationStrategy(new StandardDeactivationStrategy()); + npso.setMergingStrategy(new ScatterMergingStrategy(0.001)); + npso.setAbsorptionStrategy(new EuclideanDiversityAbsorptionStrategy(0.1));// 0.1 used in "Enhancing the NichePSO" by Engelbrecht et al. + npso.setSubswarmCreationStrategy(new StandardSubswarmCreationStrategy(0.0001)); // from "Enhancing the NichePSO" by Engelbrecht et al. + + npso.setMaxAllowedSwarmRadius(0.0001); // formally limits the swarm radius of the subswarms + + // Parameter for the mainswarm + npso.setMainSwarmAlgoType(npso.getMainSwarm().getAlgoType().setSelectedTag("Inertness")); // constriction + npso.getMainSwarm().setPhi1(1.2); +// npso.SetMainSwarmPhi2(0); // by default no communication in the mainswarm + npso.SetMainSwarmTopologyTag(0); // this doesnt have any effect due to no communication + npso.setMainSwarmTopologyRange(0); + npso.mainSwarmAlgoType = 0; + npso.getMainSwarm().setParameterControl(new ParamAdaption[]{getDefaultInertnessAdaption()}); +// npso.setMainSwarmInertness(new LinearParameterAging(0.7, 0.2, evalCnt/popSize)); +// npso.getMainSwarm().setSpeedLimit(avgRange/2.); +// npso.getMainSwarm().setCheckSpeedLimit(true); + + // parameters for the subswarms + npso.getSubswarmOptimizerTemplate().setGcpso(true); + npso.getSubswarmOptimizerTemplate().setRho(0.01); + npso.getSubswarmOptimizerTemplate().setAlgoType(new SelectedTag("Constriction")); + + npso.getSubswarmOptimizerTemplate().setConstriction(2.05, 2.05); +// npso.getSubswarmOptimizerTemplate().setInertnessAging(new NoParameterAging(npso.getSubswarmOptimizerTemplate().getInertnessOrChi())); +// System.out.println(BeanInspector.niceToString(npso)); + return npso; + } + + public String[] getAdditionalDataHeader() { + return new String[]{"mainSwarmSize","numActSpec","avgSpecSize", "numArchived", "archivedMedCorr", "archivedMeanDist", "mainSwarmInertness"}; + } + + public String[] getAdditionalDataInfo() { + return new String[]{"Size of the main swarm of explorers", + "Number of sub-swarms currently active", + "Average sub-swarm size", + "The number of stored potential local optima", + "The median correlation of stored solutions", + "The mean distance of stored solutions", + "Current inertness of the main swarm"}; + } + + public Object[] getAdditionalDataValue(PopulationInterface pop) { + int actSwarms = countActiveSubswarms(); + double avgSpSize = getAvgActiveSubSwarmSize(); + Population inactives = getSubswarmRepresentatives(true); + double medCor = inactives.getCorrelations()[3]; // median correlation of best indies of inactive subswarms + double meanDist = inactives.getPopulationMeasures()[0]; + return new Object[]{getMainSwarm().getPopulation().size(), + actSwarms, + avgSpSize, + getNumArchived(), + medCor, + meanDist, + getMainSwarm().getInertnessOrChi()}; + } + + /** + * Return the number of archived solutions, which is the number of inactive subswarms. + * @return + */ + protected int getNumArchived() { + return (getSubSwarms().size()-countActiveSubswarms()); + } + + /** + * This method is necessary to allow access from the Processor. + * @return + */ + public Object[] getParamControl() { + List ctrlbls = ParameterControlManager.listOfControllables(this); + ctrlbls.add(paramControl); + return ctrlbls.toArray(); + // this works - however differently than when returning a ParameterControlManager + } + + public ParamAdaption[] getParameterControl() { + return paramControl.getSingleAdapters(); + } + public void setParameterControl(ParamAdaption[] paramControl) { + this.paramControl.setSingleAdapters(paramControl); + } + public String parameterControlTipText() { + return "You may define dynamic paramter control strategies using the parameter name."; + } +} \ No newline at end of file diff --git a/src/eva2/server/go/strategies/ParticleSubSwarmOptimization.java b/src/eva2/server/go/strategies/ParticleSubSwarmOptimization.java new file mode 100644 index 00000000..fde3d385 --- /dev/null +++ b/src/eva2/server/go/strategies/ParticleSubSwarmOptimization.java @@ -0,0 +1,754 @@ +package eva2.server.go.strategies; + +import java.util.Vector; + +import eva2.server.go.IndividualInterface; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.individuals.ESIndividualDoubleData; +import eva2.server.go.individuals.InterfaceDataTypeDouble; +import eva2.server.go.operators.distancemetric.EuclideanMetric; +import eva2.server.go.populations.Population; +import eva2.server.go.problems.AbstractOptimizationProblem; +import eva2.server.go.problems.InterfaceOptimizationProblem; +import eva2.tools.math.Mathematics; + + +/** + * This implements a particle swarm optimizer which is used by the NichePSO and ANPSO + * to represent and train the mainswarm or any subswarm. + * This is done by extending the standard particle swarm optimizer so that + * - additional member variables (characterizing and parameterizing the subswarm) are available + * - additional information is added to the particles during an optimization loop + * - additional functions to add, remove and reinitialize particles are available + */ +public class ParticleSubSwarmOptimization extends ParticleSwarmOptimizationGCPSO { + + protected double maxAllowedSwarmRadiusNormal; // maximal allowed swarmradius (relative to the search space) + public static boolean hideFromGOE = true; // dont want it to be available in the GUI + protected boolean active; // marks the swarm active or inactive + + protected double maxPosDist; // maximal possible distance in the search space, depends on problem -> initMaxPosDist() + private int particleIndexCounter; // used to give each particle a unique index (for debbugging and plotting) + private int fitnessArchiveSize = 15; // maximal number of fitnessvalues remembered from former iterations + + //ParameterupdateStrategies +// InterfaceParameterAging inertnessAging = new NoParameterAging(); + +/********************************************************************************************************************** + * ctors, clone + */ + /** @tested ps + * ctor + */ + public ParticleSubSwarmOptimization() { + updateMaxPosDist(); + this.maxAllowedSwarmRadiusNormal = 0.1; // set similar to "particle swarms for multimodal optimization" by Oezcan and Yilmaz + this.active = true; + particleIndexCounter = getPopulation().size(); // newly added particles will start at this index +// setInitialVelocity(1.); + } + + /** @tested + * cpyctor + */ + public ParticleSubSwarmOptimization(ParticleSubSwarmOptimization a) { + super(a); + if (a.m_BestIndividual != null){ + m_BestIndividual = (AbstractEAIndividual)a.m_BestIndividual.clone(); + } + + maxAllowedSwarmRadiusNormal = a.maxAllowedSwarmRadiusNormal; + active = a.active; + maxPosDist = a.maxPosDist; + particleIndexCounter = a.particleIndexCounter; +// inertnessAging = (InterfaceParameterAging)a.inertnessAging.clone(); + fitnessArchiveSize = a.fitnessArchiveSize; + } + + /** @tested + * (non-Javadoc) @see javaeva.server.oa.go.Strategies.ParticleSwarmOptimization#clone() + */ + public Object clone() { + return (Object) new ParticleSubSwarmOptimization(this); + } + + +/********************************************************************************************************************** + * inits + */ + /** @tested ps + * (non-Javadoc) @see javaeva.server.oa.go.Strategies.ParticleSwarmOptimization#init() + */ + public void init(){ + super.init(); + + initIndividuals(); + + updateMBestIndividual(); + updateMaxPosDist(); + particleIndexCounter = getPopulation().size(); +// setInertnessOrChi(inertnessAging.getStartValue()); + } + + /** @tested ps + * (non-Javadoc) @see javaeva.server.oa.go.Strategies.ParticleSwarmOptimization#initByPopulation(javaeva.server.oa.go.Populations.Population, boolean) + */ + public void initByPopulation(Population pop, boolean reset){ + super.initByPopulation(pop, reset); + initIndividuals(); + + updateMBestIndividual(); + updateMaxPosDist(); + particleIndexCounter = getPopulation().size(); + } + + /** @tested junit& + * adds a vector for fitnessvalues to all individuals in the swarm + * and sets the current fitness as the first value + */ + protected void initIndividuals(){ + for (int i = 0; i < m_Population.size(); ++i){ + AbstractEAIndividual indy = (AbstractEAIndividual)(m_Population.getEAIndividual(i)); + initSubSwarmDefaultsOf(indy); + } + } + + public static void initSubSwarmDefaultsOf(AbstractEAIndividual indy) { + initFitnessArchiveOf(indy); + initFitnessStdDevOf(indy); + initPersonalBestOf(indy); + initPBestImprInARowOf(indy); + } + + public static void initFitnessArchiveOf(AbstractEAIndividual indy) { + Vector vec = new Vector(); + double scalarFitness = sum(indy.getFitness()); // if multiobjective, use the sum of all fitnessvalues (dont use the norm because fitnessvalues may be negative) + vec.add(new Double(scalarFitness)); + indy.putData(NichePSO.fitArchiveKey, vec); + } + + /** @tested emp + * adds a std deviation value to an individual + * and initially sets this value to infinity. + */ + public static void initFitnessStdDevOf(AbstractEAIndividual indy) { + // init stddev to inf, dont want immediate convergence... + indy.putData(NichePSO.stdDevKey, new Double(Double.POSITIVE_INFINITY)); + } + + public static void initPBestImprInARowOf(AbstractEAIndividual indy) { + indy.putData("PBestImprovementsInARow", new Integer(0)); + } + + /** @tested junit + * adds a representation of the personal best to an individual + * and initially sets the current individual as its personal best. + */ + public static void initPersonalBestOf(AbstractEAIndividual indy) { + AbstractEAIndividual newpbest = (AbstractEAIndividual)indy.clone(); + newpbest.putData("PersonalBestKey", null); // dont want to have a chain of pbests + indy.putData("PersonalBestKey", newpbest); + } + +/********************************************************************************************************************** + * Optimization + */ + /** @tested ps + * (non-Javadoc) @see javaeva.server.oa.go.Strategies.ParticleSwarmOptimization#optimize() + */ + public void optimize(){ + super.optimize(); + updateFitnessArchives(); + updateFitnessStdDev(); + updatePersonalBest(); + updateMBestIndividual(); +// updateParameters(); + } + + public void reinitIndividuals(Vector indicesToReinit) { + for (int[] indices : indicesToReinit) { + addNewParticlesToPopulation(indices); + } + } + + /** + * Get the next set of indices increasing the internal particle counter. + * Should only be called immediately before adding the new individuals. + * + * @param num + * @return + */ + private int[] getNextIndices(int num) { + int[] indices = new int[num]; + for (int i = 0; i < num; ++i){ + indices[i] = particleIndexCounter; + ++particleIndexCounter; + } + return indices; + } + + public void reinitIndividuals(int numIndies) { + addNewParticlesToPopulation(getNextIndices(numIndies)); + } + +/********************************************************************************************************************** + * updateTopology + */ + + protected AbstractEAIndividual getIndyByParticleIndexAndPopulation(Population pop, Integer index){ + for (int i = 0; i < pop.size(); ++i) + { + AbstractEAIndividual indy = pop.getEAIndividual(i); +// Integer tmp = (Integer)indy.getData("particleIndex"); // CPU-Time Hotspot +// if (index.equals(tmp)) return indy; + if (index.intValue() == indy.getIndividualIndex()) return indy; + } + return null; + } + + /* (non-Javadoc) + * @see eva2.server.go.strategies.ParticleSwarmOptimization#addSortedIndizesTo(eva2.server.go.populations.Population) + */ + protected void addSortedIndicesTo(Object[] sortedPopulation, Population pop) { + int origIndex; + for (int i=0; i bestindypbest). + // This is necessary because the current m_BestIndividual my came from + // an individual that left the swarm and would never be replaced if it + // would dominate all remaining positions in the swarm. + AbstractEAIndividual bestindy = getPopulation().getBestEAIndividual(); + AbstractEAIndividual bestindypbest = (AbstractEAIndividual)bestindy.getData("PersonalBestKey"); + m_BestIndividual = (AbstractEAIndividual)bestindypbest.clone(); + for (int i = 0; i < getPopulation().size(); ++i){ + AbstractEAIndividual currentindy = getPopulation().getEAIndividual(i); + AbstractEAIndividual currentindypbest = (AbstractEAIndividual)currentindy.getData("PersonalBestKey"); + if (currentindypbest.isDominating(m_BestIndividual)){ + m_BestIndividual = (AbstractEAIndividual)currentindypbest.clone(); +// ++gbestImprovmentsInARow; + } //else gbestImprovmentsInARow = 0; + } + } + + /** @tested junit, dbg + * adds the current fitnessvalue to the fitnessarchive for every individual in the swarm. + * Keeps the fitnessarchive at a limited size (lim+1). + */ + public void updateFitnessArchives(){ + //int lim = 3; // maximal number of fitnessvalues remembered from former iterations + for (int i = 0; i < m_Population.size(); ++i){ + AbstractEAIndividual indy = (AbstractEAIndividual)m_Population.getEAIndividual(i); + Vector fitArchive_old = (Vector)(indy.getData(NichePSO.fitArchiveKey)); + double scalarFitness = sum(indy.getFitness()); // if multiobjective, use the sum of all fitnessvalues (dont use the norm because fitnessvalues may be negative) + Double fitness = new Double(scalarFitness); + + Vector fitArchive_new = new Vector(); + int end = fitArchive_old.size(); + int start = 0; + if (end >= fitnessArchiveSize) start = end-fitnessArchiveSize; + + for (int j = start; j < end; ++j){ + fitArchive_new.add(fitArchive_old.get(j)); + } + fitArchive_new.add(fitness); + indy.putData(NichePSO.fitArchiveKey, fitArchive_new); + } + } + + /** @tested junit + * sets the std dev value of all individuals in the swarm + * to the std deviation over the last 3 fitness values + */ + public void updateFitnessStdDev(){ + for (int i = 0; i < m_Population.size(); ++i){ + AbstractEAIndividual currentindy = m_Population.getEAIndividual(i); + Vector fitnessArchive = (Vector)(currentindy.getData(NichePSO.fitArchiveKey)); + // the stddev is computed over 3 values as suggested in + // "a niching particle swarm optimizer" by Brits et al. + double sd = stdDev(fitnessArchive,NichePSO.defaultFitStdDevHorizon); + currentindy.putData(NichePSO.stdDevKey, new Double(sd)); + } + } + + /** @tested junit&, junit + * update the personal best representation if the current individual is better than the pbest + */ + public void updatePersonalBest(){ + for (int i = 0; i < m_Population.size(); ++i){ + AbstractEAIndividual currentindy = m_Population.getEAIndividual(i); + AbstractEAIndividual pbest = (AbstractEAIndividual)currentindy.getData("PersonalBestKey"); + if (currentindy.isDominating(pbest)){ + initPersonalBestOf(currentindy); + + //PBestImprovementsInARow + Integer counter = (Integer)currentindy.getData("PBestImprovementsInARow"); + counter = new Integer(counter.intValue()+1); + currentindy.putData("PBestImprovementsInARow",counter); + }else{ + initPBestImprInARowOf(currentindy); + } + } + } + + /** @tested junit .. + * updates the member representing the maximal possible distance in the current searchspace + */ + public void updateMaxPosDist(){ + // compute the maximal possible distance in the search space: + AbstractOptimizationProblem prob = (AbstractOptimizationProblem)m_Problem; + // m_Problem must have called initProblem, so that the template is set correctly. This shouls always be the case here... + AbstractEAIndividual template = prob.getIndividualTemplate(); + if (template == null){ + System.out.println("Problem does not implement getIndividualTemplate, updateMaxPosDist could not infer dimensions"); + return; + } + if (!(template instanceof ESIndividualDoubleData) && !(template instanceof InterfaceDataTypeDouble)){ + System.out.println("Problem does not use ESIndividualDoubleData or InterfaceDataTypeDouble. UpdateMaxPosDist could not infer dimensions."); + return; + } +// ESIndividualDoubleData min = (ESIndividualDoubleData)template.clone(); +// ESIndividualDoubleData max = (ESIndividualDoubleData)template.clone(); + + double[][] range = null; + if (template instanceof ESIndividualDoubleData) range = ((ESIndividualDoubleData)template).getDoubleRange(); + else range = ((InterfaceDataTypeDouble)template).getDoubleRange(); + double[] minValInDim = new double[range.length]; + double[] maxValInDim = new double[range.length]; + for (int i = 0; i < minValInDim.length; ++i){ + minValInDim[i] = range[i][0]; // get lower boarder for dimension i + maxValInDim[i] = range[i][1]; // get upper boarder for dimension i + } +// min.SetDoubleGenotype(minValInDim); // set all dimensions to min +// max.SetDoubleGenotype(maxValInDim); // set all dimensions to max + this.maxPosDist = Mathematics.euclidianDist(minValInDim, maxValInDim); + } + +// /** +// * Parametervalues of the optimizer may change over time +// */ +// protected void updateParameters() { +// setInertnessOrChi(inertnessAging.getNewParameterValue(getInertnessOrChi(), getPopulation().getGeneration())); +// } +/********************************************************************************************************************** + * dist, mean, stddev, sum + */ + /** @tested junit + * returns the euclidean distance in the search space between indy1 and indy2. + * @param indy1 + * @param indy2 + * @return + */ + public double distance(AbstractEAIndividual indy1, AbstractEAIndividual indy2){ + return EuclideanMetric.euclideanDistance(AbstractEAIndividual.getDoublePositionShallow(indy1), + AbstractEAIndividual.getDoublePositionShallow(indy2)); + } + + /** @tested junit + * returns the mean value for the provided data vec but only for a given number of values. + * If range > vec.size() the mean is computed only for the available data. + * @param vec + * @param range number of values (beginning at the end of vec!) considered to compute the mean + * @return + */ + protected static double mean(Vector vec,int range){ + if (vec.size() < range) range = vec.size(); + double sum = 0; + for (int i = vec.size()-range; i < vec.size(); ++i){ + sum += vec.get(i).doubleValue(); + } + return sum/range; + } + + /** @tested junit + * returns the std deviation for the provided data vec but only for a given number of values + * @param vec data + * @param range number of values (beginning at the end of vec!) considered to compute the std deviation + * @return + */ + public static double stdDev(Vector vec, int range){ + double ssum = 0; + if (vec.size()-range < 0 || range < 2) return Double.POSITIVE_INFINITY; // not enough values, dont risk early convergence + double mean = mean(vec,range); + for (int i = vec.size()-range; i < vec.size(); ++i){ + ssum += Math.pow(vec.get(i).doubleValue()-mean,2); + } + double result = Math.sqrt(ssum/(range-1)); + return result; + } + + private static double sum(double[] fitness) { + double ret = 0.; + for(double d : fitness){ + ret += d; + } + return ret; + } + + /** @tested ps + * Interpretes the given maximal radius as normalised according to the current search space. + * Values from [0,1], 1 means the radius can be as large as the maximal possible distance + * (between any two points) in the search space. + * Because the swarmradius and distances (e.g. in merging and absortion) are given in a standard euclidean metric, + * this function converts the normalised distance into the standard euclidean distance. + * @param normalisedRadius + * @return + */ + public double interpreteAsNormalisedSwarmRadius(double normalisedRadius){ + if(normalisedRadius > 1 || normalisedRadius < 0){ + System.out.println("interpreteAsNormalisedSwarmRadius: Radius not normalised to [0,1]"); + } + // compute standard euclidean radius from normalised radius: + return normalisedRadius*maxPosDist; + } + +/********************************************************************************************************************** + * addNewParticlesToPopulation ... + */ + + /** @tested junit ... + * adds new particles to this swarm, rndly inited over the search space by the problem + * @param particleIndices set of indices that should be used for the added particles, if null new indices are created + */ + private void addNewParticlesToPopulation(int[] particleIndices) { + if (particleIndices == null) throw new RuntimeException("Error, unable to use null index array (ParticleSubSwarmOptimization.addNewParticlesToPOpulation)"); + + Population tmp = new Population(); + tmp.setTargetSize(particleIndices.length); + ////////////// + AbstractOptimizationProblem prob = (AbstractOptimizationProblem)m_Problem; + AbstractEAIndividual template = prob.getIndividualTemplate(); // problem must be inited at this point + AbstractEAIndividual tmpIndy; + + for (int i = 0; i < tmp.getTargetSize(); i++) { + tmpIndy = (AbstractEAIndividual)((AbstractEAIndividual)template).clone(); + tmpIndy.init(prob); + tmp.add(tmpIndy); + } + tmp.init(); + /////////// + + ParticleSubSwarmOptimization tmpopt = new ParticleSubSwarmOptimization(); + tmpopt.SetProblem(this.m_Problem); + tmpopt.evaluatePopulation(tmp); + tmpopt.initByPopulation(tmp, false); // + size FCs + + if (particleIndices != null){ // use given indices + for (int i = 0; i < tmpopt.getPopulation().size(); ++i){ + AbstractEAIndividual indy = tmpopt.getPopulation().getEAIndividual(i); + indy.SetIndividualIndex(particleIndices[i]);//SetData("particleIndex", new Integer(particleIndices[i])); + indy.putData("newParticleFlag",new Boolean(true)); // for plotting + } + } + + addPopulation(tmpopt); // add to the mainswarm (FCs will be considered) + populationSizeHasChanged(); + } + +/********************************************************************************************************************** + * add and remove functions that keep the function calls of the population "accurate" + * (here "accurate" applies to the situation where an added population is always deleted in the next step, like in merging...) + */ + /** @tested nn + * adds a population and its function calls to this.population + * @param pop + */ + public void addPopulation(ParticleSubSwarmOptimization pop){ + addPopulation(pop.getPopulation()); + } + + /** @tested junit& .. + * adds a population and its function calls to this.population + * @param pop + */ + public void addPopulation(Population pop){ + m_Population.addPopulation(pop); + + // dont peculate the function calls from the added population (which is going to be deleted in NichePSO) + m_Population.incrFunctionCallsBy(pop.getFunctionCalls()); + } + + /** @tested nn + * adss an inidividual + * @param ind + * @return + */ + public boolean addIndividual(IndividualInterface ind) { + // nothing to do regarding function calls + // old calls were counted in old population new calls are now counted in this population + return m_Population.addIndividual(ind); + } + + /** @tested nn + * @param o + * @return + */ + public boolean add(Object o) { + return addIndividual((IndividualInterface)o); + } + + /** @tested nn + * adds indy to the swarm + * @param indy + */ + public void add(AbstractEAIndividual indy){ + addIndividual(indy); + } + + /** @tested nn + * removes an individual + * @param ind + */ + public boolean removeSubIndividual (IndividualInterface ind) { + return m_Population.removeMember(ind); + } + + public void removeSubPopulation(Population pop, boolean allowMissing) { // this is very slow... + for (int i = 0; i < pop.size(); ++i){ + AbstractEAIndividual indy = pop.getEAIndividual(i); + if (!removeSubIndividual(indy)) { + if (!allowMissing) { + throw new RuntimeException("Warning, assumed sub population was not contained (ParticleSubSwarmOptimization)."); + } + } + } + } + + /* + public void removeNIndividuals(int n) { + } + public void removeDoubleInstances() { + } + public void removeDoubleInstancesUsingFitness() { + } + public void removeIndexSwitched(int index) { + }*/ + +/********************************************************************************************************************** + * getter, setter + */ + /** @tested ps + * This method will set the problem that is to be optimized + * @param problem + */ + public void SetProblem (InterfaceOptimizationProblem problem) { + this.m_Problem = problem; + updateMaxPosDist(); + } + + /** @tested junit + * @return the maximal euclidean distance between the swarms gbest and any other particle in the swarm. + */ + public double getSwarmRadius(){ + if (getPopulation().size() == 0 || getPopulation().size() == 1) return 0; + + double max = Double.NEGATIVE_INFINITY; + //PhenotypeMetric metric = new PhenotypeMetric(); + + for (int i = 0; i < m_Population.size(); ++i){ + AbstractEAIndividual indy = m_Population.getEAIndividual(i); + //double dist = metric.distance(m_BestIndividual, indy); + double sqrdDist = EuclideanMetric.squaredEuclideanDistance(AbstractEAIndividual.getDoublePositionShallow(m_BestIndividual), + AbstractEAIndividual.getDoublePositionShallow(indy)); + + //dist = distance(m_BestIndividual, indy); + if (sqrdDist > max){ + max = sqrdDist; + } + } + return Math.sqrt(max); + } + + /** @tested ps + * returns the maximal distance between the gbest position and any individual in the swarm + * this distance is not allowed to exceed a given threshold + * @return + */ + public double getBoundSwarmRadius(){ + // convert the normalised (i.e. relative) maxrad to a standard euclidean (i.e. absolute) maxrad + double maxAllowedSwarmRadiusAbs = getMaxAllowedSwarmRadiusAbs(); + // only compare (absolute) euclidean distances + return Math.min(getSwarmRadius(), maxAllowedSwarmRadiusAbs); + } + + public double getMaxAllowedSwarmRadiusAbs() { + // convert the normalised (i.e. relative) maxrad to a standard euclidean (i.e. absolute) maxrad + return interpreteAsNormalisedSwarmRadius(maxAllowedSwarmRadiusNormal); + } + + /** + * @return the average distance a particle has to its neighbor + */ + public double getAveDistToNeighbor() { + Population pop = getPopulation(); + double sum = 0; + for (int i = 0; i < pop.size(); ++i){ + AbstractEAIndividual indy = pop.getEAIndividual(i); + AbstractEAIndividual neigbor = getMemberNeighbor(indy); + if (neigbor == null) return -1; + sum += distance(indy, neigbor); + } + return sum/(double)pop.size(); + } + + /** + * @return a measure for the diversity of the swarm + */ + public double getEuclideanDiversity(){ + double meanDistanceFromGBestPos = 0; + AbstractEAIndividual gbest = getGBestIndividual(); + for (int i = 0; i < getPopulation().size(); ++i){ + AbstractEAIndividual indy = getPopulation().getEAIndividual(i); + meanDistanceFromGBestPos += distance(gbest, indy); + } + meanDistanceFromGBestPos = meanDistanceFromGBestPos/(double)getPopulation().size(); + return meanDistanceFromGBestPos; + } + + /** @tested nn + * binds the swarmradius to the given normalised value + * (f.e. 1 means, that the swarmradius is allowed to take the maximal possible range in the search space) + * @param maxAllowedSwarmRadius value from the intervall [0,1] + */ + public void SetMaxAllowedSwarmRadius(double maxAllowedSwarmRadius) { + this.maxAllowedSwarmRadiusNormal = maxAllowedSwarmRadius; + } + + /** @tested nn + * @return + */ + public double getMaxAllowedSwarmRadius() { + return this.maxAllowedSwarmRadiusNormal; + } + + /** @tested nn + * marks the swarm as active or inactive + * @param active + */ + public void SetActive(boolean active) { + this.active = active; + } + + /** @tested nn + * @return + */ + public boolean isActive() { + return active; + } + +// public InterfaceParameterAging getInertnessAging() { +// return inertnessAging; +// } +// +// /** +// * sets a strategy that changes the value of the inertness parameter during an optimization run +// * @param inertnessAging +// */ +// public void setInertnessAging(InterfaceParameterAging inertnessAging) { +// this.inertnessAging = inertnessAging; +// } + + /** @tested junit + * returns the particle with the minimal distance to indy + * @param indy particle should be from this swarm + * @return null if there is no neighbor else neighbor + */ + public AbstractEAIndividual getMemberNeighbor(AbstractEAIndividual indy){ + if (getPopulation().size() == 0){ + System.out.println("getNeighbor: swarm empty"); + return null; + } + // check if there is at least a second particle... + if (getPopulation().size() == 1){ + //System.out.println("getNeighbor: swarm too small, no neighbor available"); + //return (AbstractEAIndividual)indy.clone(); // would conflict with constant size for overall population... + return null; + } + + // get the neighbor... + int index = -1; + double mindist = Double.POSITIVE_INFINITY; + boolean found=false; + for (int i = 0; i < getPopulation().size(); ++i){ + AbstractEAIndividual currentindy = getPopulation().getEAIndividual(i); + if (indy.getIndyID()!=currentindy.getIndyID()){ // dont compare particle to itself or a copy of itself + double dist = distance(indy,currentindy); + if (dist < mindist){ + mindist = dist; + index = i; + } + } else found=true; + } + + if (!found) System.err.println("getNeighbor: particle searching for neighbor is not part of the swarm"); + return getPopulation().getEAIndividual(index); + } + + public AbstractEAIndividual getGBestIndividual(){ + return m_BestIndividual; + } + + /** + * @param indyToExclude + * @return particle with worst personal best position in the swarm. The given particle is excluded. + */ + public AbstractEAIndividual getParticleWithWorstPBestButNot(AbstractEAIndividual indyToExclude) { + Population pop = getPopulation(); + if (pop.size() < 2){ + System.out.println("getParticleWithWorstPBestButNot: Population < 2 - returning null"); + return null; + } + AbstractEAIndividual indyWithWorstPBest = pop.getEAIndividual(0); + if (indyWithWorstPBest == indyToExclude){ + indyWithWorstPBest = pop.getEAIndividual(1); + } + AbstractEAIndividual worstPBest = (AbstractEAIndividual)indyWithWorstPBest.getData("PersonalBestKey"); + for (int i = 0; i < pop.size(); ++i){ + AbstractEAIndividual currentindy = pop.getEAIndividual(i); + AbstractEAIndividual currentpbest = (AbstractEAIndividual)currentindy.getData("PersonalBestKey"); + if (currentindy!=indyToExclude && worstPBest.isDominating(currentpbest)){ + indyWithWorstPBest = currentindy; + worstPBest = currentpbest; + } + } + return indyWithWorstPBest; + } + + + public int getFitnessArchiveSize() { + return fitnessArchiveSize; + } + public void setFitnessArchiveSize(int fitnessArchiveSize) { + this.fitnessArchiveSize = fitnessArchiveSize; + } + public String fitnessArchiveSizeTipText() { + return "The number of fitness values stored per individual for deactivation strategies."; + } +} diff --git a/src/eva2/server/go/strategies/ParticleSwarmOptimization.java b/src/eva2/server/go/strategies/ParticleSwarmOptimization.java index a1ca5b8c..705e8791 100644 --- a/src/eva2/server/go/strategies/ParticleSwarmOptimization.java +++ b/src/eva2/server/go/strategies/ParticleSwarmOptimization.java @@ -160,6 +160,7 @@ public class ParticleSwarmOptimization implements InterfaceOptimizer, java.io.Se this.m_Phi2 = a.m_Phi2; this.m_InertnessOrChi = a.m_InertnessOrChi; this.m_TopologyRange = a.m_TopologyRange; + this.paramControl = (ParameterControlManager) a.paramControl.clone(); //this.setCheckSpeedLimit(a.isCheckSpeedLimit()); } diff --git a/src/eva2/server/go/strategies/ParticleSwarmOptimizationGCPSO.java b/src/eva2/server/go/strategies/ParticleSwarmOptimizationGCPSO.java new file mode 100644 index 00000000..51bb184c --- /dev/null +++ b/src/eva2/server/go/strategies/ParticleSwarmOptimizationGCPSO.java @@ -0,0 +1,275 @@ +package eva2.server.go.strategies; + +import eva2.tools.math.RNG; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.populations.Population; + +/** + * This extends the particle swarm optimization implementation + * so that the guaranteed global convergence pso can be used as suggested by + * Franz van den Bergh in "An Analysis of Particle Swarm Optimizers". + * In this modification the velocity of the global best particle is updated differently. + */ +public class ParticleSwarmOptimizationGCPSO extends ParticleSwarmOptimization { + // choosable parameters: + protected boolean gcpso; + protected int sc; + protected int fc; + protected double rhoIncreaseFactor; + protected double rhoDecreaseFactor; + // members updated via updateGCPSOMember: + protected int gbestParticleIndex = -1; + protected boolean gbestParticleHasChanged; + protected int numOfSuccesses; + protected int numOfFailures; + protected AbstractEAIndividual gbestParticle; + private double rho; //initial rho value can be chosen + + protected int getAccelerationForGlobalBestParticleCounter = 0; // only for testing + +/********************************************************************************************************************** + * ctors, inits + */ + /** @tested ps + * ctor - sets default values according to + * "An Analyis of Paricle Swarm Optimizers" by Franz van den Bergh + */ + public ParticleSwarmOptimizationGCPSO(){ + setGcpso(true); + gbestParticleIndex = -1; + //gbestParticle + gbestParticleHasChanged = false; + numOfSuccesses = 0; + numOfFailures = 0; + setRho(1); + SetSc(15); + SetFc(5); + SetRhoIncreaseFactor(2.0); + SetRhoDecreaseFactor(0.5); + } + + /** @tested ps + * @param a + */ + public ParticleSwarmOptimizationGCPSO(ParticleSwarmOptimizationGCPSO a){ + super(a); + this.setGcpso(a.gcpso); + this.gbestParticleIndex = a.gbestParticleIndex; + if (a.gbestParticle != null){ + this.gbestParticle = (AbstractEAIndividual)a.gbestParticle.clone(); + double[] aFitness= (double[])a.gbestParticle.getData(partBestFitKey); + this.gbestParticle.putData(partBestFitKey, aFitness.clone()); + } + this.gbestParticleHasChanged = a.gbestParticleHasChanged; + this.numOfSuccesses = a.numOfSuccesses; + this.numOfFailures = a.numOfFailures; + this.setRho(a.getRho()); + this.SetSc(a.getSc()); + this.SetFc(a.getFc()); + this.SetRhoIncreaseFactor(a.getRhoIncreaseFactor()); + this.SetRhoDecreaseFactor(a.getRhoDecreaseFactor()); + } + + /** This method returns a global info string + * @return description + */ + public static String globalInfo() { + return "Guaranteed Convergence Particle Swarm Optimiser (GCPSO) " + + "as proposed by F. van den Bergh."; + } + +/********************************************************************************************************************** + * overwritten + */ + /** @tested + * (non-Javadoc) @see javaeva.server.go.strategies.ParticleSwarmOptimization#optimize() + */ + public void optimize() { + super.optimize(); //updatePopulation->updateIndividual->updateVelocity (s.u.) + updateGCPSOMember(); + } + + /** @tested junit& + * (non-Javadoc) @see javaeva.server.go.strategies.ParticleSwarmOptimization#updateVelocity(int, double[], double[], double[], double[], double[][]) + * uses a special velocity update strategy for the gobal best particle. + */ + protected double[] updateVelocity(int index, double[] lastVelocity, double[] personalBestPos, double[] curPosition, double[] neighbourBestPos, double[][] range) { + double[] accel, curVelocity = new double[lastVelocity.length]; + + if (useAlternative) { + accel = getAccelerationAlternative(index, personalBestPos, neighbourBestPos, curPosition, range); + } else { + if (index == gbestParticleIndex && isGcpso()) accel = getAccelerationForGlobalBestParticle(personalBestPos, neighbourBestPos, curPosition, range); + else accel = getAcceleration(personalBestPos, neighbourBestPos, curPosition, range); + } + for (int i = 0; i < lastVelocity.length; i++) { + curVelocity[i] = this.m_InertnessOrChi * lastVelocity[i]; + curVelocity[i] += accel[i]; + } + return curVelocity; + } + +/********************************************************************************************************************** + * GCPSO core + */ + /** @tested ps + * @return the acceleration component. + * Should only be called for the global best particle + * (i.e. the particle with the best personal best position) + */ + private double[] getAccelerationForGlobalBestParticle( + double[] personalBestPos, double[] neighbourBestPos, + double[] curPosition, double[][] range) + { + ++getAccelerationForGlobalBestParticleCounter; + double[] accel = new double[curPosition.length]; + for (int i = 0; i < personalBestPos.length; i++) { + // reset position to the global best position + accel[i] = -curPosition[i]+personalBestPos[i]; //pbestpos of gbestparticle is gbestpos + // random search around the global best position + accel[i] += getRho()*(1.0-2.0*RNG.randomDouble(0,1)); + } + //System.out.println("rho: " +getVecNorm(accel)); + //System.out.println("accel: " +getVecNorm(accel)); + return accel; + } + + /** @tested junit + * @return the index of the particle with the best personal best position + * (i.e. the index of the global best particle) + */ + protected int getIndexOfGlobalBestParticle() { + if (getPopulation().size() == 0){ + System.out.println("getIndexOfGlobalBestParticle error: no particle in population"); + return -1; + } + int index = 0; + double[] gbestFitness = (double[])getPopulation().getEAIndividual(0).getData(partBestFitKey); + for (int i = 1; i < getPopulation().size(); ++i){ + AbstractEAIndividual indy = getPopulation().getEAIndividual(i); + double[] currentBestFitness = (double[])indy.getData(partBestFitKey); + if (AbstractEAIndividual.isDominatingFitness(currentBestFitness,gbestFitness)){ + gbestFitness = currentBestFitness; + index = i; + } + } + return index; + } + +/********************************************************************************************************************** + * updateGCPSOMember + */ + /** @tested junit + * updates: gbestParticleIndex,gbestParticleHasChanged,numOfSuccesses,numOfFailures,gbestParticle,rho + */ + protected void updateGCPSOMember() { + int index = getIndexOfGlobalBestParticle(); + + /** gbestParticleIndex,gbestParticleHasChanged */ + // check if the gbestParticle changed in the last optimization loop + if (index != gbestParticleIndex) + { + gbestParticleHasChanged = true; + gbestParticleIndex = index; + } else gbestParticleHasChanged = false; + + /** numOfSuccesses,numOfFailures */ + // check if the gbestParticle improved over the last iteration + if (gbestParticle == null){ // no previous gbest on first call available + AbstractEAIndividual gbestParticleCurrent = (AbstractEAIndividual)getPopulation().getEAIndividual(gbestParticleIndex); + gbestParticle = (AbstractEAIndividual)gbestParticleCurrent.clone(); + } + AbstractEAIndividual gbestParticleOld = gbestParticle; + double[] gbestParticleFitnessOld = (double[])gbestParticleOld.getData(partBestFitKey); + AbstractEAIndividual gbestParticleCurrent = (AbstractEAIndividual)getPopulation().getEAIndividual(gbestParticleIndex); + double[] gbestParticleFitnessCurrent = (double[])gbestParticleCurrent.getData(partBestFitKey); + +// if (gbestParticleHasChanged && false){ // reset rho on change? +// numOfFailures = 0; +// numOfSuccesses = 0; +// setRho(1); +// } else { + if (AbstractEAIndividual.isDominatingFitnessNotEqual(gbestParticleFitnessCurrent,gbestParticleFitnessOld)){ + ++numOfSuccesses; + numOfFailures = 0; + } else{ + ++numOfFailures; + numOfSuccesses = 0; + } +// } + + /** gbestParticle */ + gbestParticle = (AbstractEAIndividual)gbestParticleCurrent.clone(); + + /** rho */ + if (numOfSuccesses > getSc()) { + setRho(getRhoIncreaseFactor()*getRho()); + //System.out.println("rho increased"); + } + //System.out.println(getRhoIncreaseFactor()); + if (numOfFailures > getFc()) { + setRho(getRhoDecreaseFactor()*getRho()); + //System.out.println("rho decreased"); + } + //System.out.println(getRhoDecreaseFactor()); + } + +/********************************************************************************************************************** + * getter, setter + */ + public void setGcpso(boolean gcpso) { + this.gcpso = gcpso; + } + + public boolean isGcpso() { + return gcpso; + } + + public String gcpsoTipText(){ + return "deactivate to use the standard PSO by Kennedy and Eberhart"; + } + + public void SetSc(int sc) { + this.sc = sc; + } + + public int getSc() { + return sc; + } + + public void SetFc(int fc) { + this.fc = fc; + } + + public int getFc() { + return fc; + } + + public void SetRhoIncreaseFactor(double rhoIncreaseFactor) { + this.rhoIncreaseFactor = rhoIncreaseFactor; + } + + public double getRhoIncreaseFactor() { + return rhoIncreaseFactor; + } + + public void SetRhoDecreaseFactor(double rhoDecreaseFactor) { + this.rhoDecreaseFactor = rhoDecreaseFactor; + } + + public double getRhoDecreaseFactor() { + return rhoDecreaseFactor; + } + + public void setRho(double rho) { + this.rho = rho; + } + + public String rhoTipText(){ + return "controls the initial radius of a random search in an area surrounding the global best position of the swarm"; + } + + public double getRho() { + return rho; + } +} diff --git a/src/eva2/server/go/strategies/StarANPSO.java b/src/eva2/server/go/strategies/StarANPSO.java new file mode 100644 index 00000000..6d10a7fc --- /dev/null +++ b/src/eva2/server/go/strategies/StarANPSO.java @@ -0,0 +1,39 @@ +package eva2.server.go.strategies; + +import eva2.server.go.operators.paramcontrol.LinearParamAdaption; +import eva2.server.go.operators.paramcontrol.ParamAdaption; + +public class StarANPSO extends ANPSO { + private int defaultEvalCnt=10000; + + public StarANPSO() { + super(); + + NichePSO.starNPSO(this, defaultEvalCnt); + setMainSwarmAlgoType(getMainSwarm().getAlgoType().setSelectedTag("Inertness")); + getMainSwarm().setParameterControl(new ParamAdaption[]{new LinearParamAdaption("inertnessOrChi", 0.7, 0.2)}); +// setMainSwarmInertness(new LinearParameterAging(0.7, 0.2, defaultEvalCnt/getMainSwarmSize())); + + + getMainSwarm().setPhi1(1.2); + getMainSwarm().setPhi2(0.6); // ANPSO uses communication in the main swarm + //Possible topologies are: "Linear", "Grid", "Star", "Multi-Swarm", "Tree", "HPSO", "Random" in that order starting by 0. + SetMainSwarmTopologyTag(3); //"Multi-Swarm" favors the formation of groups in the main swarm + setMainSwarmTopologyRange(2); // range for topologies like random, grid etc. (does not affect "Multi-Swarm") + setMaxInitialSubSwarmSize(0); // deactivate early reinits + } + +// public void setEvaluationCount(int evalCnt) { +// setMainSwarmInertness(new LinearParameterAging(0.7, 0.2, evalCnt/getMainSwarmSize())); +// } + + public StarANPSO(StarANPSO o) { + super(o); + this.defaultEvalCnt=o.defaultEvalCnt; + } + + @Override + public String getName() { + return "Star-"+super.getName(); + } +}