package algorithm.topologie; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.TreeSet; import java.util.stream.Collectors; import algorithm.objectiveFunction.TopologieObjectiveFunction; import api.TopologieAlgorithmFramework; import ui.model.DecoratedState; import util.Random; public class PsoAlgorithm extends TopologieAlgorithmFramework { private int popsize = 20; private int maxGenerations = 500; private double dependency = 2.07; private double c1, c2, w; private double maxVelocity = 10.0; private double deviation = 0.5; //mutation private int mutationInterval = 1; private boolean useIntervalMutation = false; private double mutationRate = 0.005; private double mutateProbabilityInterval = 0.01; private double maxMutationPercent = 0.01; private boolean moreInformation = false; public PsoAlgorithm(){ addIntParameter("Swarmsize", popsize, intValue -> popsize = intValue, () -> popsize, 1); addIntParameter("Iterations", maxGenerations, intValue -> maxGenerations = intValue, () -> maxGenerations, 1); addSeperator(); addDoubleParameter("Deviation", deviation, doubleValue -> deviation = doubleValue, () -> deviation, 0); addDoubleParameter("Dependency", dependency, doubleValue -> dependency = doubleValue, () -> dependency, true, 2.001, 2.4); addDoubleParameter("Particle Max-Velocity", maxVelocity, doubleValue -> maxVelocity = doubleValue, () -> maxVelocity, 0.0); addSeperator(); addIntParameter("Mutation Frequency (Iteration)", mutationInterval, intValue -> mutationInterval = intValue, () -> mutationInterval, 0); addBooleanParameter("Use Interval Mutation", useIntervalMutation, booleanValue -> useIntervalMutation = booleanValue, Arrays.asList("Probability for Frequency Mutation", "Scope of Mutation"), Arrays.asList("Probability for Bit-wise Mutation")); addDoubleParameter("Probability for Frequency Mutation", mutateProbabilityInterval, doubleValue -> mutateProbabilityInterval = doubleValue, () -> mutateProbabilityInterval, useIntervalMutation, 0.0, 1.0); addDoubleParameter("Probability for Bit-wise Mutation", mutationRate, doubleValue -> mutationRate = doubleValue, () -> mutationRate, !useIntervalMutation, 0.0, 1.0); addDoubleParameter("Scope of Mutation", maxMutationPercent, doubleValue -> maxMutationPercent = doubleValue, () -> maxMutationPercent, useIntervalMutation, 0.0, 1.0); addSeperator(); addBooleanParameter("Print Auxiliary Information", moreInformation, booleanValue -> moreInformation = booleanValue, new LinkedList(), new LinkedList()); } public static double linearInterpolate(double first, double second, double alpha) { return first * (1.0 - alpha) + second * alpha; } public static double inverseLinearInterpolation(double min, double max, double value) { if (max - min == 0) return max; else return (value - min) / (max - min); } @Override protected double evaluateState(DecoratedState actualstate, int amountOfAddedSwitch, double addedCableMeters, boolean moreInformation) { return TopologieObjectiveFunction.getFitnessValueForState(actualstate, amountOfAddedSwitch, addedCableMeters, moreInformation); } @Override /** *

Algo from Paper:

	 *  
	 *  Begin
	 *  	t = 0; {t: generation index}
	 *  	initialize particles xp,i,j(t);
	 *  	evaluation xp,i,j(t);
	 *  	while (termination condition ≠ true) do
	 *  		vi,j(t) = update vi,j(t); {by Eq. (6)}
	 *  		xg,i,j(t) = update xg,i,j(t); {by Eq. (7)}
	 *  		xg,i,j(t) = mutation xg,i,j(t); {by Eq. (11)}
	 *  		xp,i,j(t) = decode xg,i,j(t); {by Eqs. (8) and (9)}
	 *  		evaluate xp,i,j(t);
	 *  		t = t + 1;
	 *  	end while
	 *  End
*

with:

* * xg,i,j: genotype ->genetic information -> in continuous space
* xp,i,j: phenotype -> observable characteristics-> in binary space
* Xg,max: is the Maximum here set to 4.
* Eq. (6):vi,j(t + 1) = wvi,j+c1R1(Pbest,i,j-xp,i,j(t))+c2R2(gbest,i,j-xp,i,j(t))
* Eq. (7):xg,i,j(t + 1) = xg,i,j(t) + vi,j(t + 1)
* Eq. (11):if(rand()<rmu)then xg,i,j(t + 1) = -xg,i,j(t + 1)
* Eq. (8):xp,i,j(t + 1) = (rand() < S(xg,i,j(t + 1))) ? 1 : 0
* Eq. (9) Sigmoid:S(xg,i,j(t + 1)) := 1/(1 + e-xg,i,j(t + 1))
*

Parameter:

* w inertia, calculated from phi(Variable:{@link #dependency})
* c1: influence, calculated from phi(Variable:{@link #dependency})
* c2: influence, calculated from phi(Variable:{@link #dependency})
* rmu: probability that the proposed operation is conducted defined by limit(Variable:{@link #limit})
* * */ protected Individual executeAlgo() { resetWildcards(); initDependentParameter(); Individual globalBest = new Individual(); globalBest.position = extractPositionAndAccess(); globalBest.fitness = evaluatePosition(globalBest.position); console.println("Start Value:" + globalBest.fitness); int dimensions = globalBest.position.size(); List swarm= initializeParticles(dimensions); List runList = new ArrayList(); runList.add(globalBest.fitness); evaluation(globalBest, swarm); runList.add(globalBest.fitness); for (int iteration = 0; iteration < this.maxGenerations ; iteration++) { int mutationAllowed = iteration % mutationInterval; double bitsFlipped = 0; for (int particleNumber = 0; particleNumber < this.popsize; particleNumber++) { Particle particle = swarm.get(particleNumber); if(this.useIntervalMutation) { boolean allowMutation = (Random.nextDouble() < this.mutateProbabilityInterval); TreeSet mutationLocationSet = null; if(allowMutation)mutationLocationSet = locationsToMutate(dimensions); for(int index = 0; index < dimensions; index++) { updateVelocity(particle, index, globalBest); updateGenotype(particle, index); if(allowMutation &&mutationAllowed == 0 && iteration != 0 && mutationLocationSet.contains(index))mutation(particle, index); decode(particle, index); } }else { int count = 0; for(int index = 0; index < dimensions; index++) { updateVelocity(particle, index, globalBest); updateGenotype(particle, index); if(mutationAllowed == 0 && iteration != 0 && Random.nextDouble() < mutationRate) { count++; mutation(particle, index); } decode(particle, index); } bitsFlipped += count; } } if(moreInformation) console.println("\t\t\t\t\t\tAvgBitsMutate: " + (bitsFlipped / (double)popsize)); if(cancel)return null; evaluation(globalBest, swarm); runList.add(globalBest.fitness); if(moreInformation) console.println("------------------------"); } console.println(" End Value:" + globalBest.fitness); this.runList = runList; return globalBest; } @Override protected int getProgressBarMaxCount() { return rounds * maxGenerations * popsize + 1; } @Override protected String algoInformationToPrint() { return "PsoAlgo"+ " Rounds:" + rounds + " maxIterations:" + maxGenerations + " swarmSize:" + popsize + " dependency:" + dependency + " mutationInterval:" + mutationInterval + " maxVelocity: " + maxVelocity + " deviation: " + deviation + (useIntervalMutation? (" mutateProbabilityInterval:" + mutateProbabilityInterval + " maxMutationPercent:" + maxMutationPercent) : " mutationRate:" + mutationRate); } @Override protected String plottFileName() { return "pso-topologie.txt"; } /** * * @param problemSize maximum index of position in the particle * @return */ private List initializeParticles(int problemSize) { List swarm = new ArrayList(); //Create The Particle for (int particleNumber = 0; particleNumber < popsize; particleNumber++){ //Create a Random position List aRandomPosition = new ArrayList(); for (int index = 0; index < problemSize; index++){ aRandomPosition.add(Random.nextIntegerInRange(0, this.getMaximumIndexObjects(index) + 1)); } swarm.add(new Particle(aRandomPosition)); } return swarm; } /** * Calculate w, c1, c2 */ private void initDependentParameter() { w = 1.0 / (dependency - 1 + Math.sqrt(dependency * dependency - 2 * dependency)); c1 = c2 = dependency * w; } /** * Evaluate each particle and update the global Best position; * @param globalBest * @param swarm */ private void evaluation(Individual globalBest, List swarm) { for(Particle p: swarm) { double localEvaluationValue = evaluatePosition(p.xPhenotype); if(moreInformation) console.println("Fitness " + localEvaluationValue); p.checkNewEvaluationValue(localEvaluationValue); if(localEvaluationValue < globalBest.fitness) { globalBest.fitness = localEvaluationValue; globalBest.position = p.localBest.position; } } } /** * Eq. (6):vi,j(t + 1) = wvi,j+c1R1(Pbest,i,j-xp,i,j(t))+c2R2(gbest,i,j-xp,i,j(t))
* @param particle * @param index * @param globalBest */ private void updateVelocity(Particle particle, int index, Individual globalBest) { double r1 = Random.nextDouble(); double r2 = Random.nextDouble(); double posValue = particle.xPhenotype.get(index); particle.velocity.set(index, clamp(w*particle.velocity.get(index) + c1*r1*((particle.localBest.position.get(index)) - posValue) + c2*r2*((globalBest.position.get(index))- posValue)) ); } /** * Eq. (7):xg,i,j(t + 1) = xg,i,j(t) + vi,j(t + 1)
* @param particle * @param index */ private void updateGenotype(Particle particle, int index) { particle.xGenotype.set(index, clamp(particle.xGenotype.get(index) + particle.velocity.get(index))); } /** * Eq. (11):if(rand()<rmu)then xg,i,j(t + 1) = -xg,i,j(t + 1)
* @param particle * @param index */ private void mutation(Particle particle, int index) { //if(Random.nextDouble() < limit) particle.xGenotype.set(index, -particle.xGenotype.get(index)); } /** * Eq. (8):xp,i,j(t + 1) = (rand() < S(xg,i,j(t + 1))) ? 1 : 0
* @param particle * @param index */ private void decode(Particle particle, int index) { double value = clamp(Random.nextGaussian(particle.xGenotype.get(index), deviation)); double alpha = inverseLinearInterpolation(-maxVelocity, +maxVelocity, value); double result = linearInterpolate(0, this.getMaximumIndexObjects(index), alpha); particle.xPhenotype.set(index, (int)Math.round(result)); } /** * To clamp Xg,j,i and vi,j in Range [-Xg,max|+Xg,max] with {Xg,max= 4} * @param value * @return */ private double clamp(double value) { return Math.max(-maxVelocity, Math.min(maxVelocity, value)); } private TreeSet locationsToMutate(int dimensions) { TreeSet mutationLocation = new TreeSet(); //sortedSet int maximumAmountOfMutatedBits = Math.max(1, (int)Math.round(((double) dimensions) * this.maxMutationPercent)); int randomUniformAmountOfMutatedValues = Random.nextIntegerInRange(1,maximumAmountOfMutatedBits + 1); for(int i = 0; i< randomUniformAmountOfMutatedValues; i++) { boolean success = mutationLocation.add(Random.nextIntegerInRange(0, dimensions)); if(!success) i--; //can be add up to some series long loops if maximumAmountOfMutatedBits get closed to problemsize. } return mutationLocation; } /** * Class to represent a Particle. */ private class Particle{ /** * The velocity of a particle. */ public List velocity; /** * The positions genotype. */ public List xGenotype; /** * The positions phenotype. Alias the current position. */ public List xPhenotype; public Individual localBest; Particle(List position){ this.xPhenotype = position; //Init velocity, xGenotype with 0.0 values. this.velocity = position.stream().map(bool -> 0.0).collect(Collectors.toList()); this.xGenotype = position.stream().map(bool -> 0.0).collect(Collectors.toList()); localBest = new Individual(); localBest.fitness = Double.MAX_VALUE; } public void checkNewEvaluationValue(double newEvaluationValue) { if(newEvaluationValue < localBest.fitness) { localBest.fitness = newEvaluationValue; localBest.position = xPhenotype.stream().collect(Collectors.toList()); } } public String toString() { return "Particle with xPhenotype(Position), xGenotype, velocity:[" + listToString(xPhenotype) + "],[" + listToString(xGenotype) + "],[" + listToString(velocity) + "]"; } private String listToString(List list) { return list.stream().map(Object::toString).collect(Collectors.joining(", ")); } } }