From 7a6c814a56502f997d106f5c69091aac714e392d Mon Sep 17 00:00:00 2001 From: Alexander Seitz Date: Wed, 19 Dec 2012 13:52:31 +0000 Subject: [PATCH] Implemented the LTGA, there are still some errors with this optimizer --- src/eva2/server/go/strategies/LTGA.java | 397 ++++++++++++++++++++++++ 1 file changed, 397 insertions(+) create mode 100644 src/eva2/server/go/strategies/LTGA.java diff --git a/src/eva2/server/go/strategies/LTGA.java b/src/eva2/server/go/strategies/LTGA.java new file mode 100644 index 00000000..b10fdc9c --- /dev/null +++ b/src/eva2/server/go/strategies/LTGA.java @@ -0,0 +1,397 @@ +package eva2.server.go.strategies; + +import java.util.BitSet; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; + +import eva2.gui.BeanInspector; +import eva2.server.go.InterfacePopulationChangedEventListener; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.individuals.InterfaceDataTypeBinary; +import eva2.server.go.individuals.InterfaceGAIndividual; +import eva2.server.go.populations.InterfaceSolutionSet; +import eva2.server.go.populations.Population; +import eva2.server.go.populations.SolutionSet; +import eva2.server.go.problems.AbstractOptimizationProblem; +import eva2.server.go.problems.BKnapsackProblem; +import eva2.server.go.problems.InterfaceOptimizationProblem; +import eva2.tools.Pair; +import eva2.tools.math.SpecialFunction; + +public class LTGA implements InterfaceOptimizer, java.io.Serializable, InterfacePopulationChangedEventListener{ + + private static final Logger LOGGER = Logger.getLogger(BOA.class.getName()); + transient private InterfacePopulationChangedEventListener m_Listener = null; + private String m_Identifier = "LTGA"; + + private int probDim = 8; + private int fitCrit = -1; + private int popSize = 50; + private Population population = new Population(); + private AbstractOptimizationProblem problem = new BKnapsackProblem(); + private AbstractEAIndividual template = null; + private int generationCycle = 500; + + public LTGA(){ + } + + public LTGA(LTGA l){ + this.m_Listener = l.m_Listener; + this.m_Identifier = l.m_Identifier; + this.probDim = l.probDim; + this.popSize = l.popSize; + this.population = (Population)l.population.clone(); + this.problem = (AbstractOptimizationProblem)l.problem.clone(); + this.template = (AbstractEAIndividual) template.clone(); + } + + public Object clone() { + return new LTGA(this); + } + + @Override + public String getName() { + return "Linkage Tree Genetic Algorithm"; + } + + public static String globalInfo() { + return "Basic implementation of the Linkage Tree Genetic Algorithm based on the works by Dirk Thierens."; + } + + @Override + public void addPopulationChangedEventListener( + InterfacePopulationChangedEventListener ea) { + this.m_Listener = ea; + + } + + @Override + public boolean removePopulationChangedEventListener( + InterfacePopulationChangedEventListener ea) { + if (m_Listener == ea) { + m_Listener = null; + return true; + } else + return false; + } + + private void defaultInit(){ + if (population == null) { + this.population = new Population(this.popSize); + } else { + this.population.setTargetPopSize(this.popSize); + } + this.template = this.problem.getIndividualTemplate(); + if (!(template instanceof InterfaceDataTypeBinary)) { + LOGGER.log(Level.WARNING, "Requiring binary data!"); + } else { + Object dim = BeanInspector.callIfAvailable(problem, + "getProblemDimension", null); + if (dim == null) + LOGGER.log(Level.WARNING, "Coudn't get problem dimension!"); + probDim = (Integer) dim; + ((InterfaceDataTypeBinary) this.template).SetBinaryGenotype(new BitSet(probDim)); + } + this.population.addPopulationChangedEventListener(this); + this.population.setNotifyEvalInterval(this.generationCycle); + } + + private static BitSet getBinaryData(AbstractEAIndividual indy) { + if (indy instanceof InterfaceGAIndividual) + return ((InterfaceGAIndividual) indy).getBGenotype(); + else if (indy instanceof InterfaceDataTypeBinary) + return ((InterfaceDataTypeBinary) indy).getBinaryData(); + else { + throw new RuntimeException( + "Unable to get binary representation for " + + indy.getClass()); + } + } + + @Override + public void init() { + defaultInit(); + this.problem.initPopulation(this.population); + this.evaluatePopulation(this.population); + this.firePropertyChangedEvent(Population.nextGenerationPerformed); + } + + private void evaluatePopulation(Population pop) { + for (int i = 0; i < pop.size(); i++) { + evaluate(pop.getEAIndividual(i)); + } + } + + /** + * evaluate the given Individual and increments the counter. if the + * individual is null, only the counter is incremented + * + * @param indy + * the individual you want to evaluate + */ + private void evaluate(AbstractEAIndividual indy) { + // evaluate the given individual if it is not null + if (indy == null) { + LOGGER.log(Level.WARNING, "tried to evaluate null"); + return; + } + this.problem.evaluate(indy); + // increment the number of evaluations + this.population.incrFunctionCalls(); + } + + @Override + public void initByPopulation(Population pop, boolean reset) { + if (reset) { + init(); + } else { + defaultInit(); + this.population = pop; + } + } + + private Stack> buildLinkageTree(){ + // the final tree + Stack> linkageTree = new Stack>(); + // the stack to cluster here clusters can be removed + Stack> workingStack = new Stack>(); + // add the problem variables to the stacks + for(int i=0; i s1 = new HashSet(); + Set s2 = new HashSet(); + s1.add(i); + s2.add(i); + linkageTree.add(s1); + workingStack.add(s2); + } +// double[] probMass = calculateProbabilityMassFunction(); + // until there is only one cluster left + while(workingStack.size()>1){ + Pair, Set> toCluster = findNearestClusters(workingStack); + // remove the second cluster from the working set + workingStack.remove(toCluster.tail); + // add all elements from the second cluster to the first one + toCluster.head.addAll(toCluster.tail); + // add the combined cluster to the linkage tree + linkageTree.add(toCluster.head); + } + return linkageTree; + } + + private Pair, Set> findNearestClusters(Stack> stack) { + Set bestI = new HashSet(); + Set bestJ = new HashSet(); + double bestScore = Double.MAX_VALUE; + for(int i=0; i s1 = stack.get(i); + for(int j=i+1; j s2 = stack.get(j); + double currDist = calculateDistance(s1, s2); + // better cluster found + if(currDist < bestScore){ + bestI = s1; + bestJ = s2; + bestScore = currDist; + } + } + } + // return the best pair + return new Pair, Set>(bestI, bestJ); + } + + private double calculateDistance(Set s1, Set s2) { + double entropy1 = calculateEntropy(s1); + double entropy2 = calculateEntropy(s2); + Set combined = new HashSet(); + combined.addAll(s1); + combined.addAll(s2); + double entropy3 = calculateEntropy(combined); + return 2 - ((entropy1 + entropy2) / (entropy3)); + } + + private double calculateEntropy(Set s){ + double entropy = 0.0; + // for possible states {0,1} do + for(int i=0; i<=1; i++){ + int count = 0; + // for every individual + for(int k=0; k> linkageTree = buildLinkageTree(); + Population newPop = new Population(this.popSize); + for(int i=0; i<(this.popSize/2); i++){ + Population indies = this.population.getRandNIndividuals(2); + Population newIndies = buildNewIndies(indies, linkageTree); + newPop.addAll(newIndies); + } + this.population.clear(); + this.population.addAll(newPop); + this.problem.evaluatePopulationEnd(this.population); + } + + private Population buildNewIndies(Population indies, + Stack> linkageTree) { + if(indies.size() != 2){ + return indies; + } + AbstractEAIndividual indy1 = indies.getEAIndividual(0); + AbstractEAIndividual indy2 = indies.getEAIndividual(1); + BitSet gen1 = getBinaryData(indy1); + BitSet gen2 = getBinaryData(indy2); + for(Set mask: linkageTree){ + BitSet newGene1 = (BitSet) gen1.clone(); + BitSet newGene2 = (BitSet) gen2.clone(); + boolean same = true; + for(Integer exchange: mask){ + if(newGene1.get(exchange) != newGene2.get(exchange)){ + same = false; + } + newGene1.set(exchange, gen2.get(exchange)); + newGene2.set(exchange, gen1.get(exchange)); + } + if(!same){ + AbstractEAIndividual newIndy1 = (AbstractEAIndividual) this.template.clone(); + AbstractEAIndividual newIndy2 = (AbstractEAIndividual) this.template.clone(); + ((InterfaceDataTypeBinary) newIndy1).SetBinaryGenotype(newGene1); + ((InterfaceDataTypeBinary) newIndy2).SetBinaryGenotype(newGene2); + evaluate(newIndy1); + evaluate(newIndy2); + if(Math.min(newIndy1.getFitness(0), newIndy2.getFitness(0)) < Math.min(indy1.getFitness(0), indy2.getFitness(0))){ + indy1 = newIndy1; + indy2 = newIndy2; + } + } + } + Population result = new Population(2); + result.add(indy1); + result.add(indy2); + return result; + } + + /** + * Something has changed + */ + protected void firePropertyChangedEvent(String name) { + if (this.m_Listener != null) + this.m_Listener.registerPopulationStateChanged(this, name); + } + + @Override + public Population getPopulation() { + return this.population; + } + + @Override + public void setPopulation(Population pop) { + this.population = pop; + } + + @Override + public InterfaceSolutionSet getAllSolutions() { + return new SolutionSet(this.population); + } + + @Override + public void SetIdentifier(String name) { + this.m_Identifier = name; + } + + @Override + public String getIdentifier() { + return this.m_Identifier; + } + + @Override + public void SetProblem(InterfaceOptimizationProblem problem) { + this.problem = (AbstractOptimizationProblem) problem; + } + + @Override + public InterfaceOptimizationProblem getProblem() { + return this.problem; + } + + @Override + public String getStringRepresentation() { + return "Linkage Tree GA"; + } + + @Override + public void freeWilly() { + + } + + @SuppressWarnings("deprecation") + @Override + public void registerPopulationStateChanged(Object source, String name) { + // The events of the interim hill climbing population will be caught here + if (name.compareTo(Population.funCallIntervalReached) == 0) { + // set funcalls to real value + this.population.SetFunctionCalls(((Population)source).getFunctionCalls()); + this.firePropertyChangedEvent(Population.nextGenerationPerformed); + } + } + + public static void main(String[] args) { + LTGA ltga = new LTGA(); + ltga.init(); + ltga.optimize(); + System.out.println(ltga.popSize); + Population p = ltga.getPopulation(); + System.out.println(p.getFunctionCalls()+"\t"+p.size()); + System.out.println(p.getBestEAIndividual().getStringRepresentation()); + ltga.optimize(); + p = ltga.getPopulation(); + System.out.println(p.getFunctionCalls()+"\t"+p.size()); + System.out.println(p.getBestEAIndividual().getStringRepresentation()); + ltga.optimize(); + p = ltga.getPopulation(); + System.out.println(p.getFunctionCalls()+"\t"+p.size()); + System.out.println(p.getBestEAIndividual().getStringRepresentation()); + ltga.optimize(); + p = ltga.getPopulation(); + System.out.println(p.getFunctionCalls()+"\t"+p.size()); + System.out.println(p.getBestEAIndividual().getStringRepresentation()); + ltga.optimize(); + p = ltga.getPopulation(); + System.out.println(p.getFunctionCalls()+"\t"+p.size()); + System.out.println(p.getBestEAIndividual().getStringRepresentation()); + ltga.optimize(); + p = ltga.getPopulation(); + System.out.println(p.getFunctionCalls()+"\t"+p.size()); + System.out.println(p.getBestEAIndividual().getStringRepresentation()); + ltga.optimize(); + p = ltga.getPopulation(); + System.out.println(p.getFunctionCalls()+"\t"+p.size()); + System.out.println(p.getBestEAIndividual().getStringRepresentation()); + } + +}