/**
   * 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;
 }