/** * Determine the fitness of the given Chromosome instance. The higher the return value, the more * fit the instance. This method should always return the same fitness value for two equivalent * Chromosome instances. * * @param a_subject the Chromosome instance to evaluate * @return positive double reflecting the fitness rating of the given Chromosome * @since 2.0 (until 1.1: return type int) * @author Neil Rotstan, Klaus Meffert, John Serri */ public double evaluate(IChromosome a_subject) { int i = 0, j, k; for (j = 0; j < EvolvingSubsumptionForRobocode.numberOfEvents; j++) { eventPriority[j] = ((Integer) a_subject.getGene(i++).getAllele()).intValue(); } for (j = 0; j < EvolvingSubsumptionForRobocode.numberOfBehaviours; j++) { behaviourOverwrite[j] = ((Integer) a_subject.getGene(i++).getAllele()).intValue() > 50; } for (j = 0; j < EvolvingSubsumptionForRobocode.numberOfBehaviours; j++) { for (k = 0; k < EvolvingSubsumptionForRobocode.behaviourSize; k++) { behaviourActions[j][k] = ((Integer) a_subject.getGene(i++).getAllele()).intValue(); } } double tempFitness; double fitness = 0; for (j = 0; j < otherRobots.length; j++) { RobotSpecification[] tempRobots = new RobotSpecification[2]; tempRobots[0] = evolvable; tempRobots[1] = otherRobots[j]; battleSpecs = new BattleSpecification(1, new BattlefieldSpecification(800, 600), tempRobots); tempFitness = 0; System.out.println("Testing against " + otherRobots[j].getName() + "..."); for (i = 0; i < EvolvingSubsumptionForRobocode.numberOfBattles; i++) { engine.runBattle(battleSpecs, true); tempFitness += battleObserver.getScoreRobot() / 500; } tempFitness /= EvolvingSubsumptionForRobocode.numberOfBattles; fitness += tempFitness; } fitness /= otherRobots.length; return Math.min(1.0d, fitness); }
/** * Write report on eveluation to the given stream. * * @param a_fitnessFunction p_SupergeneChangeFitnessFunction * @param a_population Genotype * @return Chromosome */ public IChromosome report( SupergeneChangeFitnessFunction a_fitnessFunction, Genotype a_population) { IChromosome bestSolutionSoFar = a_population.getFittestChromosome(); if (!REPORT_ENABLED) { return bestSolutionSoFar; } System.out.println( "\nThe best solution has a fitness value of " + bestSolutionSoFar.getFitnessValue()); System.out.println("It contained the following: "); System.out.println( "\t" + a_fitnessFunction.getNumberOfCoinsAtGene(bestSolutionSoFar, QUARTERS) + " quarters."); System.out.println( "\t" + a_fitnessFunction.getNumberOfCoinsAtGene(bestSolutionSoFar, DIMES) + " dimes."); System.out.println( "\t" + a_fitnessFunction.getNumberOfCoinsAtGene(bestSolutionSoFar, NICKELS) + " nickels."); System.out.println( "\t" + a_fitnessFunction.getNumberOfCoinsAtGene(bestSolutionSoFar, PENNIES) + " pennies."); System.out.println( "For a total of " + a_fitnessFunction.amountOfChange(bestSolutionSoFar) + " cents in " + a_fitnessFunction.getTotalNumberOfCoins(bestSolutionSoFar) + " coins."); return bestSolutionSoFar; }
protected void updateChromosomes(Population a_pop, Configuration a_conf) { int currentPopSize = a_pop.size(); // Ensure all chromosomes are updated. // ----------------------------------- BulkFitnessFunction bulkFunction = a_conf.getBulkFitnessFunction(); boolean bulkFitFunc = (bulkFunction != null); if (!bulkFitFunc) { for (int i = 0; i < currentPopSize; i++) { IChromosome chrom = a_pop.getChromosome(i); chrom.getFitnessValue(); } } }
/** * Returns the total number of coins represented by all of the genes in the given potential * solution. * * @param a_potentialsolution the potential solution to evaluate * @return total number of coins represented by the given Chromosome * @author Neil Rotstan * @since 1.0 */ public static int getTotalNumberOfCoins(IChromosome a_potentialsolution) { int totalCoins = 0; int numberOfGenes = a_potentialsolution.size(); for (int i = 0; i < numberOfGenes; i++) { totalCoins += getNumberOfCoinsAtGene(a_potentialsolution, i); } return totalCoins; }
/** * Marshall a Chromosome instance to an XML Element representation, including its contained Genes * as sub-elements. This may be useful in scenarios where representation as an entire Document is * undesirable, such as when the representation of this Chromosome is to be combined with other * elements in a single Document. * * @param a_subject the chromosome to represent as an XML element * @param a_xmlDocument a Document instance that will be used to create the Element instance. Note * that the element will NOT be added to the document by this method * @return an Element object representing the given Chromosome * @author Neil Rotstan * @since 1.0 * @deprecated use XMLDocumentBuilder instead */ public static Element representChromosomeAsElement( final IChromosome a_subject, final Document a_xmlDocument) { // Start by creating an element for the chromosome and its size // attribute, which represents the number of genes in the chromosome. // ------------------------------------------------------------------ Element chromosomeElement = a_xmlDocument.createElement(CHROMOSOME_TAG); chromosomeElement.setAttribute(SIZE_ATTRIBUTE, Integer.toString(a_subject.size())); // Next create the genes element with its nested gene elements, // which will contain string representations of the alleles. // -------------------------------------------------------------- Element genesElement = representGenesAsElement(a_subject.getGenes(), a_xmlDocument); // Add the new genes element to the chromosome element and then // return the chromosome element. // ------------------------------------------------------------- chromosomeElement.appendChild(genesElement); return chromosomeElement; }
/** * Operate on the given chromosome with the given mutation rate. * * @param a_chrom chromosome to operate * @param a_rate mutation rate * @param a_generator random generator to use (must not be null) * @return mutated chromosome of null if no mutation has occured. * @author Audrius Meskauskas * @author Florian Hafner * @since 3.3.2 */ protected IChromosome operate( final IChromosome a_chrom, final int a_rate, final RandomGenerator a_generator) { IChromosome chromosome = null; // ---------------------------------------- for (int j = m_startOffset; j < a_chrom.size(); j++) { // Ensure probability of 1/currentRate for applying mutation. // ---------------------------------------------------------- if (a_generator.nextInt(a_rate) == 0) { if (chromosome == null) { chromosome = (IChromosome) a_chrom.clone(); // In case monitoring is active, support it. // ----------------------------------------- if (m_monitorActive) { chromosome.setUniqueIDTemplate(a_chrom.getUniqueID(), 1); } } Gene[] genes = chromosome.getGenes(); if (m_range == 0) { m_range = genes.length; } Gene[] mutated = operate(a_generator, j, genes); // setGenes is not required for this operator, but it may // be needed for the derived operators. // ------------------------------------------------------ try { chromosome.setGenes(mutated); } catch (InvalidConfigurationException cex) { throw new Error("Gene type not allowed by constraint checker", cex); } } } return chromosome; }
/** * Determine the fitness of the given Chromosome instance. The higher the return value, the more * fit the instance. This method should always return the same fitness value for two equivalent * Chromosome instances. * * @param a_subject the Chromosome instance to evaluate * @return positive double reflecting the fitness rating of the given Chromosome * @since 2.0 (until 1.1: return type int) * @author Neil Rotstan, Klaus Meffert, John Serri */ public double evaluate(IChromosome a_subject) { // Take care of the fitness evaluator. It could either be weighting higher // fitness values higher (e.g.DefaultFitnessEvaluator). Or it could weight // lower fitness values higher, because the fitness value is seen as a // defect rate (e.g. DeltaFitnessEvaluator) boolean defaultComparation = a_subject.getConfiguration().getFitnessEvaluator().isFitter(2, 1); // The fitness value measures both how close the value is to the // target amount supplied by the user and the total number of coins // represented by the solution. We do this in two steps: first, // we consider only the represented amount of change vs. the target // amount of change and return higher fitness values for amounts // closer to the target, and lower fitness values for amounts further // away from the target. Then we go to step 2, which returns a higher // fitness value for solutions representing fewer total coins, and // lower fitness values for solutions representing more total coins. // ------------------------------------------------------------------ int changeAmount = amountOfChange(a_subject); int totalCoins = getTotalNumberOfCoins(a_subject); int changeDifference = Math.abs(m_targetAmount - changeAmount); double fitness; if (defaultComparation) { fitness = 0.0d; } else { fitness = MAX_BOUND / 2; } // Step 1: Determine distance of amount represented by solution from // the target amount. If the change difference is greater than zero we // will divide one by the difference in change between the // solution amount and the target amount. That will give the desired // effect of returning higher values for amounts closer to the target // amount and lower values for amounts further away from the target // amount. // In the case where the change difference is zero it means that we have // the correct amount and we assign a higher fitness value. // --------------------------------------------------------------------- if (defaultComparation) { fitness += changeDifferenceBonus(MAX_BOUND / 2, changeDifference); } else { fitness -= changeDifferenceBonus(MAX_BOUND / 2, changeDifference); } // Step 2: We divide the fitness value by a penalty based on the number of // coins. The higher the number of coins the higher the penalty and the // smaller the fitness value. // And inversely the smaller number of coins in the solution the higher // the resulting fitness value. // ----------------------------------------------------------------------- if (defaultComparation) { fitness -= computeCoinNumberPenalty(MAX_BOUND / 2, totalCoins); } else { fitness += computeCoinNumberPenalty(MAX_BOUND / 2, totalCoins); } // Make sure fitness value is always positive. // ------------------------------------------- return Math.max(1.0d, fitness); }
boolean checkAlleles(IChromosome chrom, int j, int nextInt) { Gene[] newgene = chrom.getGenes(); Integer[] alleles = new Integer[j]; for (int i = 0; i < j; i++) { alleles[i] = (Integer) newgene[i].getAllele(); } if (Arrays.asList(alleles).contains(new Integer(nextInt))) { return true; } return false; }
/** * Convenience method that returns a new Chromosome instance with its genes values (alleles) * randomized. Note that, if possible, this method will acquire a Chromosome instance from the * active ChromosomePool (if any) and then randomize its gene values before returning it. If a * Chromosome cannot be acquired from the pool, then a new instance will be constructed and its * gene values randomized before returning it. * * @param a_configuration the configuration to use * @return randomly initialized Chromosome * @throws InvalidConfigurationException if the given Configuration instance is invalid * @throws IllegalArgumentException if the given Configuration instance is null * @author Neil Rotstan * @author Klaus Meffert * @since 1.0 */ public static IChromosome randomInitialChromosome(Configuration a_configuration) throws InvalidConfigurationException { // Sanity check: make sure the given configuration isn't null. // ----------------------------------------------------------- if (a_configuration == null) { throw new IllegalArgumentException("Configuration instance must not be null"); } // Lock the configuration settings so that they can't be changed // from now on. // ------------------------------------------------------------- a_configuration.lockSettings(); // First see if we can get a Chromosome instance from the pool. // If we can, we'll randomize its gene values (alleles) and then // return it. // ------------------------------------------------------------- IChromosomePool pool = a_configuration.getChromosomePool(); if (pool != null) { IChromosome randomChromosome = pool.acquireChromosome(); if (randomChromosome != null) { Gene[] genes = randomChromosome.getGenes(); RandomGenerator generator = a_configuration.getRandomGenerator(); for (int i = 0; i < genes.length; i++) { genes[i].setToRandomValue(generator); /** @todo what about Gene's energy? */ } randomChromosome.setFitnessValueDirectly(FitnessFunction.NO_FITNESS_VALUE); return randomChromosome; } } // We weren't able to get a Chromosome from the pool, so we have to // construct a new instance and build it from scratch. // ------------------------------------------------------------------ IChromosome sampleChromosome = a_configuration.getSampleChromosome(); sampleChromosome.setFitnessValue(FitnessFunction.NO_FITNESS_VALUE); Gene[] sampleGenes = sampleChromosome.getGenes(); Gene[] newGenes = new Gene[sampleGenes.length]; RandomGenerator generator = a_configuration.getRandomGenerator(); for (int i = 0; i < newGenes.length; i++) { // We use the newGene() method on each of the genes in the // sample Chromosome to generate our new Gene instances for // the Chromosome we're returning. This guarantees that the // new Genes are setup with all of the correct internal state // for the respective gene position they're going to inhabit. // ----------------------------------------------------------- newGenes[i] = sampleGenes[i].newGene(); // Set the gene's value (allele) to a random value. // ------------------------------------------------ newGenes[i].setToRandomValue(generator); /** @todo what about Gene's energy? */ } // Finally, construct the new chromosome with the new random // genes values and return it. // --------------------------------------------------------- return new Chromosome(a_configuration, newGenes); }
/** * Executes the genetic algorithm to determine the minimum number of items necessary to make up * the given target volume. The solution will then be written to the console. * * @param a_knapsackVolume the target volume for which this method is attempting to produce the * optimal list of items * @throws Exception * @author Klaus Meffert * @since 2.3 */ public static void findItemsForVolume(double a_knapsackVolume) throws Exception { // Start with a DefaultConfiguration, which comes setup with the // most common settings. // ------------------------------------------------------------- Configuration conf = new DefaultConfiguration(); conf.setPreservFittestIndividual(true); // Set the fitness function we want to use. We construct it with // the target volume passed in to this method. // --------------------------------------------------------- FitnessFunction myFunc = new KnapsackFitnessFunction(a_knapsackVolume); conf.setFitnessFunction(myFunc); // Now we need to tell the Configuration object how we want our // Chromosomes to be setup. We do that by actually creating a // sample Chromosome and then setting it on the Configuration // object. As mentioned earlier, we want our Chromosomes to each // have as many genes as there are different items available. We want the // values (alleles) of those genes to be integers, which represent // how many items of that type we have. We therefore use the // IntegerGene class to represent each of the genes. That class // also lets us specify a lower and upper bound, which we set // to senseful values (i.e. maximum possible) for each item type. // -------------------------------------------------------------- Gene[] sampleGenes = new Gene[itemVolumes.length]; for (int i = 0; i < itemVolumes.length; i++) { sampleGenes[i] = new IntegerGene(conf, 0, (int) Math.ceil(a_knapsackVolume / itemVolumes[i])); } IChromosome sampleChromosome = new Chromosome(conf, sampleGenes); conf.setSampleChromosome(sampleChromosome); // Finally, we need to tell the Configuration object how many // Chromosomes we want in our population. The more Chromosomes, // the larger number of potential solutions (which is good for // finding the answer), but the longer it will take to evolve // the population (which could be seen as bad). // ------------------------------------------------------------ conf.setPopulationSize(50); // Create random initial population of Chromosomes. // Here we try to read in a previous run via XMLManager.readFile(..) // for demonstration purpose! // ----------------------------------------------------------------- Genotype population; try { Document doc = XMLManager.readFile(new File("knapsackJGAP.xml")); population = XMLManager.getGenotypeFromDocument(conf, doc); } catch (FileNotFoundException fex) { population = Genotype.randomInitialGenotype(conf); } population = Genotype.randomInitialGenotype(conf); // Evolve the population. Since we don't know what the best answer // is going to be, we just evolve the max number of times. // --------------------------------------------------------------- for (int i = 0; i < MAX_ALLOWED_EVOLUTIONS; i++) { population.evolve(); } // Save progress to file. A new run of this example will then be able to // resume where it stopped before! // --------------------------------------------------------------------- // represent Genotype as tree with elements Chromomes and Genes // ------------------------------------------------------------ DataTreeBuilder builder = DataTreeBuilder.getInstance(); IDataCreators doc2 = builder.representGenotypeAsDocument(population); // create XML document from generated tree // --------------------------------------- XMLDocumentBuilder docbuilder = new XMLDocumentBuilder(); Document xmlDoc = (Document) docbuilder.buildDocument(doc2); XMLManager.writeFile(xmlDoc, new File("knapsackJGAP.xml")); // Display the best solution we found. // ----------------------------------- IChromosome bestSolutionSoFar = population.getFittestChromosome(); System.out.println( "The best solution has a fitness value of " + bestSolutionSoFar.getFitnessValue()); System.out.println("It contained the following: "); int count; double totalVolume = 0.0d; for (int i = 0; i < bestSolutionSoFar.size(); i++) { count = ((Integer) bestSolutionSoFar.getGene(i).getAllele()).intValue(); if (count > 0) { System.out.println("\t " + count + " x " + itemNames[i]); totalVolume += itemVolumes[i] * count; } } System.out.println("\nFor a total volume of " + totalVolume + " ccm"); System.out.println("Expected volume was " + a_knapsackVolume + " ccm"); System.out.println("Volume difference is " + Math.abs(totalVolume - a_knapsackVolume) + " ccm"); }
public void operate(final Population a_population, final List a_candidateChromosomes) { // Work out the number of crossovers that should be performed. // ----------------------------------------------------------- int m_crossoverRate = getCrossOverRate(); double m_crossoverRatePercent = getCrossOverRatePercent(); int size = Math.min(getConfiguration().getPopulationSize(), a_population.size()); int numCrossovers = 0; if (m_crossoverRate >= 0) { numCrossovers = size / m_crossoverRate; } else if (m_crossoverRateCalc != null) { numCrossovers = size / 6; } else { numCrossovers = (int) (size * m_crossoverRatePercent); } RandomGenerator generator = getConfiguration().getRandomGenerator(); IGeneticOperatorConstraint constraint = getConfiguration().getJGAPFactory().getGeneticOperatorConstraint(); // For each crossover, grab two random chromosomes, pick a random // locus (gene location), and then swap that gene and all genes // to the "right" (those with greater loci) of that gene between // the two chromosomes. // -------------------------------------------------------------- int index1, index2; crossoverValues = new int[size]; for (int i = 0; i < size; i++) { crossoverValues[i] = 0; } List<Integer> chromeSel = new ArrayList<Integer>(); for (int i = 0; i < size; i++) { if (m_crossoverRateCalc != null) { CrossoverRateCalculator ccalc = (CrossoverRateCalculator) m_crossoverRateCalc; ccalc.setCurrentFitness(a_population.getChromosome(i).getFitnessValue()); int numbers = ccalc.calculateCurrentRate(); crossoverValues[i] = numbers; while (numbers > 0) { chromeSel.add(i); numbers--; } } } int justtocheck = chromeSel.size(); if (m_crossoverRateCalc != null) { if (justtocheck == 0) { System.out.println("Exception Caught.. Crossover.. chromesel array is null!!"); for (int fix = 0; fix <= size - 2; fix++) { chromeSel.add(fix); } } } // for (int i = 0; i < numCrossovers; i++) { IChromosome chrom1; IChromosome chrom2; if (m_crossoverRateCalc != null) { index1 = generator.nextInt(chromeSel.size()); index2 = generator.nextInt(chromeSel.size()); chrom1 = a_population.getChromosome(chromeSel.get(index1)); chrom2 = a_population.getChromosome(chromeSel.get(index2)); } else { index1 = generator.nextInt(size); index2 = generator.nextInt(size); chrom1 = a_population.getChromosome(index1); chrom2 = a_population.getChromosome(index2); } // Verify that crossover is allowed. // --------------------------------- if (!isXoverNewAge() && chrom1.getAge() < 1 && chrom2.getAge() < 1) { // Crossing over two newly created chromosomes is not seen as helpful // here. // ------------------------------------------------------------------ continue; } if (constraint != null) { List v = new Vector(); v.add(chrom1); v.add(chrom2); if (!constraint.isValid(a_population, v, this)) { // Constraint forbids crossing over. // --------------------------------- continue; } } // Clone the chromosomes. // ---------------------- IChromosome firstMate = (IChromosome) ((ICloneable) chrom1).clone(); IChromosome secondMate = (IChromosome) ((ICloneable) chrom2).clone(); // Cross over the chromosomes. // --------------------------- doCrossover(firstMate, secondMate, a_candidateChromosomes, generator); } }
/** * Executes the genetic algorithm to determine the minimum number of coins necessary to make up * the given target amount of change. The solution will then be written to System.out. * * @param a_targetChangeAmount the target amount of change for which this method is attempting to * produce the minimum number of coins * @param a_doMonitor true: turn on monitoring for later evaluation of evolution progress * @throws Exception * @author Neil Rotstan * @author Klaus Meffert * @since 1.0 */ public static void makeChangeForAmount(int a_targetChangeAmount, boolean a_doMonitor) throws Exception { // Start with a DefaultConfiguration, which comes setup with the // most common settings. // ------------------------------------------------------------- Configuration conf = new DefaultConfiguration(); // Care that the fittest individual of the current population is // always taken to the next generation. // Consider: With that, the pop. size may exceed its original // size by one sometimes! // ------------------------------------------------------------- conf.setPreservFittestIndividual(true); conf.setKeepPopulationSizeConstant(false); // Set the fitness function we want to use, which is our // MinimizingMakeChangeFitnessFunction. We construct it with // the target amount of change passed in to this method. // --------------------------------------------------------- FitnessFunction myFunc = new SampleFitnessFunction(a_targetChangeAmount); conf.setFitnessFunction(myFunc); if (a_doMonitor) { // Turn on monitoring/auditing of evolution progress. // -------------------------------------------------- m_monitor = new EvolutionMonitor(); conf.setMonitor(m_monitor); } // Now we need to tell the Configuration object how we want our // Chromosomes to be setup. We do that by actually creating a // sample Chromosome and then setting it on the Configuration // object. As mentioned earlier, we want our Chromosomes to each // have four genes, one for each of the coin types. We want the // values (alleles) of those genes to be integers, which represent // how many coins of that type we have. We therefore use the // IntegerGene class to represent each of the genes. That class // also lets us specify a lower and upper bound, which we set // to sensible values for each coin type. // -------------------------------------------------------------- Gene[] sampleGenes = new Gene[4]; sampleGenes[0] = new IntegerGene(conf, 0, 98); // Wasser sampleGenes[1] = new IntegerGene(conf, 0, 98); // Zucker sampleGenes[2] = new IntegerGene(conf, 0, 98); // Saft1 sampleGenes[3] = new IntegerGene(conf, 0, 98); // Saft2 IChromosome sampleChromosome = new Chromosome(conf, sampleGenes); conf.setSampleChromosome(sampleChromosome); // Finally, we need to tell the Configuration object how many // Chromosomes we want in our population. The more Chromosomes, // the larger number of potential solutions (which is good for // finding the answer), but the longer it will take to evolve // the population (which could be seen as bad). // ------------------------------------------------------------ conf.setPopulationSize(80); // Now we initialize the population randomly, anyway (as an example only)! // If you want to load previous results from file, remove the next line! // ----------------------------------------------------------------------- Genotype population = Genotype.randomInitialGenotype(conf); // Evolve the population. Since we don't know what the best answer // is going to be, we just evolve the max number of times. // --------------------------------------------------------------- long startTime = System.currentTimeMillis(); for (int i = 0; i < MAX_ALLOWED_EVOLUTIONS; i++) { if (!uniqueChromosomes(population.getPopulation())) { throw new RuntimeException("Invalid state in generation " + i); } if (m_monitor != null) { population.evolve(m_monitor); } else { population.evolve(); } } long endTime = System.currentTimeMillis(); System.out.println("Total evolution time: " + (endTime - startTime) + " ms"); // Save progress to file. A new run of this example will then be able to // resume where it stopped before! --> this is completely optional. // --------------------------------------------------------------------- // Display the best solution we found. // ----------------------------------- IChromosome bestSolutionSoFar = population.getFittestChromosome(); double v1 = bestSolutionSoFar.getFitnessValue(); System.out.println( "The best solution has a fitness value of " + bestSolutionSoFar.getFitnessValue()); bestSolutionSoFar.setFitnessValueDirectly(-1); System.out.println("It contains the following: "); System.out.println( "\t" + SampleFitnessFunction.getNumberOfCoinsAtGene(bestSolutionSoFar, 0) + " ml water."); System.out.println( "\t" + SampleFitnessFunction.getNumberOfCoinsAtGene(bestSolutionSoFar, 1) + " ml sugar."); System.out.println( "\t" + SampleFitnessFunction.getNumberOfCoinsAtGene(bestSolutionSoFar, 2) + " ml juice 1."); System.out.println( "\t" + SampleFitnessFunction.getNumberOfCoinsAtGene(bestSolutionSoFar, 3) + " ml juice 2."); System.out.println( "For a total of " + SampleFitnessFunction.amountOfChange(bestSolutionSoFar) + " ml."); }
/** * Evolves the population of chromosomes within a genotype. This will execute all of the genetic * operators added to the present active configuration and then invoke the natural selector to * choose which chromosomes will be included in the next generation population. * * @param a_pop the population to evolve * @param a_conf the configuration to use for evolution * @return evolved population * @author Klaus Meffert * @since 3.2 */ public Population evolve(Population a_pop, Configuration a_conf) { Population pop = a_pop; int originalPopSize = a_conf.getPopulationSize(); boolean monitorActive = a_conf.getMonitor() != null; IChromosome fittest = null; // If first generation: Set age to one to allow genetic operations, // see CrossoverOperator for an illustration. // ---------------------------------------------------------------- if (a_conf.getGenerationNr() == 0) { int size = pop.size(); for (int i = 0; i < size; i++) { IChromosome chrom = pop.getChromosome(i); chrom.increaseAge(); } } else { // Select fittest chromosome in case it should be preserved and we are // not in the very first generation. // ------------------------------------------------------------------- if (a_conf.isPreserveFittestIndividual()) { /** @todo utilize jobs. In pop do also utilize jobs, especially for fitness computation */ fittest = pop.determineFittestChromosome(0, pop.size() - 1); } } if (a_conf.getGenerationNr() > 0) { // Adjust population size to configured size (if wanted). // Theoretically, this should be done at the end of this method. // But for optimization issues it is not. If it is the last call to // evolve() then the resulting population possibly contains more // chromosomes than the wanted number. But this is no bad thing as // more alternatives mean better chances having a fit candidate. // If it is not the last call to evolve() then the next call will // ensure the correct population size by calling keepPopSizeConstant. // ------------------------------------------------------------------ keepPopSizeConstant(pop, a_conf); } // Ensure fitness value of all chromosomes is udpated. // --------------------------------------------------- if (monitorActive) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf .getMonitor() .event( IEvolutionMonitor.MONITOR_EVENT_BEFORE_UPDATE_CHROMOSOMES1, a_conf.getGenerationNr(), new Object[] {pop}); } updateChromosomes(pop, a_conf); if (monitorActive) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf .getMonitor() .event( IEvolutionMonitor.MONITOR_EVENT_AFTER_UPDATE_CHROMOSOMES1, a_conf.getGenerationNr(), new Object[] {pop}); } // Apply certain NaturalSelectors before GeneticOperators will be executed. // ------------------------------------------------------------------------ pop = applyNaturalSelectors(a_conf, pop, true); // Execute all of the Genetic Operators. // ------------------------------------- applyGeneticOperators(a_conf, pop); // Reset fitness value of genetically operated chromosomes. // Normally, this should not be necessary as the Chromosome class // initializes each newly created chromosome with // FitnessFunction.NO_FITNESS_VALUE. But who knows which Chromosome // implementation is used... // ---------------------------------------------------------------- int currentPopSize = pop.size(); for (int i = originalPopSize; i < currentPopSize; i++) { IChromosome chrom = pop.getChromosome(i); chrom.setFitnessValueDirectly(FitnessFunction.NO_FITNESS_VALUE); // Mark chromosome as new-born. // ---------------------------- chrom.resetAge(); // Mark chromosome as being operated on. // ------------------------------------- chrom.increaseOperatedOn(); } // Increase age of all chromosomes which are not modified by genetic // operations. // ----------------------------------------------------------------- int size = Math.min(originalPopSize, currentPopSize); for (int i = 0; i < size; i++) { IChromosome chrom = pop.getChromosome(i); chrom.increaseAge(); // Mark chromosome as not being operated on. // ----------------------------------------- chrom.resetOperatedOn(); } // If a bulk fitness function has been provided, call it. // ------------------------------------------------------ BulkFitnessFunction bulkFunction = a_conf.getBulkFitnessFunction(); if (bulkFunction != null) { if (monitorActive) { // Monitor that bulk fitness will be called for evaluation. // -------------------------------------------------------- a_conf .getMonitor() .event( IEvolutionMonitor.MONITOR_EVENT_BEFORE_BULK_EVAL, a_conf.getGenerationNr(), new Object[] {bulkFunction, pop}); } /** @todo utilize jobs: bulk fitness function is not so important for a prototype! */ bulkFunction.evaluate(pop); if (monitorActive) { // Monitor that bulk fitness has been called for evaluation. // --------------------------------------------------------- a_conf .getMonitor() .event( IEvolutionMonitor.MONITOR_EVENT_AFTER_BULK_EVAL, a_conf.getGenerationNr(), new Object[] {bulkFunction, pop}); } } // Ensure fitness value of all chromosomes is udpated. // --------------------------------------------------- if (monitorActive) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf .getMonitor() .event( IEvolutionMonitor.MONITOR_EVENT_BEFORE_UPDATE_CHROMOSOMES2, a_conf.getGenerationNr(), new Object[] {pop}); } updateChromosomes(pop, a_conf); if (monitorActive) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf .getMonitor() .event( IEvolutionMonitor.MONITOR_EVENT_AFTER_UPDATE_CHROMOSOMES2, a_conf.getGenerationNr(), new Object[] {pop}); } // Apply certain NaturalSelectors after GeneticOperators have been applied. // ------------------------------------------------------------------------ pop = applyNaturalSelectors(a_conf, pop, false); // Fill up population randomly if size dropped below specified percentage // of original size. // ---------------------------------------------------------------------- if (a_conf.getMinimumPopSizePercent() > 0) { int sizeWanted = a_conf.getPopulationSize(); int popSize; int minSize = (int) Math.round(sizeWanted * (double) a_conf.getMinimumPopSizePercent() / 100); popSize = pop.size(); if (popSize < minSize) { IChromosome newChrom; IChromosome sampleChrom = a_conf.getSampleChromosome(); Class sampleChromClass = sampleChrom.getClass(); IInitializer chromIniter = a_conf.getJGAPFactory().getInitializerFor(sampleChrom, sampleChromClass); while (pop.size() < minSize) { try { /** * @todo utilize jobs as initialization may be time-consuming as invalid combinations * may have to be filtered out */ newChrom = (IChromosome) chromIniter.perform(sampleChrom, sampleChromClass, null); if (monitorActive) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf .getMonitor() .event( IEvolutionMonitor.MONITOR_EVENT_BEFORE_ADD_CHROMOSOME, a_conf.getGenerationNr(), new Object[] {pop, newChrom}); } pop.addChromosome(newChrom); } catch (Exception ex) { throw new RuntimeException(ex); } } } } IChromosome newFittest = reAddFittest(pop, fittest); if (monitorActive && newFittest != null) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf .getMonitor() .event( IEvolutionMonitor.MONITOR_EVENT_READD_FITTEST, a_conf.getGenerationNr(), new Object[] {pop, fittest}); } // Increase number of generations. // ------------------------------- a_conf.incrementGenerationNr(); // Fire an event to indicate we've performed an evolution. // ------------------------------------------------------- m_lastPop = pop; m_lastConf = a_conf; a_conf .getEventManager() .fireGeneticEvent(new GeneticEvent(GeneticEvent.GENOTYPE_EVOLVED_EVENT, this)); return pop; }
/** * Retrieves the number of coins represented by the given potential solution at the given gene * position. * * @param a_potentialSolution the potential solution to evaluate * @param a_position the gene position to evaluate * @return the number of coins represented by the potential solution at the given gene position * @author Neil Rotstan * @since 1.0 */ public static int getNumberOfCoinsAtGene(IChromosome a_potentialSolution, int a_position) { Integer numCoins = (Integer) a_potentialSolution.getGene(a_position).getAllele(); return numCoins.intValue(); }
/** * Returns a copy of this Chromosome. The returned instance can evolve independently of this * instance. Note that, if possible, this method will first attempt to acquire a Chromosome * instance from the active ChromosomePool (if any) and set its value appropriately before * returning it. If that is not possible, then a new Chromosome instance will be constructed and * its value set appropriately before returning. * * @return copy of this Chromosome * @throws IllegalStateException instead of CloneNotSupportedException * @author Neil Rotstan * @author Klaus Meffert * @since 1.0 */ public synchronized Object clone() { // Before doing anything, make sure that a Configuration object // has been set on this Chromosome. If not, then throw an // IllegalStateException. // ------------------------------------------------------------ if (getConfiguration() == null) { throw new IllegalStateException( "The active Configuration object must be set on this " + "Chromosome prior to invocation of the clone() method."); } IChromosome copy = null; // Now, first see if we can pull a Chromosome from the pool and just // set its gene values (alleles) appropriately. // ------------------------------------------------------------ IChromosomePool pool = getConfiguration().getChromosomePool(); if (pool != null) { copy = pool.acquireChromosome(); if (copy != null) { Gene[] genes = copy.getGenes(); for (int i = 0; i < size(); i++) { genes[i].setAllele(getGene(i).getAllele()); } } } try { if (copy == null) { // We couldn't fetch a Chromosome from the pool, so we need to create // a new one. First we make a copy of each of the Genes. We explicity // use the Gene at each respective gene location (locus) to create the // new Gene that is to occupy that same locus in the new Chromosome. // ------------------------------------------------------------------- int size = size(); if (size > 0) { Gene[] copyOfGenes = new Gene[size]; for (int i = 0; i < copyOfGenes.length; i++) { copyOfGenes[i] = getGene(i).newGene(); Object allele = getGene(i).getAllele(); if (allele != null) { IJGAPFactory factory = getConfiguration().getJGAPFactory(); if (factory != null) { ICloneHandler cloner = factory.getCloneHandlerFor(allele, allele.getClass()); if (cloner != null) { try { allele = cloner.perform(allele, null, this); } catch (Exception ex) { throw new RuntimeException(ex); } } } } copyOfGenes[i].setAllele(allele); } // Now construct a new Chromosome with the copies of the genes and // return it. Also clone the IApplicationData object later on. // --------------------------------------------------------------- if (getClass() == Chromosome.class) { copy = new Chromosome(getConfiguration(), copyOfGenes); } else { copy = (IChromosome) getConfiguration().getSampleChromosome().clone(); copy.setGenes(copyOfGenes); } } else { if (getClass() == Chromosome.class) { copy = new Chromosome(getConfiguration()); } else { copy = (IChromosome) getConfiguration().getSampleChromosome().clone(); } } } copy.setFitnessValue(m_fitnessValue); // Clone constraint checker. // ------------------------- copy.setConstraintChecker(getConstraintChecker()); } catch (InvalidConfigurationException iex) { throw new IllegalStateException(iex.getMessage()); } // Also clone the IApplicationData object. // --------------------------------------- try { copy.setApplicationData(cloneObject(getApplicationData())); } catch (Exception ex) { throw new IllegalStateException(ex.getMessage()); } // Clone multi-objective object if necessary and possible. // ------------------------------------------------------- if (m_multiObjective != null) { if (getClass() == Chromosome.class) { try { ((Chromosome) copy).setMultiObjectives((List) cloneObject(m_multiObjective)); } catch (Exception ex) { throw new IllegalStateException(ex.getMessage()); } } } return copy; }
protected void doCrossover( IChromosome firstMate, IChromosome secondMate, List a_candidateChromosomes, RandomGenerator generator) { Gene[] firstGenes = firstMate.getGenes(); Gene[] secondGenes = secondMate.getGenes(); int locus = generator.nextInt(firstGenes.length); // Swap the genes. // --------------- Gene gene1, gene11; Gene gene2, gene22; Integer firstAllele, firstAllele1; Integer secondAllele, secondAllele1; for (int j = locus; j < firstGenes.length; j++) { gene1 = firstGenes[j]; gene2 = secondGenes[j]; firstAllele = (Integer) gene1.getAllele(); secondAllele = (Integer) gene2.getAllele(); if (payload[firstAllele] != null && payload[secondAllele] != null) { if (!checkAlleles(firstMate, j, secondAllele)) gene1.setAllele(secondAllele); if (!checkAlleles(secondMate, j, firstAllele)) gene2.setAllele(firstAllele); } if (payload[firstAllele] == null && payload[secondAllele] == null) { if (payload[64 + firstAllele].getPair() != payload[64 + secondAllele].getPair()) continue; if (payload[64 + firstAllele].getPair() == 1) { if (!checkAlleles(firstMate, j, secondAllele) && !checkAlleles(secondMate, j, firstAllele)) { if (chkonepair(j) || chktwopair(j + 1)) { System.out.println("Crossover.. something wrong"); } gene11 = firstGenes[j + 1]; firstAllele1 = (Integer) gene11.getAllele(); gene22 = secondGenes[j + 1]; secondAllele1 = (Integer) gene22.getAllele(); if (!checkAlleles(firstMate, j + 1, secondAllele1)) { gene1.setAllele(secondAllele); gene11.setAllele(secondAllele1); } if (!checkAlleles(secondMate, j + 1, firstAllele1)) { gene2.setAllele(firstAllele); gene22.setAllele(firstAllele1); } } } else if (payload[64 + firstAllele].getPair() == 2) { if (!checkAlleles(firstMate, j, secondAllele) && !checkAlleles(secondMate, j, firstAllele)) { gene11 = firstGenes[j - 1]; firstAllele1 = (Integer) gene11.getAllele(); gene22 = secondGenes[j - 1]; secondAllele1 = (Integer) gene22.getAllele(); if (!checkAlleles(firstMate, j - 1, secondAllele1)) { gene1.setAllele(secondAllele); gene11.setAllele(secondAllele1); } if (!checkAlleles(secondMate, j - 1, firstAllele1)) { gene2.setAllele(firstAllele); gene22.setAllele(firstAllele1); } } } else { System.out.println("...Invalid Configuration Exception..."); } } } // Add the modified chromosomes to the candidate pool so that // they'll be considered for natural selection during the next // phase of evolution. // ----------------------------------------------------------- a_candidateChromosomes.add(firstMate); a_candidateChromosomes.add(secondMate); }
/** * Compares the given Chromosome to this Chromosome. This chromosome is considered to be "less * than" the given chromosome if it has a fewer number of genes or if any of its gene values * (alleles) are less than their corresponding gene values in the other chromosome. * * @param other the Chromosome against which to compare this chromosome * @return a negative number if this chromosome is "less than" the given chromosome, zero if they * are equal to each other, and a positive number if this chromosome is "greater than" the * given chromosome * @author Neil Rotstan * @author Klaus Meffert * @since 1.0 */ public int compareTo(Object other) { // First, if the other Chromosome is null, then this chromosome is // automatically the "greater" Chromosome. // --------------------------------------------------------------- if (other == null) { return 1; } int size = size(); IChromosome otherChromosome = (IChromosome) other; Gene[] otherGenes = otherChromosome.getGenes(); // If the other Chromosome doesn't have the same number of genes, // then whichever has more is the "greater" Chromosome. // -------------------------------------------------------------- if (otherChromosome.size() != size) { return size() - otherChromosome.size(); } // Next, compare the gene values (alleles) for differences. If // one of the genes is not equal, then we return the result of its // comparison. // --------------------------------------------------------------- for (int i = 0; i < size; i++) { int comparison = getGene(i).compareTo(otherGenes[i]); if (comparison != 0) { return comparison; } } // Compare current fitness value. // ------------------------------ if (m_fitnessValue != otherChromosome.getFitnessValueDirectly()) { FitnessEvaluator eval = getConfiguration().getFitnessEvaluator(); if (eval != null) { if (eval.isFitter(m_fitnessValue, otherChromosome.getFitnessValueDirectly())) { return 1; } else { return -1; } } else { // undetermined order, but unequal! // -------------------------------- return -1; } } if (m_compareAppData) { // Compare application data. // ------------------------- if (getApplicationData() == null) { if (otherChromosome.getApplicationData() != null) { return -1; } } else if (otherChromosome.getApplicationData() == null) { return 1; } else { if (getApplicationData() instanceof Comparable) { try { return ((Comparable) getApplicationData()) .compareTo(otherChromosome.getApplicationData()); } catch (ClassCastException cex) { /** @todo improve */ return -1; } } else { return getApplicationData() .getClass() .getName() .compareTo(otherChromosome.getApplicationData().getClass().getName()); } } } // Everything is equal. Return zero. // --------------------------------- return 0; }