diff --git a/src/eva2/server/go/operators/crossover/AdaptiveCrossoverEAMixer.java b/src/eva2/server/go/operators/crossover/AdaptiveCrossoverEAMixer.java new file mode 100644 index 00000000..d0238af4 --- /dev/null +++ b/src/eva2/server/go/operators/crossover/AdaptiveCrossoverEAMixer.java @@ -0,0 +1,104 @@ +package eva2.server.go.operators.crossover; + +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.operators.mutation.InterfaceAdaptOperatorGenerational; +import eva2.server.go.populations.Population; +import eva2.server.go.problems.InterfaceOptimizationProblem; + +/** + * A modified version of the CrossoverEAMixer that adapts the weights with which the crossover-methods are chosen + * + * @author Alex + * + */ +public class AdaptiveCrossoverEAMixer extends CrossoverEAMixer implements InterfaceAdaptOperatorGenerational { + + private Population pop = new Population(); + private boolean initialized = false; + private double lastFitness = Double.MAX_VALUE; + private int[] used; + private InterfaceOptimizationProblem opt; + + public AdaptiveCrossoverEAMixer(){ + super(); + } + + public AdaptiveCrossoverEAMixer(AdaptiveCrossoverEAMixer mutator) { + super(mutator); + this.pop = (Population) mutator.pop.clone(); // TODO !Make a deep copy!? + this.initialized = mutator.initialized; + this.lastFitness = mutator.lastFitness; + this.used = mutator.used; + this.opt = mutator.opt; + } + + /** + * Create a mutation mixer with equal weights of the given mutation operators. + * @param mutators + */ + public AdaptiveCrossoverEAMixer(InterfaceCrossover ... crossovers) { + this.m_Crossers = new PropertyCrossoverMixer(crossovers); + this.m_Crossers.m_SelectedTargets = m_Crossers.m_AvailableTargets.clone(); + } + + @Override + protected void maybeAdaptWeights(AbstractEAIndividual[] indies) { + if(initialized){ + AbstractEAIndividual indy = indies[0]; + this.opt.evaluate(indy); + this.pop.incrFunctionCalls(); + if(indy.getFitness(0)0); + if(indy1 instanceof InterfaceDataTypeBinary && partners.getEAIndividual(0) instanceof InterfaceDataTypeBinary){ + BitSet data = ((InterfaceDataTypeBinary) indy1).getBinaryData(); + BitSet dataSave = (BitSet) data.clone(); + BitSet data2 = ((InterfaceDataTypeBinary) partners.getEAIndividual(0)).getBinaryData(); + double f1 = indy1.getFitness(0); + double f2 = partners.getEAIndividual(0).getFitness(0); + double min = Math.min(f1, f2); + int different = 0; + boolean foundBetter = false; + for(int i=0; i 0){ + dataSave.flip(i); + } + } + } + ((InterfaceDataTypeBinary) indy1).SetBinaryGenotype(data); + } + result[0] = indy1; + return result; + } + + public void init(AbstractEAIndividual individual, + InterfaceOptimizationProblem opt) { + this.m_OptimizationProblem = opt; + } + + public String getStringRepresentation() { + return getName(); + } + + public int getEvaluations(){ + return this.evaluations; + } + + /***************************************************** + * GUI + */ + + public String getName(){ + return "Combination Method 7"; + } + + public static String globalInfo() { + //TODO + return ""; + } + + public void resetEvaluations() { + this.evaluations = 0; + } + +} diff --git a/src/eva2/server/go/operators/crossover/InterfaceEvaluatingCrossoverOperator.java b/src/eva2/server/go/operators/crossover/InterfaceEvaluatingCrossoverOperator.java new file mode 100644 index 00000000..ad1da21d --- /dev/null +++ b/src/eva2/server/go/operators/crossover/InterfaceEvaluatingCrossoverOperator.java @@ -0,0 +1,13 @@ +package eva2.server.go.operators.crossover; + + +public interface InterfaceEvaluatingCrossoverOperator extends InterfaceCrossover { + /** + * Retrieve the number of evaluations performed during crossover. + * + * @return + */ + public int getEvaluations(); + + public void resetEvaluations(); +} diff --git a/src/eva2/server/go/strategies/BOA.java b/src/eva2/server/go/strategies/BOA.java new file mode 100644 index 00000000..6b852a9f --- /dev/null +++ b/src/eva2/server/go/strategies/BOA.java @@ -0,0 +1,522 @@ +package eva2.server.go.strategies; + +import java.util.BitSet; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +import eva2.gui.BeanInspector; +import eva2.gui.GenericObjectEditor; +import eva2.server.go.InterfacePopulationChangedEventListener; +import eva2.server.go.individuals.AbstractEAIndividual; +import eva2.server.go.individuals.GAIndividualBinaryData; +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.BayNet; +import eva2.tools.math.RNG; + +/** + * Basic implementation of the Bayesian Optimization Algorithm + * + * Martin Pelikan, David E. Goldberg and Erick Cantu-Paz: 'BOA: The Bayesian Optimization Algorithm' + * the works by Martin Pelikan and David E. Goldberg. + * + * @author seitz + * + */ +public class BOA implements InterfaceOptimizer, java.io.Serializable { + + private static boolean TRACE = true; + transient private InterfacePopulationChangedEventListener m_Listener = null; + private String m_Identifier = "BOA"; + + private int probDim = 3; + private int fitCrit = -1; + private int PopSize = 50; + private int numberOfParents = 3; + private boolean replaceNetwork = true; + private transient BayNet network = null; + private Population population = new Population(); + private AbstractOptimizationProblem problem = new BKnapsackProblem(); + private AbstractEAIndividual template = null; + private double learningSetRatio = 0.5; + private double resampleRatio = 0.5; + private double upperProbLimit = 0.9; + private double lowerProbLimit = 0.1; + + // private networkGenerationMethod netGenMethod = networkGenerationMethod.GREEDY; + // public enum networkGenerationMethod { GREEDY, K2 }; + + public BOA(){ + + } + + public BOA(int numberOfParents, int popSize, boolean replaceNetwork, double learningSetRatio, double resampleRatio){ + this.numberOfParents = numberOfParents; + this.PopSize = popSize; + this.replaceNetwork = replaceNetwork; + this.learningSetRatio = learningSetRatio; + this.resampleRatio = resampleRatio; + } + + public BOA(BOA b){ + this.m_Listener = b.m_Listener; + this.m_Identifier = b.m_Identifier; + this.probDim = b.probDim; + this.fitCrit = b.fitCrit; + this.PopSize = b.PopSize; + this.numberOfParents = b.numberOfParents; + this.replaceNetwork = b.replaceNetwork; + this.network = (BayNet) b.network.clone(); + this.population = (Population) b.population.clone(); + this.problem = (AbstractOptimizationProblem) b.problem.clone(); + this.template = (AbstractEAIndividual) b.template.clone(); + this.learningSetRatio = b.learningSetRatio; + this.resampleRatio = b.resampleRatio; + this.upperProbLimit = b.upperProbLimit; + } + + public Object clone(){ + return new BOA(this); + } + + public String getName() { + return "Bayesian Optimization Algorithm"; + } + + public static String globalInfo() { + return "Basic implementation of the Bayesian Optimization Algorithm based on the works by Martin Pelikan and David E. Goldberg."; + } + + public void hideHideable() { + GenericObjectEditor.setHideProperty(this.getClass(), "population", true); + } + + 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; + } + + 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()); + } + } + + /** + * 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){ + this.problem.evaluate(indy); + } + // increment the number of evaluations + this.population.incrFunctionCalls(); + } + + /** + * the default initialization + */ + 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)){ + System.err.println("Requiring binary data!"); + }else{ + Object dim = BeanInspector.callIfAvailable(problem, "getProblemDimension", null); + if (dim==null) System.err.println("Couldnt get problem dimension!"); + probDim = (Integer)dim; + ((InterfaceDataTypeBinary)this.template).SetBinaryGenotype(new BitSet(probDim)); + } + this.network = new BayNet(this.probDim, upperProbLimit, lowerProbLimit); + } + + 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> bestNetworks = new LinkedList>(); + while(improvement){ + improvement = false; +// System.out.println("score:"+score); + for(int i=0; i= score){ + if(tmpScore == score){ + bestNetworks.add(new Pair(i, j)); + }else{ + bestNetworks.clear(); + bestNetworks.add(new Pair(i, j)); + score = tmpScore; + improvement = true; + } + } + } + this.network.removeEdge(i, j); + } + } + } + if(bestNetworks.size() > 0){ + int val = RNG.randomInt(bestNetworks.size()); + Pair pair = bestNetworks.get(val); + this.network.addEdge(pair.getHead(), pair.getTail()); + } + bestNetworks.clear(); + } +// time = new Date(); +// System.out.println("Stop: "+time.getHours()+":"+time.getMinutes()+":"+time.getSeconds()); + } + + private boolean expandGreedy(Population pop){ + BayNet net = (BayNet) this.network.clone(); + BayNet best = (BayNet) this.network.clone(); + boolean improv = false; + boolean improvement = true; + double score = net.bayesianDirichletMetric(pop); + Date time = new Date(); +// System.out.println("Start: "+time.getHours()+":"+time.getMinutes()+":"+time.getSeconds()); + while(improvement){ + improvement = false; +// System.out.println("score:"+score); + for(int i=0; i score){ + best = (BayNet) tmp.clone(); + score = tmpScore; + improvement = true; + improv = true; + } + } + } + } + } + net = (BayNet) best.clone();; + } + time = new Date(); +// System.out.println("Stop: "+time.getHours()+":"+time.getMinutes()+":"+time.getSeconds()); + this.network = (BayNet) best.clone(); + return improv; + } + + /** + * Generate a Bayesian network with the individuals of the population as a reference Point + * @param pop the individuals the network is based on + */ + private void constructNetwork(Population pop){ + if(this.replaceNetwork){ + generateGreedy(pop); + }else{ + boolean improve = expandGreedy(pop); + if(!improve){ + generateGreedy(pop); + } + } + //TODO + } + + /** + * generate new individuals based on the bayesian network + * @return the new individuals + */ + private Population generateNewIndys(int sampleSetSize){ + Population pop = new Population(sampleSetSize); + if (TRACE) System.out.println("Resampling " + sampleSetSize + " indies..."); + while(pop.size() < sampleSetSize){ + AbstractEAIndividual indy = (AbstractEAIndividual) this.template.clone(); + BitSet data = this.network.sample(getBinaryData(indy)); + ((InterfaceDataTypeBinary) indy).SetBinaryGenotype(data); + evaluate(indy); + pop.add(indy); + } + return pop; + } + + /** + * Calculate a plausible number of individuals to be resampled per iteration. + * @return + */ + private int calcResampleSetSize() { + int result = (int)Math.min(PopSize, Math.max(1.0, ((double)PopSize)*resampleRatio)); +// System.out.println(result); + return result; + } + + /** + * Calculate a plausible number of individuals from which the BayNet is learned. + * In principle this can be independent of the resampling set size. + * @return + */ + private int calcLearningSetSize() { + return (int)Math.min(PopSize, Math.max(1.0, ((double)PopSize)*learningSetRatio)); + } + + public void remove(Population pop){ + for(Object indy: pop){ + this.population.remove(indy); + } + } + + public void optimize() { + Population best = this.population.getBestNIndividuals(calcLearningSetSize(), this.fitCrit); + constructNetwork(best); + Population newlyGenerated = generateNewIndys(calcResampleSetSize()); + Population toRemove = this.population.getWorstNIndividuals(calcResampleSetSize(), this.fitCrit); + remove(toRemove); + this.population.addAll(newlyGenerated); +// print(); + this.firePropertyChangedEvent(Population.nextGenerationPerformed); + } + + + /** Something has changed + */ + protected void firePropertyChangedEvent (String name) { + if (this.m_Listener != null) this.m_Listener.registerPopulationStateChanged(this, name); + } + + public Population getPopulation() { + return this.population; + } + + public void setPopulation(Population pop) { + this.population = pop; + } + + public InterfaceSolutionSet getAllSolutions() { + return new SolutionSet(this.population); + } + + public void SetIdentifier(String name) { + this.m_Identifier = name; + } + + public String getIdentifier() { + return this.m_Identifier; + } + + public void SetProblem(InterfaceOptimizationProblem problem) { + this.problem = (AbstractOptimizationProblem) problem; + } + + public InterfaceOptimizationProblem getProblem() { + return this.problem; + } + + public String getStringRepresentation() { + return "Bayesian Network"; + } + + public void freeWilly() { + + } + + //------------------------------- + //-------------GUI--------------- + //------------------------------- + + public int getNumberOfParents(){ + return this.numberOfParents; + } + + public void setNumberOfParents(int i){ + this.numberOfParents = i; + } + + public String numberOfParentsTipText(){ + return "The maximum number of parents a node in the Bayesian Network can have"; + } + + public boolean getReplaceNetwork(){ + return this.replaceNetwork; + } + + public void setReplaceNetwork(boolean b){ + this.replaceNetwork = b; + } + + public String replaceNetworkTipText(){ + return "if set, the network will be completely replaced. If not, it will be tried to improve the last network, if that is not possible, it will be replaced"; + } + + // public networkGenerationMethod getNetworkGenerationMethod(){ + // return this.netGenMethod; + // } + // + // public void setNetworkGenerationMethod(networkGenerationMethod n){ + // this.netGenMethod = n; + // } + // + // public String networkGenerationMethodTipText(){ + // return "The Method with which the Bayesian Network will be gererated"; + // } + + public void print(){ + this.network.print(); + } + + public static void main(String[] args){ + Population pop = new Population(); + GAIndividualBinaryData indy1 = new GAIndividualBinaryData(); + indy1.setBinaryDataLength(3); + GAIndividualBinaryData indy2 = (GAIndividualBinaryData) indy1.clone(); + GAIndividualBinaryData indy3 = (GAIndividualBinaryData) indy1.clone(); + GAIndividualBinaryData indy4 = (GAIndividualBinaryData) indy1.clone(); + GAIndividualBinaryData indy5 = (GAIndividualBinaryData) indy1.clone(); + BitSet data1 = indy1.getBinaryData(); + BitSet data2 = indy2.getBinaryData(); + BitSet data3 = indy3.getBinaryData(); + BitSet data4 = indy4.getBinaryData(); + BitSet data5 = indy5.getBinaryData(); + data1.set(0, true); + data1.set(1, true); + data1.set(2, false); + data2.set(0, true); + data2.set(1, true); + data2.set(2, true); + data3.set(0, false); + data3.set(1, true); + data3.set(2, false); + data4.set(0, false); + data4.set(1, true); + data4.set(2, true); + data5.set(0, true); + data5.set(1, false); + data5.set(2, false); + indy1.SetBinaryGenotype(data1); + indy2.SetBinaryGenotype(data2); + indy3.SetBinaryGenotype(data3); + indy4.SetBinaryGenotype(data4); + indy5.SetBinaryGenotype(data5); + pop.add(indy1); + pop.add(indy2); + AbstractEAIndividual ind = (AbstractEAIndividual) indy2.clone(); + pop.add(ind); +// pop.add(indy3); +// pop.add(indy4); +// pop.add(indy5); + BOA b = new BOA(); + b.generateGreedy(pop); + System.out.println(pop.getStringRepresentation()); + b.print(); + } + + public int getPopulationSize() { + return PopSize; + } + public void setPopulationSize(int popSize) { + PopSize = popSize; + } + public String populationSizeTipText() { + return "Define the pool size used by BOA"; + } + + public double getResamplingRatio() { + return resampleRatio; + } + public void setResamplingRatio(double resampleRat) { + this.resampleRatio = resampleRat; + } + public String resamplingRatioTipText() { + return "Ratio of individuals to be resampled from the Bayesian network per iteration"; + } + + public double getLearningRatio() { + return learningSetRatio; + } + public void setLearningRatio(double rat) { + this.learningSetRatio = rat; + } + public String learningRatioTipText() { + return "Ratio of individuals to be used to learn the Bayesian network"; + } + + public double getProbLimitHigh() { + return upperProbLimit; + } + + public void setProbLimitHigh(double upperProbLimit) { + this.upperProbLimit = upperProbLimit; + } + + public String probLimitHighTipText(){ + return "the upper limit of the probability to set one Bit to 1"; + } + + public double getProbLimitLow() { + return lowerProbLimit; + } + + public void setProbLimitLow(double lowerProbLimit) { + this.lowerProbLimit = lowerProbLimit; + } + + public String probLimitLowTipText(){ + return "the lower limit of the probability to set one Bit to 1"; + } + + public String[] customPropertyOrder() { + return new String[] {"learningRatio", "resamplingRatio"}; + } + +} diff --git a/src/eva2/server/go/strategies/BinaryScatterSearch.java b/src/eva2/server/go/strategies/BinaryScatterSearch.java new file mode 100644 index 00000000..5006fef1 --- /dev/null +++ b/src/eva2/server/go/strategies/BinaryScatterSearch.java @@ -0,0 +1,844 @@ +package eva2.server.go.strategies; + +import java.util.ArrayList; +import java.util.BitSet; + +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.operators.crossover.AdaptiveCrossoverEAMixer; +import eva2.server.go.operators.crossover.CM1; +import eva2.server.go.operators.crossover.CM2; +import eva2.server.go.operators.crossover.CM3; +import eva2.server.go.operators.crossover.CM4; +import eva2.server.go.operators.crossover.CM5; +import eva2.server.go.operators.crossover.CM6; +import eva2.server.go.operators.crossover.CM7; +import eva2.server.go.operators.distancemetric.GenotypeMetricBitSet; +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.B1Problem; +import eva2.server.go.problems.InterfaceOptimizationProblem; +import eva2.tools.Pair; +import eva2.tools.math.RNG; + +/** + * A BinaryScatterSearch implementation taken mainly from [i]. + * + * @author Alex + * + * F. Gortazar, A. Duarte, M. Laguna and R. Marti: Black Box Scatter Search for General Classes of Binary Optimization Problems + * Computers and Operations research, vol. 37, no. 11, pp. 1977-1986 (2010) + */ +public class BinaryScatterSearch implements InterfaceOptimizer, java.io.Serializable, InterfacePopulationChangedEventListener { + private static boolean TRACE = false; + transient private InterfacePopulationChangedEventListener m_Listener = null; + private String m_Identifier = "BinaryScatterSearch"; + + + private int MaxImpIter = 5; + private int poolSize = 100; + private int refSetSize = 10; + private int fitCrit = -1; + private int probDim = -1; + private int generationCycle = 500; + private double th1 = 0.5; + private double th2 = 0.5; + private double g1 = 1.0/3.0; + private double g2 = 1.0/3.0; + private boolean firstTime = true; + private AbstractEAIndividual template = null; + private AbstractOptimizationProblem problem = new B1Problem(); + private Population pool = new Population(); + private Population refSet = new Population(10); + private AdaptiveCrossoverEAMixer cross = new AdaptiveCrossoverEAMixer(new CM1(), new CM2(), new CM3(), new CM4(), new CM5(), new CM6(), new CM7()); + + /** + * Create a new BinaryScatterSearch with default values + */ + public BinaryScatterSearch(){ + } + + /** + * Create a new BinaryScatterSearch with the same parameters as the given BinaryScatterSearch + * @param b + */ + public BinaryScatterSearch(BinaryScatterSearch b){ + this.m_Listener = b.m_Listener; + this.m_Identifier = b.m_Identifier; + this.MaxImpIter = b.MaxImpIter; + this.poolSize = b.poolSize; + this.refSetSize = b.refSetSize; + this.fitCrit = b.fitCrit; + this.probDim = b.probDim; + this.generationCycle= b.generationCycle; + this.th1 = b.th1; + this.th2 = b.th2; + this.g1 = b.g1; + this.g2 = b.g2; + this.firstTime = b.firstTime; + this.template = b.template; + this.problem = b.problem; + this.pool = b.pool; + this.refSet = b.refSet; + this.cross = b.cross; + } + + /** + * Create a new BinaryScatterSearch with the given Parameters + * @param refSetS the refSetSize + * @param poolS the poolSize + * @param lowerThreshold the lower Boundary for the local Search + * @param upperThreshold the upper Boundary for the local Search + * @param perCentFirstIndGenerator how many individuals (in prospect of the poolSize) are generated through the first Generator + * @param perCentSecondIndGenerator how many individuals (in prospect of the poolSize) are generated through the second Generator + * @param prob the Problem + */ + public BinaryScatterSearch( + int refSetS, int poolS, double lowerThreshold, double upperThreshold, + double perCentFirstIndGenerator, double perCentSecondIndGenerator, AbstractOptimizationProblem prob) { + this.refSetSize = refSetS; + this.poolSize= poolS; + this.th1 = lowerThreshold; + this.th2 = upperThreshold; + this.g1 = perCentFirstIndGenerator; + this.g2 = perCentSecondIndGenerator; + this.problem = prob; + } + + /** + * Create a new BinaryScatterSearch with the given Parameters + * @param refSetS the refSetSize + * @param poolS the poolSize + * @param lowerThreshold the lower Boundary for the local Search + * @param upperThreshold the upper Boundary for the local Search + * @param perCentFirstIndGenerator how many individuals (in prospect of the poolSize) are generated through the first Generator + * @param perCentSecondIndGenerator how many individuals (in prospect of the poolSize) are generated through the second Generator + * @param prob the Problem + * @param cross the Crossover-Operators + */ + public BinaryScatterSearch( + int refSetS, int poolS, double lowerThreshold, double upperThreshold, + double perCentFirstIndGenerator, double perCentSecondIndGenerator, + AbstractOptimizationProblem prob, AdaptiveCrossoverEAMixer cross) { + this.refSetSize = refSetS; + this.poolSize= poolS; + this.th1 = lowerThreshold; + this.th2 = upperThreshold; + this.g1 = perCentFirstIndGenerator; + this.g2 = perCentSecondIndGenerator; + this.problem = prob; + this.cross = cross; + } + + /** + * @return a copy of the current BinaryScatterSearch + */ + public Object clone(){ + return new BinaryScatterSearch(this); + } + + public String getName() { + return "BSS"; + } + + 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; + } + + /** + * 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){ + this.problem.evaluate(indy); + } + // increment the number of evaluations + this.refSet.incrFunctionCalls(); + } + + /** + * Default initialization + */ + private void defaultInit(){ + this.refSet = new Population(); + this.template = this.problem.getIndividualTemplate(); + if (!(template instanceof InterfaceDataTypeBinary)){ + System.err.println("Requiring binary data!"); + }else{ + Object dim = BeanInspector.callIfAvailable(problem, "getProblemDimension", null); + if (dim==null) System.err.println("Couldnt get problem dimension!"); + probDim = (Integer)dim; + ((InterfaceDataTypeBinary)this.template).SetBinaryGenotype(new BitSet(probDim)); + } + this.firstTime = true; + this.cross.init(this.template, problem, refSet, Double.MAX_VALUE); + refSet.addPopulationChangedEventListener(this); + this.refSet.setNotifyEvalInterval(this.generationCycle); + } + + public void init() { + defaultInit(); + initRefSet(diversify()); + this.firePropertyChangedEvent(Population.nextGenerationPerformed); + } + + public void initByPopulation(Population pop, boolean reset) { + defaultInit(); + initRefSet(diversify(pop)); + this.firePropertyChangedEvent(Population.nextGenerationPerformed); + } + + /** + * + * @return a new diversified Population + */ + private Population diversify(){ + return diversify(new Population()); + } + + /** + * + * @param pop the initial Population + * @return a diversified Population with all the Individuals in the initial Population + */ + private Population diversify(Population pop){ + pop = generateG1(pop); + pop = generateG2(pop); + pop = generateG3(pop); + return pop; + } + + /** + * generate a new Population with diverse Individuals starting with 000...000, then 010101...01, 101010...10, 001001001...001, 110110110...110 and so on + * @param pop the initial Population + * @return the new Population + */ + private Population generateG1(Population pop){ + boolean method1 = true; + int i=1; + while(pop.size() < ((double) this.poolSize) * this.g1){ + AbstractEAIndividual indy = (AbstractEAIndividual) this.template.clone(); + BitSet data = getBinaryData(indy); + if(method1){ + method1 = !method1; + data.set(0, data.size(), true); + for(int j=0; j> list = new ArrayList>(); + for(int i=0; i< this.refSet.size(); i++){ + AbstractEAIndividual indy = this.refSet.getEAIndividual(i); + list.add(Population.getClosestFarthestIndy(indy, rest, new GenotypeMetricBitSet(), false)); + } + Pair pair = list.get(0); + for(Pair p: list){ + if(p.getTail()0 && best.getBestEAIndividual().getFitness(0) order(ArrayList list){ + ArrayList result = new ArrayList(); + for(Integer s: list){ + boolean done = false; + if(result.isEmpty()){ + result.add(s); + }else{ + for(int i=0; iscore(result.get(i), this.refSet)&&!done){ + result.add(i,s); + done = true; + } + } + if(!done){ + result.add(s); + } + } + } + return result; + } + + /** + * Do a local search + * @param indy the individual that will be improved + * @return the new improved individual + */ + private AbstractEAIndividual improve(AbstractEAIndividual indy){ + AbstractEAIndividual tmpIndy = (AbstractEAIndividual) indy.clone(); + BitSet data = ((InterfaceDataTypeBinary)tmpIndy).getBinaryData(); + ArrayList cl = new ArrayList(); + int localIter = 0; + for(int i=0; i=this.th1){ + cl.add(i); + } + } + } + cl = order(cl); + boolean improvement = true; + while(improvement && localIter < this.MaxImpIter){ + improvement = false; + for(int i:cl){ + data.flip(i); + ((InterfaceDataTypeBinary) tmpIndy).SetBinaryGenotype(data); + evaluate(tmpIndy); + if(tmpIndy.getFitness(0) generateSubsets(){ + ArrayList result = new ArrayList(); + for(int i=0; i=2){ + AbstractEAIndividual indy1 = pop.getEAIndividual(0); + pop.remove(0); + // Because some Crossover-Methods need the score, we need to give them the RefSet + for(int i=0; i0){ + result = pop.getBestEAIndividual(); + }else{ + System.err.println("Population empty"); + //return null; + } + return result; + } + + /** + * look if the individual is already in the population + * @param indy the Individual to be tested + * @param pop the population in where to search + * @return is the individual already in the Population + */ + private boolean contains(InterfaceDataTypeBinary indy, Population pop){ + if(pop.size()<=0){ + return false; + }else{ + BitSet data = indy.getBinaryData(); + for(int i=0; i newSubsets = generateSubsets(); + for(int i=0; i rootNodes = new LinkedList(); + private double upperProbLimit = 0.9; + private double lowerProbLimit = 0.1; + + public BayNet(int dimension, double upperLimit, double lowerLimit){ + this.dimension = dimension; + this.upperProbLimit = upperLimit; + this.lowerProbLimit = lowerLimit; + init(); + } + + public BayNet(BayNet b){ + this.network = cloneNetwork(b.network); + this.dimension = b.dimension; + this.nodes = new BayNode[b.dimension]; + for(int i=0; i(); + for(BayNode node: b.rootNodes){ + this.rootNodes.add(this.nodes[node.getId()]); + } + this.upperProbLimit = b.upperProbLimit; + this.lowerProbLimit = b.lowerProbLimit; + } + + public Object clone(){ + return new BayNet(this); + } + + private boolean[][] cloneNetwork(boolean[][] b){ + boolean[][] result = new boolean[b.length][b.length]; + for(int i=0; i getRootNodes(){ +// ArrayList result = new ArrayList(); +// for (int i=0; i getChildren(BayNode n){ +// ArrayList result = new ArrayList(); +// int i = n.getId(); +// for(int j=0; j ids = n.getChildren(); + List result = new ArrayList(); + for(int i: ids){ + result.add(this.nodes[i]); + } + return result; + } + + /** + * return the parents for a given node + * @param n the node + * @return the parents of the node + */ + public List getParents(BayNode n){ +// ArrayList result = new ArrayList(); +// int i = n.getId(); +// for(int j=0; j ids = n.getParents(); + List result = new LinkedList(); + for(int i: ids){ + result.add(this.nodes[i]); + } + return result; + } + + /** + * return the children of a list of nodes + * @param n the list of nodes + * @return the children of the nodes + */ + public List getChildren(List n){ + ArrayList result = new ArrayList(); + for(BayNode node: n){ + List children = getChildren(node); + for(BayNode nod: children){ + if(!result.contains(nod)){ + result.add(nod); + } + } + } + return result; + } + + /** + * remove the edge from node i to node j + * @param i the node from which the edge comes + * @param j the node to which the edge points + */ + public void removeEdge(int i, int j){ + if(this.network[i][j]){ + this.network[i][j] = false; + this.nodes[j].decrNumberOfParents(); + this.nodes[i].removeChild(j); + this.nodes[j].removeParent(i); + this.nodes[j].generateNewPTable(); + if(this.nodes[j].getNumberOfParents() == 0){ + this.rootNodes.add(nodes[j]); + } + } + } + + /** + * add an edge from the node i to the node j + * @param i edge from this node + * @param j edge to this node + */ + public void addEdge(int i, int j){ + if(!this.network[i][j]){ + this.network[i][j] = true; + this.nodes[j].incrNumberOfParents(); + this.nodes[j].generateNewPTable(); + this.rootNodes.remove(this.nodes[j]); + this.nodes[i].addChild(j); + this.nodes[j].addParent(i); + } + } + + /** + * find the next value where all the parents are already set + * @param data + * @return + */ + private int findNext(double[] probabilities, List nodes){ + for(BayNode node: nodes){ + List parents = getParents(node); + boolean possible = false; + for(BayNode p: parents){ + if(probabilities[p.getId()] != -1){ + possible = true; + }else{ + possible = false; + break; + } + } + if(possible){ + return node.getId(); + } + } + return -1; + } + + /** + * calculate a new BitSet according to the network + * @param data the BitSet that will be calculated + * @return the new BitSet + */ + public BitSet sample(BitSet data){ + // generate a new probabilities-vector + double[] probabilities = new double[this.network.length]; + for(int i=0; i nodes = getRootNodes(); + // calculate the BitSet-Value for these nodes + for(BayNode node: nodes){ + int id = node.getId(); + probabilities[id] = node.getProbability(0); + data.set(id, RNG.flipCoin(probabilities[id])); + } + // find the next node that can be evaluated + List toCalculate = getChildren(nodes); + int next = findNext(probabilities, toCalculate); + while(next != -1){ + toCalculate.remove(this.nodes[next]); + probabilities[next] = calculateNextProbability(data, toCalculate, next); + data.set(next, RNG.flipCoin(probabilities[next])); + next = findNext(probabilities, toCalculate); + } + return data; + } + + /** + * calculate the next probability + * @param data the already calculated data + * @param probabilities the already calculated probabilities + * @param toCalculate the Nodes that have yet to be calculated + * @param next the node for which to calculate the probability + * @return the new probabilities array + */ + private double calculateNextProbability(BitSet data, List toCalculate, int next) { + toCalculate.addAll(getChildren(this.nodes[next])); + int[] parId = calculateSortedParentIds(next); + int prob = 0; + int cnt = 0; + for(int j=parId.length-1; j>=0; j--){ + if(data.get(parId[j])){ + prob += (int) Math.pow(2, j); + } + cnt++; + } + return this.nodes[next].getProbability(prob); + } + + /** + * generate an array of the parents, sorted by there id + * @param id the id of the node + * @return the sorted parent-ids + */ + private int[] calculateSortedParentIds(int id) { + List parents = getParents(this.nodes[id]); + int[] parId = new int[parents.size()]; + int i=0; + for(BayNode nod: parents){ + parId[i] = nod.getId(); + i++; + } + Arrays.sort(parId); + return parId; + } + + /** + * generate an array of the parents plus the given node, sorted by there id + * @param id the id of the node + * @return the sorted parent-ids + */ + private int[] calculateSortedParentPlusNodeIds(int id) { + List nodes = getParents(this.nodes[id]); + nodes.add(this.nodes[id]); + int[] sortedIds = new int[nodes.size()]; + int i=0; + for(BayNode nod: nodes){ + sortedIds[i] = nod.getId(); + i++; + } + Arrays.sort(sortedIds); + return sortedIds; + } + + private void resetCalculated(){ + for(int i=0; i toCalculate = getChildren(this.nodes[to]); + while(!toCalculate.isEmpty()){ + BayNode node = toCalculate.get(0); + toCalculate.remove(node); + if(!node.getCalculated()){ + node.setCalculated(true); + if(from == node.getId()){ + resetCalculated(); + return false; + } + List children = getChildren(node); + toCalculate.addAll(children); + } + } + resetCalculated(); + return true; + } + + /** + * check if the given Network is acyclic + * @param net the Network + * @return is the net acyclic + */ + public boolean isACyclic(){ + List> deletedEdges = new LinkedList>(); + List nodes = getRootNodes(); + boolean res=false; + for(int i=0; i<=this.dimension; i++){ + for(BayNode node: nodes){ + int id = node.getId(); + for(int j=0; j(id,j)); + } + } + } + nodes = getRootNodes(); + // if we only have root nodes, we have an acyclic graph + if(nodes.size() == this.nodes.length){ + res = true; + break; + } + } +// System.out.println("Deleted edges: " + BeanInspector.toString(deletedEdges)); + for (Pair edge : deletedEdges) { + this.network[edge.head][edge.tail] = true; + } + return res; + } + + private double getPrior(List parents, Population pop){ + return (double) pop.size() / Math.pow(2.0, (double) parents.size()); + } + + private double getPrior(List parents, BayNode current, Population pop){ + return getPrior(parents, pop) / 2.0; + } + + private void setRootPTables(Population pop){ + List rootNodes = getRootNodes(); + for(BayNode node: rootNodes){ + int id = node.getId(); + double count = 0; + for(int i=0; i parents = getParents(currentNode); +// System.out.println("parents: "+parents.size()); + // get the parentIds sorted (for the lookup) + if(!parents.isEmpty()){ + int[] parId = calculateSortedParentIds(i); + // the parentIds plus the id of the current node sorted (for the lookup + int[] nodeIds = calculateSortedParentPlusNodeIds(i); + double[] pTable = currentNode.getPTable(); + for(int j=0; j0) && (data.get(ids[m]))){ + setCorrectly = true; + }else if(!((j & (1<0) && (!data.get(ids[m]))){ + setCorrectly = true; + }else{ + setCorrectly = false; + m = j+10; + } + } + return setCorrectly; + } + + public void print(){ + for(int i=0; i parents = new LinkedList(); + private List children = new LinkedList(); + + public BayNode(int id){ + this.id = id; + } + + public BayNode(BayNode b){ + this.id = b.id; + this.numberOfParents = b.numberOfParents; + this.pTable = b.pTable.clone(); + this.parents = new LinkedList(); + this.children = new LinkedList(); + for(int i: b.parents){ + this.parents.add(i); + } + for(int i: b.children){ + this.children.add(i); + } + this.calculated = b.calculated; + } + + public Object clone(){ + return new BayNode(this); + } + + public double getProbability(int i){ + return pTable[i]; + } + + public void generateNewPTable(){ + this.pTable = new double[(int) Math.pow(2, this.numberOfParents)]; + for(int i=0; i getParents(){ + return this.parents; + } + + public void addParent(Integer b){ + if(!this.parents.contains(b)){ + this.parents.add(b); + } + } + + public void removeParent(Integer b){ + this.parents.remove(b); + } + + public List getChildren(){ + return this.children; + } + + public void addChild(Integer b){ + if(!this.children.contains(b)){ + this.children.add(b); + } + } + public void removeChild(Integer b){ + this.children.remove(b); + } + + public void setPTable(double[] table){ + this.pTable = table; + } + + public void setPTable(int i, double v){ + this.pTable[i] = v; + } + + public void incrNumberOfParents(){ + this.numberOfParents++; + } + + public void decrNumberOfParents(){ + this.numberOfParents--; + } + + public int getNumberOfParents(){ + return this.numberOfParents; + } + + public int getId(){ + return this.id; + } + + public double[] getPTable(){ + return this.pTable; + } + + public boolean getCalculated(){ + return this.calculated; + } + + public void setCalculated(boolean b){ + this.calculated = b; + } +}