/* * This file is part of JGAP. * * JGAP offers a dual license model containing the LGPL as well as the MPL. * * For licensing information please see the file license.txt included with JGAP * or have a look at the top of class org.jgap.Chromosome which representatively * includes the JGAP license policy applicable for any file delivered with JGAP. */ package examples.supergene; import org.jgap.*; import org.jgap.impl.*; /** * Abstract class for testing Supergene performance. * * @author Neil Rotstan * @author Klaus Meffert * @author Audrius Meskauskas * @since 2.0 * */ public abstract class AbstractSupergeneTest { /** String containing the CVS revision. Read out via reflection!*/ private static final String CVS_REVISION = "$Revision: 1.5 $"; /** * Gene index for the dimes gene */ public static final int DIMES = 0; /** * Gene index for the quarters gene. */ public static final int QUARTERS = 1; /** * Gene index for the nickels gene * Only used in the alternative presentation */ public static final int NICKELS = 2; /** * Gene index for the pennies gene. * Only used in the alternative presentation */ public static final int PENNIES = 3; /** * The total number of times we'll let the population evolve. */ public static int MAX_ALLOWED_EVOLUTIONS = 200; /** * Chromosome size. */ public static int POPULATION_SIZE = 2000; public static boolean REPORT_ENABLED = true; /** * @param a_conf the configuration to use * * @return created Dimes gene instance */ protected Gene getDimesGene(Configuration a_conf) { try { return new IntegerGene(a_conf, 0, 2); // 10? } catch (InvalidConfigurationException iex) { throw new IllegalStateException(iex.getMessage()); } } ; /** * @param a_conf the configuration to use * * @return created Nickels gene instance */ protected Gene getNickelsGene(Configuration a_conf) { try { return new IntegerGene(a_conf, 0, 5); } catch (InvalidConfigurationException iex) { throw new IllegalStateException(iex.getMessage()); } } /** * @param a_conf the configuration to use * * @return created Pennies (1) gene instance */ protected Gene getPenniesGene(Configuration a_conf) { try { return new IntegerGene(a_conf, 0, 7); } catch (InvalidConfigurationException iex) { throw new IllegalStateException(iex.getMessage()); } } /** * @param a_conf the configuration to use * * @return created Quarters gene instance */ protected Gene getQuartersGene(Configuration a_conf) { try { return new IntegerGene(a_conf, 0, 3); } catch (InvalidConfigurationException iex) { throw new IllegalStateException(iex.getMessage()); } } /** Compute the money value from the coin information. */ public static int amountOfChange(int a_numQuarters, int a_numDimes, int a_numNickels, int a_numPennies) { return (a_numQuarters * 25) + (a_numDimes * 10) + (a_numNickels * 5) + a_numPennies; } ; /** * 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 * * @return absolute difference between the required and computed change * amount * @throws Exception */ public abstract int makeChangeForAmount(int a_targetChangeAmount) throws Exception; /** * 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; } /** * If set to true (required for strict tests), only tasks with existing * solutions will be submitted as a test tasks. */ public static boolean EXISTING_SOLUTIONS_ONLY = false; /** * Test the method, returns the sum of all differences between * the required and obtained excange amount. One exception counts * as 1000 on the error score. */ public int test() { int s = 0; int e; for (int amount = 20; amount < 100; amount++) { try { if (REPORT_ENABLED) { System.out.println("EXCHANGING " + amount + " "); } // Do not solve cases without solutions if (EXISTING_SOLUTIONS_ONLY) { if (!Force.solve(amount)) { continue; } } // Need to reset the configuration because it needs to be changed each // time when looping. // ------------------------------------------------------------------- DefaultConfiguration.reset(); e = makeChangeForAmount(amount); if (REPORT_ENABLED) { System.out.println(" err " + e); System.out.println("---------------"); } s = s + e; } catch (Exception ex) { ex.printStackTrace(); s += 1000; } } if (REPORT_ENABLED) { System.out.println("Sum of errors " + s); } return s; } /** * Find and print the solution, return the solution error. * * @param a_conf the configuration to use * * @return absolute difference between the required and computed change */ protected int solve(Configuration a_conf, int a_targetChangeAmount, SupergeneChangeFitnessFunction a_fitnessFunction, Gene[] a_sampleGenes) throws InvalidConfigurationException { IChromosome sampleChromosome = new Chromosome(a_conf, a_sampleGenes); a_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). We'll just set // the population size to 500 here. // ------------------------------------------------------------ a_conf.setPopulationSize(POPULATION_SIZE); // Create random initial population of Chromosomes. // ------------------------------------------------ Genotype population = Genotype.randomInitialGenotype(a_conf); int s; Evolution: // Evolve the population, break if the the change solution is found. // ----------------------------------------------------------------- for (int i = 0; i < MAX_ALLOWED_EVOLUTIONS; i++) { population.evolve(); s = Math.abs(a_fitnessFunction.amountOfChange(population. getFittestChromosome()) - a_targetChangeAmount); if (s == 0) { break Evolution; } } // Display the best solution we found. // ----------------------------------- IChromosome bestSolutionSoFar = report(a_fitnessFunction, population); return Math.abs(a_fitnessFunction.amountOfChange(bestSolutionSoFar) - a_targetChangeAmount); } }