Java tutorial
package sos.base.util.genetic; /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import org.apache.commons.math3.exception.OutOfRangeException; import org.apache.commons.math3.exception.util.LocalizedFormats; import org.apache.commons.math3.genetics.ChromosomePair; import org.apache.commons.math3.genetics.CrossoverPolicy; import org.apache.commons.math3.genetics.MutationPolicy; import org.apache.commons.math3.genetics.Population; import org.apache.commons.math3.genetics.SelectionPolicy; import org.apache.commons.math3.genetics.StoppingCondition; import org.apache.commons.math3.random.JDKRandomGenerator; import org.apache.commons.math3.random.RandomGenerator; /** * Implementation of a genetic algorithm. All factors that govern the operation * of the algorithm can be configured for a specific problem. * * @since 2.0 * @version $Id: GeneticAlgorithm.java 1416643 2012-12-03 19:37:14Z tn $ */ public class SOSGeneticAlgorithm { private RandomGenerator randomGenerator = new JDKRandomGenerator(); /** the crossover policy used by the algorithm. */ private final CrossoverPolicy crossoverPolicy; /** the rate of crossover for the algorithm. */ private final double crossoverRate; /** the mutation policy used by the algorithm. */ private final MutationPolicy mutationPolicy; /** the rate of mutation for the algorithm. */ private final double mutationRate; /** the selection policy used by the algorithm. */ private final SelectionPolicy selectionPolicy; /** the number of generations evolved to reach {@link StoppingCondition} in the last run. */ private int generationsEvolved = 0; private SOSSelectionPolicy sosSelect; /** * Create a new genetic algorithm. * * @param crossoverPolicy * The {@link CrossoverPolicy} * @param crossoverRate * The crossover rate as a percentage (0-1 inclusive) * @param mutationPolicy * The {@link MutationPolicy} * @param mutationRate * The mutation rate as a percentage (0-1 inclusive) * @param selectionPolicy * The {@link SelectionPolicy} * @throws OutOfRangeException * if the crossover or mutation rate is outside the [0, 1] range */ public SOSGeneticAlgorithm(final CrossoverPolicy crossoverPolicy, final double crossoverRate, final MutationPolicy mutationPolicy, final double mutationRate, final SelectionPolicy selectionPolicy, final SOSSelectionPolicy sosSelect) throws OutOfRangeException { this.sosSelect = sosSelect; if (crossoverRate < 0 || crossoverRate > 1) { throw new OutOfRangeException(LocalizedFormats.CROSSOVER_RATE, crossoverRate, 0, 1); } if (mutationRate < 0 || mutationRate > 1) { throw new OutOfRangeException(LocalizedFormats.MUTATION_RATE, mutationRate, 0, 1); } this.crossoverPolicy = crossoverPolicy; this.crossoverRate = crossoverRate; this.mutationPolicy = mutationPolicy; this.mutationRate = mutationRate; this.selectionPolicy = selectionPolicy; } /** * Set the random generator. * * @param random * random generator */ public synchronized void setRandomGenerator(final RandomGenerator random) { randomGenerator = random; } /** * Returns the random generator. * * @return the random generator shared by GA implementation classes */ public synchronized RandomGenerator getRandomGenerator() { return randomGenerator; } /** * Evolve the given population. Evolution stops when the stopping condition * is satisfied. Updates the {@link #getGenerationsEvolved() generationsEvolved} property with the number of generations evolved before the StoppingCondition * is satisfied. * * @param initial * the initial, seed population. * @param condition * the stopping condition used to stop evolution. * @return the population that satisfies the stopping condition. */ public Population evolve(final Population initial, final StoppingCondition condition) { Population current = initial; generationsEvolved = 0; while (!condition.isSatisfied(current)) { current = nextGeneration(current); generationsEvolved++; } return current; } /** * Evolve the given population into the next generation. * <p> * <ol> * <li>Get nextGeneration population to fill from <code>current</code> generation, using its nextGeneration method</li> * <li>Loop until new generation is filled:</li> * <ul> * <li>Apply configured SelectionPolicy to select a pair of parents from <code>current</code></li> * <li>With probability = {@link #getCrossoverRate()}, apply configured {@link CrossoverPolicy} to parents</li> * <li>With probability = {@link #getMutationRate()}, apply configured {@link MutationPolicy} to each of the offspring</li> * <li>Add offspring individually to nextGeneration, space permitting</li> * </ul> * <li>Return nextGeneration</li> * </ol> * * @param current * the current population. * @return the population for the next generation. */ public Population nextGeneration(final Population pop) { SOSListPopulation current = (SOSListPopulation) pop; SOSListPopulation nextGeneration = (SOSListPopulation) current.nextGeneration(); RandomGenerator randGen = getRandomGenerator(); while (nextGeneration.getPopulationSize() < nextGeneration.getPopulationLimit()) { // select parent chromosomes ChromosomePair pair = getSelectionPolicy().select(current); // crossover? if (randGen.nextDouble() < getCrossoverRate()) { // apply crossover policy to create two offspring pair = getCrossoverPolicy().crossover(pair.getFirst(), pair.getSecond()); } // mutation? if (randGen.nextDouble() < getMutationRate()) { // apply mutation policy to the chromosomes pair = new ChromosomePair(getMutationPolicy().mutate(pair.getFirst()), getMutationPolicy().mutate(pair.getSecond())); } // add the first chromosome to the population nextGeneration.addChromosome(pair.getFirst()); // is there still a place for the second chromosome? if (nextGeneration.getPopulationSize() < nextGeneration.getPopulationLimit()) { // add the second chromosome to the population nextGeneration.addChromosome(pair.getSecond()); } } nextGeneration.setPopulationLimit(nextGeneration.getPopulationLimit() + current.getPopulationSize()); nextGeneration.addChromosomes(current.getChromosomes());//adding the current population nextGeneration = (SOSListPopulation) sosSelect.selectNextGeneration(nextGeneration); nextGeneration.setPopulationLimit(current.getPopulationLimit()); return nextGeneration; } /** * Returns the crossover policy. * * @return crossover policy */ public CrossoverPolicy getCrossoverPolicy() { return crossoverPolicy; } /** * Returns the crossover rate. * * @return crossover rate */ public double getCrossoverRate() { return crossoverRate; } /** * Returns the mutation policy. * * @return mutation policy */ public MutationPolicy getMutationPolicy() { return mutationPolicy; } /** * Returns the mutation rate. * * @return mutation rate */ public double getMutationRate() { return mutationRate; } /** * Returns the selection policy. * * @return selection policy */ public SelectionPolicy getSelectionPolicy() { return selectionPolicy; } /** * Returns the number of generations evolved to reach {@link StoppingCondition} in the last run. * * @return number of generations evolved * @since 2.1 */ public int getGenerationsEvolved() { return generationsEvolved; } }