package ec.pso ;

import ec.* ;
import ec.vector.*;
import ec.util.*;
import java.util.* ;
import java.io.*;

/*
 * Particle.java
 * Created: Thu May  2 17:09:40 EDT 2013
 */

/**
 * Particle is a DoubleVectorIndividual with additional statistical information
 * necessary to perform Particle Swarm Optimization.  Specifically, it has a 
 * VELOCITY, a NEIGHBORHOOD of indexes of individuals, a NEIGHBORHOOD BEST genome
 * and fitness, and a PERSONAL BEST genome and fitness.  These elements, plus the
 * GLOBAL BEST genome and fitness found in PSOBreeder, are used to collectively
 * update the particle's location in space.
 *
 * 

Particle updates its location in two steps. First, it gathers current * neighborhood and personal best statistics via the update(...) method. Then * it updates the particle's velocity and location (genome) according to these * statistics in the tweak(...) method. Notice that neither of these methods is * the defaultMutate(...) method used in DoubleVectorIndividual: this means that * in *theory* you could rig up Particles to also be mutated if you thought that * was a good reason. * *

Many of the parameters passed into the tweak(...) method are based on * weights determined by the PSOBreeder. * * @author Khaled Ahsan Talukder */ public class Particle extends DoubleVectorIndividual { public static final String AUXILLARY_PREAMBLE = "Auxillary: "; // my velocity public double[] velocity ; // the individuals in my neighborhood public int[] neighborhood = null ; // the best genome and fitness members of my neighborhood ever achieved public double[] neighborhoodBestGenome = null; public Fitness neighborhoodBestFitness = null; // the best genome and fitness *I* personally ever achieved public double[] personalBestGenome = null; public Fitness personalBestFitness = null; public int hashCode() { int hash = super.hashCode(); // no need to change anything I think return hash; } public boolean equals(Object ind) { if (!super.equals(ind)) return false; Particle i = (Particle) ind; if ((velocity == null && i.velocity != null) || (velocity != null && i.velocity == null)) return false; if (velocity != null) { if (velocity.length != i.velocity.length) return false; for (int j = 0; j < velocity.length; j++) if (velocity[j] != i.velocity[j]) return false; } if ((neighborhood == null && i.neighborhood != null) || (neighborhood != null && i.neighborhood == null)) return false; if (neighborhood != null) { if (neighborhood.length != i.neighborhood.length) return false; for (int j = 0; j < neighborhood.length; j++) if (neighborhood[j] != i.neighborhood[j]) return false; } if ((neighborhoodBestGenome == null && i.neighborhoodBestGenome != null) || (neighborhoodBestGenome != null && i.neighborhoodBestGenome == null)) return false; if (neighborhoodBestGenome != null) { if (neighborhoodBestGenome.length != i.neighborhoodBestGenome.length) return false; for (int j = 0; j < neighborhoodBestGenome.length; j++) if (neighborhoodBestGenome[j] != i.neighborhoodBestGenome[j]) return false; } if ((neighborhoodBestFitness == null && i.neighborhoodBestFitness != null) || (neighborhoodBestFitness != null && i.neighborhoodBestFitness == null)) return false; if (neighborhoodBestFitness != null) { if (!neighborhoodBestFitness.equals(i.neighborhoodBestFitness)) return false; } if ((personalBestGenome == null && i.personalBestGenome != null) || (personalBestGenome != null && i.personalBestGenome == null)) return false; if (personalBestGenome != null) { if (personalBestGenome.length != i.personalBestGenome.length) return false; for (int j = 0; j < personalBestGenome.length; j++) if (personalBestGenome[j] != i.personalBestGenome[j]) return false; } if ((personalBestFitness == null && i.personalBestFitness != null) || (personalBestFitness != null && i.personalBestFitness == null)) return false; if (personalBestFitness != null) { if (!personalBestFitness.equals(i.personalBestFitness)) return false; } return true; } public void setup(final EvolutionState state, final Parameter base) { super.setup(state, base); velocity = new double[genome.length] ; } public Object clone() { Particle myobj = (Particle) (super.clone()); // must clone the velocity and neighborhood pattern if they exist if (velocity != null) velocity = (double[])(velocity.clone()); if (neighborhood != null) neighborhood = (int[])(neighborhood.clone()); return myobj; } public void update(final EvolutionState state, int subpop, int myindex, int thread) { // update personal best if (personalBestFitness == null || fitness.betterThan(personalBestFitness)) { personalBestFitness = (Fitness)(fitness.clone()); personalBestGenome = (double[])(genome.clone()); } // initialize neighborhood if it's not been created yet PSOBreeder psob = (PSOBreeder)(state.breeder); if (neighborhood == null || psob.neighborhood == psob.C_NEIGHBORHOOD_RANDOM_EACH_TIME) { if (psob.neighborhood == psob.C_NEIGHBORHOOD_RANDOM) // "random" scheme is the only thing that is available for now neighborhood = createRandomPattern(myindex, psob.includeSelf, state.population.subpops[subpop].individuals.length, psob.neighborhoodSize, state, thread); else if (psob.neighborhood == psob.C_NEIGHBORHOOD_TOROIDAL || psob.neighborhood == psob.C_NEIGHBORHOOD_RANDOM_EACH_TIME) neighborhood = createToroidalPattern(myindex, psob.includeSelf, state.population.subpops[subpop].individuals.length, psob.neighborhoodSize); else // huh? state.output.fatal("internal error: invalid PSO neighborhood style: " + psob.neighborhood); } // identify neighborhood best neighborhoodBestFitness = fitness; // initially me neighborhoodBestGenome = genome; for(int i = 0 ; i < neighborhood.length ; i++) { int ind = neighborhood[i] ; if (state.population.subpops[subpop].individuals[ind].fitness.betterThan(fitness)) { neighborhoodBestFitness = state.population.subpops[subpop].individuals[ind].fitness; neighborhoodBestGenome = ((DoubleVectorIndividual)(state.population.subpops[subpop].individuals[ind])).genome; } } // clone neighborhood best neighborhoodBestFitness = (Fitness)(neighborhoodBestFitness.clone()); neighborhoodBestGenome = (double[])(neighborhoodBestGenome.clone()); } // velocityCoeff: cognitive/confidence coefficient for the velocity // personalCoeff: cognitive/confidence coefficient for self // informantCoeff: cognitive/confidence coefficient for informants/neighbours // globalCoeff: cognitive/confidence coefficient for global best, this is not done in the standard PSO public void tweak( EvolutionState state, double[] globalBest, double velocityCoeff, double personalCoeff, double informantCoeff, double globalCoeff, int thread) { for(int x = 0 ; x < genomeLength() ; x++) { double xCurrent = genome[x] ; double xPersonal = personalBestGenome[x] ; double xNeighbour = neighborhoodBestGenome[x] ; double xGlobal = globalBest[x] ; double beta = state.random[thread].nextDouble() * personalCoeff ; double gamma = state.random[thread].nextDouble() * informantCoeff ; double delta = state.random[thread].nextDouble() * globalCoeff ; double newVelocity = (velocityCoeff * velocity[x]) + (beta * (xPersonal - xCurrent)) + (gamma * (xNeighbour - xCurrent)) + (delta * (xGlobal - xCurrent)) ; velocity[x] = newVelocity ; genome[x] += newVelocity ; } evaluated = false ; // printIndividual(state, 0); } // Creates a toroidal neighborhood pattern for the individual int[] createRandomPattern(int myIndex, boolean includeSelf, int popsize, int neighborhoodSize, EvolutionState state, int threadnum) { MersenneTwisterFast mtf = state.random[threadnum]; HashSet already = new HashSet(); int[] neighbors = null; if (includeSelf) { neighbors = new int[neighborhoodSize + 1]; neighbors[neighborhoodSize] = myIndex; // put me at the top already.add(Integer.valueOf(myIndex)); } else neighbors = new int[neighborhoodSize]; Integer n = null; for(int i = 0; i < neighborhoodSize; i++) { do { neighbors[i] = mtf.nextInt(popsize); n = Integer.valueOf(neighbors[i]); } while (already.contains(n)); already.add(n); } return neighbors; } // Creates a toroidal neighborhood pattern for the individual indexed by 'myindex' int[] createToroidalPattern(int myindex, boolean includeSelf, int popsize, int neighborhoodSize) { int[] neighbors = null; if (includeSelf) { neighbors = new int[neighborhoodSize + 1]; neighbors[neighborhoodSize] = myindex; // put me at the top } else neighbors = new int[neighborhoodSize]; int pos = 0; for(int i = myindex - neighborhoodSize / 2; i < myindex; i++) { neighbors[pos++] = ((i % popsize) + popsize) % popsize; } for(int i = myindex + 1; i < neighborhoodSize - (neighborhoodSize / 2) + 1; i++) { neighbors[pos++] = ((i % popsize) + popsize) % popsize; } return neighbors; } /// The following methods handle modifying the auxillary data when the /// genome is messed around with. void resetAuxillaryInformation() { neighborhood = null; neighborhoodBestGenome = null; neighborhoodBestFitness = null; personalBestGenome = null; personalBestFitness = null; for(int i = 0; i < velocity.length; i++) velocity[i] = 0.0; } public void reset(EvolutionState state, int thread) { super.reset(state, thread); if (genome.length != velocity.length) velocity = new double[genome.length]; resetAuxillaryInformation(); } // This would be exceptionally weird to use in a PSO context, but for // consistency's sake... public void setGenomeLength(int len) { super.setGenomeLength(len); // we always reset regardless of whether the length is the same if (genome.length != velocity.length) velocity = new double[genome.length]; resetAuxillaryInformation(); } // This would be exceptionally weird to use in a PSO context, but for // consistency's sake... public void setGenome(Object gen) { super.setGenome(gen); // we always reset regardless of whether the length is the same if (genome.length != velocity.length) velocity = new double[genome.length]; resetAuxillaryInformation(); } // This would be exceptionally weird to use in a PSO context, but for // consistency's sake... public void join(Object[] pieces) { super.join(pieces); // we always reset regardless of whether the length is the same if (genome.length != velocity.length) velocity = new double[genome.length]; resetAuxillaryInformation(); } /// gunk for reading and writing, but trying to preserve some of the /// auxillary information StringBuilder encodeAuxillary() { StringBuilder s = new StringBuilder(); s.append(AUXILLARY_PREAMBLE); s.append(Code.encode(true)); s.append(Code.encode(neighborhood!=null)); s.append(Code.encode(neighborhoodBestGenome != null)); s.append(Code.encode(neighborhoodBestFitness != null)); s.append(Code.encode(personalBestGenome != null)); s.append(Code.encode(personalBestFitness != null)); s.append("\n"); // velocity s.append(Code.encode(velocity.length)); for(int i = 0; i < velocity.length; i++) s.append(Code.encode(velocity[i])); s.append("\n"); // neighborhood if (neighborhood != null) { s.append(Code.encode(neighborhood.length)); for(int i = 0; i < neighborhood.length; i++) s.append(Code.encode(neighborhood[i])); s.append("\n"); } // neighborhood best if (neighborhoodBestGenome != null) { s.append(Code.encode(neighborhoodBestGenome.length)); for(int i = 0; i < neighborhoodBestGenome.length; i++) s.append(Code.encode(neighborhoodBestGenome[i])); s.append("\n"); } if (neighborhoodBestFitness != null) s.append(neighborhoodBestFitness.fitnessToString()); // personal best if (personalBestGenome != null) { s.append(Code.encode(personalBestGenome.length)); for(int i = 0; i < personalBestGenome.length; i++) s.append(Code.encode(personalBestGenome[i])); s.append("\n"); } if (personalBestFitness != null) s.append(personalBestFitness.fitnessToString()); s.append("\n"); return s; } public void printIndividual(final EvolutionState state, final int log) { super.printIndividual(state, log); state.output.println(encodeAuxillary().toString(), log); } public void printIndividual(final EvolutionState state, final PrintWriter writer) { super.printIndividual(state, writer); writer.println(encodeAuxillary().toString()); } public void readIndividual(final EvolutionState state, final LineNumberReader reader) throws IOException { super.readIndividual(state, reader); // Next, read auxillary header. DecodeReturn d = new DecodeReturn(Code.readStringWithPreamble(AUXILLARY_PREAMBLE, state, reader)); Code.decode(d); if (d.type != DecodeReturn.T_BOOLEAN) state.output.fatal("Line " + d.lineNumber + " should have six boolean values but seems to have fewer."); boolean v = (d.l != 0); Code.decode(d); if (d.type != DecodeReturn.T_BOOLEAN) state.output.fatal("Line " + d.lineNumber + " should have six boolean values but seems to have fewer."); boolean n = (d.l != 0); Code.decode(d); if (d.type != DecodeReturn.T_BOOLEAN) state.output.fatal("Line " + d.lineNumber + " should have six boolean values but seems to have fewer."); boolean nb = (d.l != 0); Code.decode(d); if (d.type != DecodeReturn.T_BOOLEAN) state.output.fatal("Line " + d.lineNumber + " should have six boolean values but seems to have fewer."); boolean nbf = (d.l != 0); Code.decode(d); if (d.type != DecodeReturn.T_BOOLEAN) state.output.fatal("Line " + d.lineNumber + " should have six boolean values but seems to have fewer."); boolean pb = (d.l != 0); Code.decode(d); if (d.type != DecodeReturn.T_BOOLEAN) state.output.fatal("Line " + d.lineNumber + " should have six boolean values but seems to have fewer."); boolean pbf = (d.l != 0); // Next, read auxillary arrays. if (v) { String s = reader.readLine(); d = new DecodeReturn(s); Code.decode(d); if (d.type != DecodeReturn.T_INT) state.output.fatal("Velocity length missing."); velocity = new double[(int)(d.l)]; for(int i = 0; i < velocity.length; i++) { Code.decode(d); if (d.type != DecodeReturn.T_DOUBLE) state.output.fatal("Velocity information not long enough"); velocity[i] = d.d; } } else velocity = new double[genome.length]; if (n) { String s = reader.readLine(); d = new DecodeReturn(s); Code.decode(d); if (d.type != DecodeReturn.T_INT) state.output.fatal("Neighborhood length missing."); neighborhood = new int[(int)(d.l)]; for(int i = 0; i < neighborhood.length; i++) { Code.decode(d); if (d.type != DecodeReturn.T_INT) state.output.fatal("Neighborhood information not long enough"); neighborhood[i] = (int)(d.l); } } else neighborhood = null; if (nb) { String s = reader.readLine(); d = new DecodeReturn(s); Code.decode(d); if (d.type != DecodeReturn.T_INT) state.output.fatal("Neighborhood-Best length missing."); neighborhoodBestGenome = new double[(int)(d.l)]; for(int i = 0; i < neighborhoodBestGenome.length; i++) { Code.decode(d); if (d.type != DecodeReturn.T_DOUBLE) state.output.fatal("Neighborhood-Best genome not long enough"); neighborhoodBestGenome[i] = d.d; } } else neighborhoodBestGenome = null; if (nbf) { // here we don't know what kind of fitness it is. So we'll do our best and guess // that it's the same fitness as our own Particle neighborhoodBestFitness = (Fitness)(fitness.clone()); neighborhoodBestFitness.readFitness(state, reader); } if (pb) { String s = reader.readLine(); d = new DecodeReturn(s); Code.decode(d); if (d.type != DecodeReturn.T_INT) state.output.fatal("Personal-Best length missing."); personalBestGenome = new double[(int)(d.l)]; for(int i = 0; i < personalBestGenome.length; i++) { Code.decode(d); if (d.type != DecodeReturn.T_DOUBLE) state.output.fatal("Personal-Best genome not long enough"); personalBestGenome[i] = d.d; } } else personalBestGenome = null; if (pbf) { // here we don't know what kind of fitness it is. So we'll do our best and guess // that it's the same fitness as our own Particle personalBestFitness = (Fitness)(fitness.clone()); personalBestFitness.readFitness(state, reader); } } public void writeIndividual(final EvolutionState state, final DataOutput dataOutput) throws IOException { super.writeIndividual(state, dataOutput); if (velocity != null) // it's always non-null { dataOutput.writeBoolean(true); dataOutput.writeInt(velocity.length); for(int i = 0; i < velocity.length; i++) dataOutput.writeDouble(velocity[i]); } else dataOutput.writeBoolean(false); // this will never happen if (neighborhood != null) { dataOutput.writeBoolean(true); dataOutput.writeInt(neighborhood.length); for(int i = 0; i < neighborhood.length; i++) dataOutput.writeDouble(neighborhood[i]); } else dataOutput.writeBoolean(false); if (neighborhoodBestGenome != null) { dataOutput.writeBoolean(true); dataOutput.writeInt(neighborhoodBestGenome.length); for(int i = 0; i < neighborhoodBestGenome.length; i++) dataOutput.writeDouble(neighborhoodBestGenome[i]); } else dataOutput.writeBoolean(false); if (neighborhoodBestFitness != null) { dataOutput.writeBoolean(true); neighborhoodBestFitness.writeFitness(state, dataOutput); } else dataOutput.writeBoolean(false); if (personalBestGenome != null) // it's always non-null { dataOutput.writeBoolean(true); dataOutput.writeInt(personalBestGenome.length); for(int i = 0; i < personalBestGenome.length; i++) dataOutput.writeDouble(personalBestGenome[i]); } else dataOutput.writeBoolean(false); if (personalBestFitness != null) { dataOutput.writeBoolean(true); personalBestFitness.writeFitness(state, dataOutput); } else dataOutput.writeBoolean(false); } public void readIndividual(final EvolutionState state, final DataInput dataInput) throws IOException { super.readIndividual(state, dataInput); // Next, read auxillary arrays. if (dataInput.readBoolean()) { velocity = new double[dataInput.readInt()]; for(int i = 0; i < velocity.length; i++) velocity[i] = dataInput.readDouble(); } else velocity = new double[genome.length]; if (dataInput.readBoolean()) { neighborhood = new int[dataInput.readInt()]; for(int i = 0; i < neighborhood.length; i++) neighborhood[i] = dataInput.readInt(); } else neighborhood = null; if (dataInput.readBoolean()) { neighborhoodBestGenome = new double[dataInput.readInt()]; for(int i = 0; i < neighborhoodBestGenome.length; i++) neighborhoodBestGenome[i] = dataInput.readDouble(); } else neighborhoodBestGenome = null; if (dataInput.readBoolean()) { neighborhoodBestFitness = (Fitness)(fitness.clone()); neighborhoodBestFitness.readFitness(state, dataInput); } if (dataInput.readBoolean()) { personalBestGenome = new double[dataInput.readInt()]; for(int i = 0; i < personalBestGenome.length; i++) personalBestGenome[i] = dataInput.readDouble(); } else personalBestGenome = null; if (dataInput.readBoolean()) { personalBestFitness = (Fitness)(fitness.clone()); personalBestFitness.readFitness(state, dataInput); } } }

Ads help maintain this website.