0001 /*
0002 * Java Genetic Algorithm Library (jenetics-1.5.0).
0003 * Copyright (c) 2007-2013 Franz Wilhelmstötter
0004 *
0005 * Licensed under the Apache License, Version 2.0 (the "License");
0006 * you may not use this file except in compliance with the License.
0007 * You may obtain a copy of the License at
0008 *
0009 * http://www.apache.org/licenses/LICENSE-2.0
0010 *
0011 * Unless required by applicable law or agreed to in writing, software
0012 * distributed under the License is distributed on an "AS IS" BASIS,
0013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014 * See the License for the specific language governing permissions and
0015 * limitations under the License.
0016 *
0017 * Author:
0018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
0019 */
0020 package org.jenetics;
0021
0022 import static java.lang.Math.round;
0023 import static java.lang.String.format;
0024 import static java.util.Objects.requireNonNull;
0025 import static org.jenetics.util.arrays.forEach;
0026 import static org.jenetics.util.object.NonNull;
0027 import static org.jenetics.util.object.checkProbability;
0028
0029 import java.util.Collection;
0030 import java.util.concurrent.atomic.AtomicInteger;
0031 import java.util.concurrent.locks.Lock;
0032 import java.util.concurrent.locks.ReentrantLock;
0033
0034 import org.jscience.mathematics.number.Float64;
0035
0036 import org.jenetics.util.Array;
0037 import org.jenetics.util.Concurrency;
0038 import org.jenetics.util.Factory;
0039 import org.jenetics.util.Function;
0040 import org.jenetics.util.Timer;
0041 import org.jenetics.util.functions;
0042
0043 /**
0044 * <h3>Getting started</h3>
0045 *
0046 * The minimum GA setup needs a genotype factory, {@code Factory<Genotype<?>>},
0047 * and a fitness {@link Function}. The {@link Genotype} implements the
0048 * {@link Factory} interface and can therefore be used as prototype for creating
0049 * the initial Population and for creating new random Genotypes.
0050 *
0051 * [code]
0052 * public static void main(final String[] args) {
0053 * final Factory〈Genotype〈BitGene〉〉 gtf = Genotype.valueOf(
0054 * BitChromosome.valueOf(10, 0.5)
0055 * );
0056 * final Function〈Genotype〈BitGene〉 Float64〉 ff = ...
0057 * final GeneticAlgorithm〈BitGene, Float64〉
0058 * ga = new GeneticAlgorithm〈〉(gtf, ff, Optimize.MAXIMUM);
0059 *
0060 * ga.setup();
0061 * ga.evolve(100);
0062 * System.out.println(ga.getBestPhenotype());
0063 * }
0064 * [/code]
0065 *
0066 * <p>
0067 * The genotype factory, {@code gtf}, in the example above will create genotypes
0068 * which consists of one {@link BitChromosome} with length 10. The one to zero
0069 * probability of the newly created genotypes is set to 0.5. The fitness function
0070 * is parametrized with a {@link BitGene} and a {@link Float64}. That means
0071 * that the fitness function is calculating the fitness value as {@link Float64}.
0072 * The return type of the fitness function must be at least a {@link Comparable}.
0073 * The {@code GeneticAlgorithm} object is then created with the genotype factory
0074 * and the fitness function. In this example the GA tries to maximize the fitness
0075 * function. If you want to find the minimal value you have to change the optimize
0076 * parameter from {@code Optimize.MAXIMUM} to {@code Optimize.MINIMUM}. The
0077 * {@code ga.setup()} call creates the initial population and calculates its
0078 * fitness value. Then the GA evolves 100 generations ({@code ga.evolve(100)})
0079 * an prints the best phenotype found so far onto the console.
0080 * </p>
0081 * In a more advanced setup you may want to change the default mutation and/or
0082 * selection strategies.
0083 *
0084 * [code]
0085 * public static void main(final String[] args) {
0086 * ...
0087 * ga.setSelectors(new RouletteWheelSelector〈BitGene〉());
0088 * ga.setAlterers(
0089 * new SinglePointCrossover〈BitGene〉(0.1),
0090 * new Mutator〈BitGene〉(0.01)
0091 * );
0092 *
0093 * ga.setup();
0094 * ga.evolve(100);
0095 * System.out.println(ga.getBestPhenotype());
0096 * }
0097 * [/code]
0098 *
0099 * The selection strategy for offspring and survivors are set to the
0100 * roulette-wheel selector. It is also possible to set the selector for
0101 * offspring and survivors independently with the {@code setOffspringSelector}
0102 * and {@code setSurvivorSelector} methods. The alterers are concatenated, at
0103 * first the crossover (with probability 0.1) is performed and then the
0104 * chromosomes are mutated (with probability 0.01).
0105 * <p/>
0106 *
0107 * <h3>Serialization</h3>
0108 *
0109 * With the serialization mechanism you can write a population to disk and load
0110 * it into an GA at a later time. It can also be used to transfer populations to
0111 * GAs, running on different hosts, over a network link. The IO class, located
0112 * in the {@code org.jenetics.util} package, supports native Java serialization
0113 * and XML serialization. For XML marshaling <em>Jenetics</em> internally uses
0114 * the XML support from the Javolution project.
0115 *
0116 * [code]
0117 * // Writing the population to disk.
0118 * final File file = new File("population.xml");
0119 * IO.xml.write(ga.getPopulation(), file);
0120 *
0121 * // Reading the population from disk.
0122 * Population〈Float64Gene,Float64〉 population =
0123 * (Population〈Float64Gene, Float64〉)IO.xml.read(file);
0124 * ga.setPopulation(population);
0125 * [/code]
0126 *
0127 * @see <a href="http://en.wikipedia.org/wiki/Genetic_algorithm">
0128 * Wikipedia: Genetic algorithm
0129 * </a>
0130 * @see Alterer
0131 * @see Selector
0132 *
0133 * @param <G> The gene type this GA evaluates,
0134 * @param <C> The result type (of the fitness function).
0135 *
0136 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
0137 * @since 1.0
0138 * @version 1.0 — <em>$Date: 2013-12-05 $</em>
0139 */
0140 public class GeneticAlgorithm<
0141 G extends Gene<?, G>,
0142 C extends Comparable<? super C>
0143 >
0144 {
0145
0146 /**
0147 * The default population size used by this GA.
0148 */
0149 public static final int DEFAULT_POPULATION_SIZE = 50;
0150
0151 /**
0152 * The default maximal phenotype age of this GA:
0153 */
0154 public static final int DEFAULT_MAXIMAL_PHENOTYPE_AGE = 70;
0155
0156 /**
0157 * The default offspring fraction used by this GA.
0158 */
0159 public static final double DEFAULT_OFFSPRING_FRACTION = 0.6;
0160
0161
0162 private final Lock _lock = new ReentrantLock(true);
0163
0164 private final Optimize _optimization;
0165
0166 private final Factory<Genotype<G>> _genotypeFactory;
0167 private final Factory<Phenotype<G, C>> _phenotypeFactory;
0168 private final Function<Genotype<G>, C> _fitnessFunction;
0169 private Function<C, C> _fitnessScaler;
0170
0171 private double _offspringFraction = DEFAULT_OFFSPRING_FRACTION;
0172
0173 // Alterers
0174 private Alterer<G> _alterer = CompositeAlterer.valueOf(
0175 new SinglePointCrossover<G>(0.1),
0176 new Mutator<G>(0.05)
0177 );
0178
0179 // Selectors
0180 private Selector<G, C> _survivorSelector = new TournamentSelector<>(3);
0181 private Selector<G, C> _offspringSelector = new TournamentSelector<>(3);
0182
0183 // Population
0184 private int _populationSize = DEFAULT_POPULATION_SIZE;
0185 private Population<G, C> _population = new Population<>(_populationSize);
0186 private int _maximalPhenotypeAge = DEFAULT_MAXIMAL_PHENOTYPE_AGE;
0187 private volatile int _generation = 0;
0188
0189 // Statistics
0190 private Statistics.Calculator<G, C> _calculator = new Statistics.Calculator<>();
0191 private Statistics<G, C> _bestStatistics = null;
0192 private Statistics<G, C> _statistics = null;
0193 private final AtomicInteger _killed = new AtomicInteger(0);
0194 private final AtomicInteger _invalid = new AtomicInteger(0);
0195
0196 //Some performance measure.
0197 private final Timer _executionTimer = new Timer("Execution time");
0198 private final Timer _selectTimer = new Timer("Select time");
0199 private final Timer _alterTimer = new Timer("Alter time");
0200 private final Timer _combineTimer = new Timer("Combine survivors and offspring time");
0201 private final Timer _statisticTimer = new Timer("Statistic time");
0202 private final Timer _evaluateTimer = new Timer("Evaluate time");
0203
0204
0205 /**
0206 * Create a new genetic algorithm.
0207 *
0208 * @param genotypeFactory the genotype factory this GA is working with.
0209 * @param fitnessFunction the fitness function this GA is using.
0210 * @param fitnessScaler the fitness scaler this GA is using.
0211 * @param optimization Determine whether this GA maximize or minimize the
0212 * fitness function.
0213 * @throws NullPointerException if one of the arguments is {@code null}.
0214 */
0215 public GeneticAlgorithm(
0216 final Factory<Genotype<G>> genotypeFactory,
0217 final Function<Genotype<G>, C> fitnessFunction,
0218 final Function<C, C> fitnessScaler,
0219 final Optimize optimization
0220 ) {
0221 _genotypeFactory = requireNonNull(genotypeFactory, "GenotypeFactory");
0222 _fitnessFunction = requireNonNull(fitnessFunction, "FitnessFunction");
0223 _fitnessScaler = requireNonNull(fitnessScaler, "FitnessScaler");
0224 _optimization = requireNonNull(optimization, "Optimization");
0225
0226 _phenotypeFactory = new Factory<Phenotype<G, C>>() {
0227 @Override public Phenotype<G, C> newInstance() {
0228 return Phenotype.valueOf(
0229 _genotypeFactory.newInstance(),
0230 _fitnessFunction,
0231 _fitnessScaler,
0232 _generation
0233 );
0234 }
0235 };
0236 }
0237
0238 /**
0239 * Create a new genetic algorithm. By default the GA tries to maximize the
0240 * fitness function.
0241 *
0242 * @param genotypeFactory the genotype factory this GA is working with.
0243 * @param fitnessFunction the fitness function this GA is using.
0244 * @throws NullPointerException if one of the arguments is {@code null}.
0245 */
0246 public GeneticAlgorithm(
0247 final Factory<Genotype<G>> genotypeFactory,
0248 final Function<Genotype<G>, C> fitnessFunction
0249 ) {
0250 this(
0251 genotypeFactory,
0252 fitnessFunction,
0253 functions.<C>Identity(),
0254 Optimize.MAXIMUM
0255 );
0256 }
0257
0258 /**
0259 * Create a new genetic algorithm.
0260 *
0261 * @param genotypeFactory the genotype factory this GA is working with.
0262 * @param fitnessFunction the fitness function this GA is using.
0263 * @param optimization Determine whether this GA maximize or minimize the
0264 * fitness function.
0265 * @throws NullPointerException if one of the arguments is {@code null}.
0266 */
0267 public GeneticAlgorithm(
0268 final Factory<Genotype<G>> genotypeFactory,
0269 final Function<Genotype<G>, C> fitnessFunction,
0270 final Optimize optimization
0271 ) {
0272 this(
0273 genotypeFactory,
0274 fitnessFunction,
0275 functions.<C>Identity(),
0276 optimization
0277 );
0278 }
0279
0280 /**
0281 * Create a new genetic algorithm. By default the GA tries to maximize the
0282 * fitness function.
0283 *
0284 * @param genotypeFactory the genotype factory this GA is working with.
0285 * @param fitnessFunction the fitness function this GA is using.
0286 * @param fitnessScaler the fitness scaler this GA is using.
0287 * @throws NullPointerException if one of the arguments is {@code null}.
0288 */
0289 public GeneticAlgorithm(
0290 final Factory<Genotype<G>> genotypeFactory,
0291 final Function<Genotype<G>, C> fitnessFunction,
0292 final Function<C, C> fitnessScaler
0293 ) {
0294 this(
0295 genotypeFactory,
0296 fitnessFunction,
0297 fitnessScaler,
0298 Optimize.MAXIMUM
0299 );
0300 }
0301
0302 /**
0303 * Create the initial population of the GA. Subsequent calls to this
0304 * method throw IllegalStateException. If no initial population has been
0305 * set (with {@link #setPopulation(Collection)} or
0306 * {@link #setGenotypes(Collection)}) a random population is generated.
0307 *
0308 * @throws IllegalStateException if called more than once.
0309 */
0310 public void setup() {
0311 _lock.lock();
0312 try {
0313 prepareSetup();
0314 _population.fill(
0315 _phenotypeFactory,
0316 _populationSize - _population.size()
0317 );
0318 finishSetup();
0319 } finally {
0320 _lock.unlock();
0321 }
0322 }
0323
0324 /**
0325 * Setting up the {@code GeneticAlgorithm} with the given initial
0326 * population. Subsequent calls to this method throw an IllegalStateException.
0327 * This method is similar to the {@link #setGenotypes(Collection)} and
0328 * {@link #setPopulation(Collection)} methods, but this method is required
0329 * to be called only once and before starting evaluation. It also calculates
0330 * the timing statistics when (calculating the fitness values for the given
0331 * genotypes.
0332 *
0333 * @see #setGenotypes(Collection)
0334 * @see #setPopulation(Collection)
0335 * @param genotypes the initial population.
0336 * @throws IllegalStateException if called more than once.
0337 */
0338 public void setup(final Collection<Genotype<G>> genotypes) {
0339 _lock.lock();
0340 try {
0341 prepareSetup();
0342 setGenotypes(genotypes);
0343 finishSetup();
0344 } finally {
0345 _lock.unlock();
0346 }
0347 }
0348
0349 private void prepareSetup() {
0350 if (_generation > 0) {
0351 throw new IllegalStateException(
0352 "The method GeneticAlgorithm.setup() must be called only once."
0353 );
0354 }
0355
0356 ++_generation;
0357 _executionTimer.start();
0358 }
0359
0360 private void finishSetup() {
0361 //Evaluate the fitness.
0362 evaluate();
0363
0364 //First valuation of the initial population.
0365 _statisticTimer.start();
0366 _statistics = _calculator.evaluate(
0367 _population, _generation, _optimization
0368 ).build();
0369
0370 _bestStatistics = _statistics;
0371 _statisticTimer.stop();
0372
0373 _executionTimer.stop();
0374
0375 setTimes(_statistics);
0376 }
0377
0378 /**
0379 * Evolve one generation.
0380 *
0381 * @throws IllegalStateException if the {@link GeneticAlgorithm#setup()}
0382 * method was not called first.
0383 */
0384 public void evolve() {
0385 _lock.lock();
0386 try {
0387 // Check the setup state.
0388 if (_generation == 0) {
0389 throw new IllegalStateException(
0390 "Call the GeneticAlgorithm.setup() method before " +
0391 "calling GeneticAlgorithm.evolve()."
0392 );
0393 }
0394
0395 //Start the overall execution timer.s
0396 _executionTimer.start();
0397
0398 //Increment the generation and the generation.
0399 ++_generation;
0400
0401 //Select the survivors and the offsprings.
0402 _selectTimer.start();
0403 final Array<Population<G, C>> selection = select();
0404 final Population<G, C> survivors = selection.get(0);
0405 final Population<G, C> offsprings = selection.get(1);
0406 _selectTimer.stop();
0407
0408 //Alter the offsprings (Recombination, Mutation ...).
0409 _alterTimer.start();
0410 _alterer.alter(offsprings, _generation);
0411 _alterTimer.stop();
0412
0413 // Combining the new population (containing the survivors and the
0414 // altered offsprings).
0415 _combineTimer.start();
0416 final int killed = _killed.get();
0417 final int invalid = _invalid.get();
0418 _population = combine(survivors, offsprings);
0419 _combineTimer.stop();
0420
0421 //Evaluate the fitness
0422 evaluate();
0423
0424 //Evaluate the statistic
0425 _statisticTimer.start();
0426 final Statistics.Builder<G, C> builder = _calculator.evaluate(
0427 _population, _generation, _optimization
0428 );
0429 builder.killed(_killed.get() - killed);
0430 builder.invalid(_invalid.get() - invalid);
0431 _statistics = builder.build();
0432
0433 final int comp = _optimization.compare(
0434 _statistics.getBestPhenotype(),
0435 _bestStatistics.getBestPhenotype()
0436 );
0437
0438 if (comp > 0) {
0439 _bestStatistics = _statistics;
0440 }
0441
0442 _statisticTimer.stop();
0443
0444 _executionTimer.stop();
0445
0446 setTimes(_statistics);
0447 } finally {
0448 _lock.unlock();
0449 }
0450 }
0451
0452 private void setTimes(final Statistics<?, ?> statistic) {
0453 statistic.getTime().execution.set(_executionTimer.getInterimTime());
0454 statistic.getTime().selection.set(_selectTimer.getInterimTime());
0455 statistic.getTime().alter.set(_alterTimer.getInterimTime());
0456 statistic.getTime().combine.set(_combineTimer.getInterimTime());
0457 statistic.getTime().evaluation.set(_evaluateTimer.getInterimTime());
0458 statistic.getTime().statistics.set(_statisticTimer.getInterimTime());
0459 }
0460
0461 private void evaluate() {
0462 _evaluateTimer.start();
0463 try (Concurrency c = Concurrency.start()) {
0464 for (int i = _population.size(); --i >= 0;) {
0465 c.execute(_population.get(i));
0466 }
0467 }
0468 _evaluateTimer.stop();
0469 }
0470
0471 /**
0472 * Evolve the given number of {@code generations}
0473 *
0474 * @param generations the number of {@code generations} to evolve.
0475 */
0476 public void evolve(final int generations) {
0477 for (int i = 0; i < generations; ++i) {
0478 evolve();
0479 }
0480 }
0481
0482 /**
0483 * Evolve the GA as long the given {@link Function} returns {@code true}.
0484 *
0485 * @see termination
0486 *
0487 * @param until the predicate which defines the termination condition.
0488 * @throws NullPointerException if the given predicate is {@code null}.
0489 */
0490 public void evolve(final Function<? super Statistics<G, C>, Boolean> until) {
0491 requireNonNull(until, "Termination condition");
0492 while (until.apply(getStatistics())) {
0493 evolve();
0494 }
0495 }
0496
0497 private Array<Population<G, C>> select() {
0498 final Array<Population<G, C>> selection = new Array<>(2);
0499 final int numberOfSurvivors = getNumberOfSurvivors();
0500 final int numberOfOffspring = getNumberOfOffsprings();
0501 assert (numberOfSurvivors + numberOfOffspring == _populationSize);
0502
0503 try (Concurrency c = Concurrency.start()) {
0504 c.execute(new Runnable() { @Override public void run() {
0505 final Population<G, C> survivors = _survivorSelector.select(
0506 _population, numberOfSurvivors, _optimization
0507 );
0508
0509 assert (survivors.size() == numberOfSurvivors);
0510 selection.set(0, survivors);
0511 }});
0512
0513 final Population<G, C> offsprings = _offspringSelector.select(
0514 _population, numberOfOffspring, _optimization
0515 );
0516
0517 assert (offsprings.size() == numberOfOffspring);
0518 selection.set(1, offsprings);
0519 }
0520
0521 return selection;
0522 }
0523
0524 private Population<G, C> combine(
0525 final Population<G, C> survivors,
0526 final Population<G, C> offsprings
0527 ) {
0528 assert (survivors.size() + offsprings.size() == _populationSize);
0529 final Population<G, C> population = new Population<>(_populationSize);
0530
0531 try (Concurrency c = Concurrency.start()) {
0532 // Kill survivors which are to old and replace it with new one.
0533 c.execute(new Runnable() { @Override public void run() {
0534 for (int i = 0, n = survivors.size(); i < n; ++i) {
0535 final Phenotype<G, C> survivor = survivors.get(i);
0536
0537 final boolean isTooOld =
0538 survivor.getAge(_generation) > _maximalPhenotypeAge;
0539
0540 final boolean isInvalid = isTooOld || !survivor.isValid();
0541
0542 // Sorry, too old or not valid.
0543 if (isInvalid) {
0544 survivors.set(i, _phenotypeFactory.newInstance());
0545 }
0546
0547 if (isTooOld) {
0548 _killed.incrementAndGet();
0549 } else if (isInvalid) {
0550 _invalid.incrementAndGet();
0551 }
0552 }
0553 }});
0554
0555 // In the mean time we can add the offsprings.
0556 population.addAll(offsprings);
0557 }
0558
0559 population.addAll(survivors);
0560
0561 return population;
0562 }
0563
0564 private int getNumberOfSurvivors() {
0565 return _populationSize - getNumberOfOffsprings();
0566 }
0567
0568 private int getNumberOfOffsprings() {
0569 return (int)round(
0570 _offspringFraction*_populationSize
0571 );
0572 }
0573
0574 /**
0575 * Return {@code true} if the {@link #setup()} method has already been called,
0576 * {@code false} otherwise.
0577 *
0578 * @return {@code true} if the {@link #setup()} method has already been called,
0579 * {@code false} otherwise.
0580 */
0581 public boolean isInitialized() {
0582 _lock.lock();
0583 try {
0584 return _generation > 0;
0585 } finally {
0586 _lock.unlock();
0587 }
0588 }
0589
0590 /**
0591 * <p>
0592 * If you are using the {@code GeneticAlgorithm} in an threaded environment
0593 * and you want to change some of the GAs parameters you can use the returned
0594 * {@link Lock} to synchronize your parameter changes. The GA acquires the
0595 * lock at the begin of the {@link #setup()} and the {@link #evolve()}
0596 * methods and releases it at the end of these methods.
0597 * </p>
0598 * To set one ore more GA parameter you will write code like this:
0599 * [code]
0600 * final GeneticAlgorithm〈Float64Gene, Float64〉 ga = ...
0601 * final Function〈GeneticAlgorithm〈?, ?〉, Boolean〉 until = ...
0602 *
0603 * //Starting the GA in separate thread.
0604 * final Thread thread = new Thread(new Runnable() {
0605 * public void run() {
0606 * while (!Thread.currentThread().isInterrupted() &&
0607 * !until.apply(ga))
0608 * {
0609 * if (ga.getGeneration() == 0) {
0610 * ga.setup();
0611 * } else {
0612 * ga.evolve();
0613 * }
0614 * }
0615 * }
0616 * });
0617 * thread.start();
0618 *
0619 * //Changing the GA parameters outside the evolving thread. All parameters
0620 * //are changed before the next evolve step.
0621 * ga.getLock().lock();
0622 * try {
0623 * ga.setAlterer(new Mutation(0.02);
0624 * ga.setPopulationSize(55);
0625 * ga.setMaximalPhenotypeAge(30);
0626 * } finally {
0627 * ga.getLock().unlock();
0628 * }
0629 * [/code]
0630 *
0631 * You can use the same lock if you want get a consistent state of the used
0632 * parameters, if they where changed within an other thread.
0633 *
0634 * [code]
0635 * ga.getLock().lock();
0636 * try {
0637 * final Statistics〈?, ?〉 statistics = ga.getStatistic();
0638 * final Function〈?, ?〉 scaler = ga.getFitnessScaler();
0639 * } finally {
0640 * ga.getLock().unlock();
0641 * }
0642 * [/code]
0643 *
0644 * The code above ensures that the returned {@code statistics} and
0645 * {@code scaler} where used together within the same {@link #evolve()} step.
0646 *
0647 * @return the lock acquired in the {@link #setup()} and the {@link #evolve()}
0648 * method.
0649 */
0650 public Lock getLock() {
0651 return _lock;
0652 }
0653
0654 /**
0655 * Return the used genotype {@link Factory} of the GA. The genotype factory
0656 * is used for creating the initial population and new, random individuals
0657 * when needed (as replacement for invalid and/or died genotypes).
0658 *
0659 * @return the used genotype {@link Factory} of the GA.
0660 */
0661 public Factory<Genotype<G>> getGenotypeFactory() {
0662 return _genotypeFactory;
0663 }
0664
0665 /**
0666 * <p>
0667 * Return the used fitness {@link Function} of the GA. The fitness function
0668 * is also an important part when modeling the GA. It takes a genotype as
0669 * argument and returns, at least, a Comparable object as result---the
0670 * fitness value. This allows the GA, respectively the selection operators,
0671 * to select the offspring- and survivor population. Some selectors have
0672 * stronger requirements to the fitness value than a Comparable, but this
0673 * constraints is checked by the Java type system at compile time.
0674 * </p>
0675 * The following example shows the simplest possible fitness function. It's
0676 * the identity function and returns the allele of an 1x1 float genotype.
0677 * [code]
0678 * class Id implements Function〈Genotype〈Float64Gene〉, Float64〉 {
0679 * public Float64 apply(final Genotype〈Float64Gene〉 genotype) {
0680 * return genotype.getGene().getAllele();
0681 * }
0682 * }
0683 * [/code]
0684 * The first type parameter of the {@link Function} defines the kind of
0685 * genotype from which the fitness value is calculated and the second type
0686 * parameter determines the return type. As already mentioned, the return
0687 * type must implement the {@link Comparable} interface.
0688 *
0689 * @return the used fitness {@link Function} of the GA.
0690 */
0691 public Function<Genotype<G>, C> getFitnessFunction() {
0692 return _fitnessFunction;
0693 }
0694
0695 /**
0696 * Set the currently used fitness scaler. The fitness value, calculated by
0697 * the fitness function, is the raw-fitness of an individual. The
0698 * <em>Jenetics</em> library allows you to apply an additional scaling
0699 * function on the raw-fitness to form the fitness value which is used by
0700 * the selectors. This can be useful when using probability selectors, where
0701 * the actual amount of the fitness value influences the selection
0702 * probability. In such cases, the fitness scaler gives you additional
0703 * flexibility when selecting offspring and survivors. In the default
0704 * configuration the raw-fitness is equal to the actual fitness value, that
0705 * means, the used fitness scaler is the identity function.
0706 * [code]
0707 * class Sqrt extends Function〈Float64, Float64〉 {
0708 * public Float64 apply(final Float64 value) {
0709 * return Float64.valueOf(sqrt(value.doubleValue()));
0710 * }
0711 * }
0712 * [/code]
0713 *
0714 * <p>
0715 * The listing above shows a fitness scaler which reduces the the raw-fitness
0716 * to its square root. This gives weaker individuals a greater changes being
0717 * selected and weakens the influence of super-individuals.
0718 * </p>
0719 * When using a fitness scaler you have to take care, that your scaler
0720 * doesn't destroy your fitness value. This can be the case when your
0721 * fitness value is negative and your fitness scaler squares the value.
0722 * Trying to find the minimum will not work in this configuration.</b>
0723 *
0724 * @param scaler The fitness scaler.
0725 * @throws NullPointerException if the scaler is {@code null}.
0726 */
0727 public void setFitnessScaler(final Function<C, C> scaler) {
0728 _fitnessScaler = requireNonNull(scaler, "FitnessScaler");
0729 }
0730
0731 /**
0732 * Return the currently used fitness scaler {@link Function} of the GA.
0733 *
0734 * @return the currently used fitness scaler {@link Function} of the GA.
0735 */
0736 public Function<C, C> getFitnessScaler() {
0737 return _fitnessScaler;
0738 }
0739
0740 /**
0741 * Return the currently used offspring fraction of the GA.
0742 *
0743 * @return the currently used offspring fraction of the GA.
0744 */
0745 public double getOffspringFraction() {
0746 return _offspringFraction;
0747 }
0748
0749 /**
0750 * Return the currently used offspring {@link Selector} of the GA.
0751 *
0752 * @return the currently used offspring {@link Selector} of the GA.
0753 */
0754 public Selector<G, C> getOffspringSelector() {
0755 return _offspringSelector;
0756 }
0757
0758 /**
0759 * Return the currently used survivor {@link Selector} of the GA.
0760 *
0761 * @return the currently used survivor {@link Selector} of the GA.
0762 */
0763 public Selector<G, C> getSurvivorSelector() {
0764 return _survivorSelector;
0765 }
0766
0767 /**
0768 * Return the currently used {@link Alterer} of the GA.
0769 *
0770 * @return the currently used {@link Alterer} of the GA.
0771 */
0772 public Alterer<G> getAlterer() {
0773 return _alterer;
0774 }
0775
0776 /**
0777 * Return the current overall generation.
0778 *
0779 * @return the current overall generation.
0780 */
0781 public int getGeneration() {
0782 return _generation;
0783 }
0784
0785 /**
0786 * Return the maximal age of the {@link Phenotype}s.
0787 *
0788 * @return the maximal age of the {@link Phenotype}s.
0789 */
0790 public int getMaximalPhenotypeAge() {
0791 return _maximalPhenotypeAge;
0792 }
0793
0794 /**
0795 * Return the best {@link Phenotype} so far or {@code null} if the GA hasn't
0796 * been initialized yet.
0797 *
0798 * @return the best {@link Phenotype} so far or {@code null} if the GA hasn't
0799 * been initialized yet.
0800 */
0801 public Phenotype<G, C> getBestPhenotype() {
0802 return _bestStatistics != null ? _bestStatistics.getBestPhenotype() : null;
0803 }
0804
0805 /**
0806 * Return the current {@link Population} {@link Statistics} or {@code null}
0807 * if the GA hasn't been initialized yet.
0808 *
0809 * @return the current {@link Population} {@link Statistics} or {@code null}
0810 * if the GA hasn't been initialized yet.
0811 */
0812 public Statistics<G, C> getStatistics() {
0813 return _statistics;
0814 }
0815
0816 /**
0817 * Set the offspring selector.
0818 *
0819 * @param selector The offspring selector.
0820 * @throws NullPointerException, if the given selector is null.
0821 */
0822 public void setOffspringSelector(final Selector<G, C> selector) {
0823 _offspringSelector = requireNonNull(selector, "Offspring selector");
0824 }
0825
0826 /**
0827 * Set the survivor selector.
0828 *
0829 * @param selector The survivor selector.
0830 * @throws NullPointerException, if the given selector is null.
0831 */
0832 public void setSurvivorSelector(final Selector<G, C> selector) {
0833 _survivorSelector = requireNonNull(selector, "Survivor selector");
0834 }
0835
0836 /**
0837 * Set both, the offspring selector and the survivor selector.
0838 *
0839 * @param selector The selector for the offspring and the survivors.
0840 * @throws NullPointerException if the {@code selector} is {@code null}
0841 */
0842 public void setSelectors(final Selector<G, C> selector) {
0843 setOffspringSelector(selector);
0844 setSurvivorSelector(selector);
0845 }
0846
0847 /**
0848 * Set the offspring fraction.
0849 *
0850 * @param offspringFraction The offspring fraction.
0851 * @throws IllegalArgumentException if the offspring fraction is out of
0852 * range.
0853 */
0854 public void setOffspringFraction(final double offspringFraction) {
0855 _offspringFraction = checkProbability(offspringFraction);
0856 }
0857
0858 /**
0859 * Set the alterer.
0860 *
0861 * @param alterer The alterer.
0862 * @throws NullPointerException if the alterer is null.
0863 */
0864 public void setAlterer(final Alterer<G> alterer) {
0865 _alterer = requireNonNull(alterer, "Alterer");
0866 }
0867
0868 /**
0869 * Set the given alterers.
0870 *
0871 * @param alterers the alterers to set.
0872 * @throws NullPointerException if the alterers are null.
0873 */
0874 @SafeVarargs
0875 public final void setAlterers(final Alterer<G>... alterers) {
0876 setAlterer(CompositeAlterer.valueOf(alterers));
0877 }
0878
0879 /**
0880 * Set the maximum age of the phenotypes in the population.
0881 *
0882 * @param age Maximal phenotype age.
0883 * @throws IllegalArgumentException if the age is smaller then one.
0884 */
0885 public void setMaximalPhenotypeAge(final int age) {
0886 if (age < 1) {
0887 throw new IllegalArgumentException(format(
0888 "Phenotype age must be greater than one, but was %s.", age
0889 ));
0890 }
0891 _maximalPhenotypeAge = age;
0892 }
0893
0894 /**
0895 * Set the desired population size.
0896 *
0897 * @param size The population size.
0898 * @throws IllegalArgumentException if the population size is smaller than
0899 * one.
0900 */
0901 public void setPopulationSize(final int size) {
0902 if (size < 1) {
0903 throw new IllegalArgumentException(format(
0904 "Population size must be greater than zero, but was %s.", size
0905 ));
0906 }
0907 _populationSize = size;
0908 }
0909
0910 /**
0911 * Set the (initial) population in form of a list of phenotypes. The fitness
0912 * function and fitness scaler of the phenotypes will be changed with the
0913 * current one of this GA. The fitness values are calculated as needed by
0914 * the next <i>evolve</i> step. <em>This method doesn't acquire the GA lock.
0915 * When used from another thread, the lock must be acquired from outside.</em>
0916 *
0917 * @see #setGenotypes(Collection)
0918 * @see #setup(Collection)
0919 * @param population The list of phenotypes to set. The population size is
0920 * set to {@code phenotype.size()}.
0921 * @throws NullPointerException if the population, or one of its element, is
0922 * {@code null}.
0923 * @throws IllegalArgumentException it the population size is smaller than
0924 * one.
0925 */
0926 public void setPopulation(final Collection<Phenotype<G, C>> population) {
0927 forEach(population, NonNull);
0928 if (population.size() < 1) {
0929 throw new IllegalArgumentException(format(
0930 "Population size must be greater than zero, but was %s.",
0931 population.size()
0932 ));
0933 }
0934
0935 final Population<G, C> pop = new Population<>(population.size());
0936 for (Phenotype<G, C> phenotype : population) {
0937 pop.add(phenotype.newInstance(
0938 _fitnessFunction, _fitnessScaler, _generation
0939 ));
0940 }
0941
0942 _population = pop;
0943 _populationSize = population.size();
0944 }
0945
0946 /**
0947 * Set/change the population in form of a list of genotypes. The fitness
0948 * function and fitness scaler will not be changed. The fitness values are
0949 * calculated as needed by the next <i>evolve</i> step. <em>This method
0950 * doesn't acquire the GA lock. When used from another thread, the lock must
0951 * be acquired from outside.</em>
0952 *
0953 * @see #setPopulation(Collection)
0954 * @see #setup(Collection)
0955 * @param genotypes The list of genotypes to set. The population size is set
0956 * to {@code genotypes.size()}.
0957 * @throws NullPointerException if the population, or one of its elements,
0958 * is {@code null}s.
0959 * @throws IllegalArgumentException it the population size is smaller than
0960 * one.
0961 */
0962 public void setGenotypes(final Collection<Genotype<G>> genotypes) {
0963 forEach(genotypes, NonNull);
0964 if (genotypes.size() < 1) {
0965 throw new IllegalArgumentException(
0966 "Genotype size must be greater than zero, but was " +
0967 genotypes.size() + ". "
0968 );
0969 }
0970
0971 final Population<G, C> population = new Population<>(genotypes.size());
0972 for (Genotype<G> genotype : genotypes) {
0973 population.add(Phenotype.valueOf(
0974 genotype,
0975 _fitnessFunction,
0976 _fitnessScaler,
0977 _generation
0978 ));
0979 }
0980
0981 _population = population;
0982 _populationSize = genotypes.size();
0983 }
0984
0985 /**
0986 * Return a copy of the current population.
0987 *
0988 * @return The copy of the current population.
0989 */
0990 public Population<G, C> getPopulation() {
0991 return new Population<>(_population);
0992 }
0993
0994 /**
0995 * Return the desired population size of the GA.
0996 *
0997 * @return the desired population size of the GA.
0998 */
0999 public int getPopulationSize() {
1000 return _populationSize;
1001 }
1002
1003 /**
1004 * Return the statistics of the best phenotype. The returned statistics is
1005 * {@code null} if the algorithms hasn't been initialized.
1006 *
1007 * @return the statistics of the best phenotype, or {@code null} if the GA
1008 * hasn't been initialized yet.
1009 */
1010 public Statistics<G, C> getBestStatistics() {
1011 return _bestStatistics;
1012 }
1013
1014 /**
1015 * Return the number of killed phenotypes, so far.
1016 *
1017 * @return the number of killed phenotypes
1018 */
1019 public int getNumberOfKilledPhenotypes() {
1020 return _killed.get();
1021 }
1022
1023 /**
1024 * Return the number of invalid phenotypes, so far.
1025 *
1026 * @return the number of invalid phenotypes
1027 */
1028 public int getNumberOfInvalidPhenotypes() {
1029 return _invalid.get();
1030 }
1031
1032 /**
1033 * Set the statistic calculator for this genetic algorithm instance.
1034 *
1035 * @param calculator the new statistic calculator.
1036 * @throws NullPointerException if the given {@code calculator} is
1037 * {@code null}.
1038 */
1039 public void setStatisticsCalculator(
1040 final Statistics.Calculator<G, C> calculator
1041 ) {
1042 _calculator = requireNonNull(calculator, "Statistic calculator");
1043 }
1044
1045 /**
1046 * Return the current statistics calculator.
1047 *
1048 * @return the current statistics calculator.
1049 */
1050 public Statistics.Calculator<G, C> getStatisticsCalculator() {
1051 return _calculator;
1052 }
1053
1054 /**
1055 * Return the current time statistics of the GA. This method acquires the
1056 * lock to ensure that the returned values are consistent.
1057 *
1058 * @return the current time statistics.
1059 */
1060 public Statistics.Time getTimeStatistics() {
1061 _lock.lock();
1062 try {
1063 final Statistics.Time time = new Statistics.Time();
1064 time.alter.set(_alterTimer.getTime());
1065 time.combine.set(_combineTimer.getTime());
1066 time.evaluation.set(_evaluateTimer.getTime());
1067 time.execution.set(_executionTimer.getTime());
1068 time.selection.set(_selectTimer.getTime());
1069 time.statistics.set(_statisticTimer.getTime());
1070 return time;
1071 } finally {
1072 _lock.unlock();
1073 }
1074 }
1075
1076 /**
1077 * This method acquires the lock to ensure that the returned value is
1078 * consistent.
1079 */
1080 @Override
1081 public String toString() {
1082 Phenotype<G, C> phenotype = null;
1083 int generation = 0;
1084
1085 _lock.lock();
1086 try {
1087 generation = _generation;
1088 phenotype = getStatistics().getBestPhenotype();
1089 } finally {
1090 _lock.unlock();
1091 }
1092
1093 return format("%4d: (best) %s", generation, phenotype);
1094 }
1095
1096 }
1097
1098
1099
1100
1101
1102
|