0001 /*
0002 * Java Genetic Algorithm Library (jenetics-4.2.0).
0003 * Copyright (c) 2007-2018 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@gmail.com)
0019 */
0020 package io.jenetics.engine;
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 io.jenetics.internal.util.require.probability;
0026
0027 import java.time.Clock;
0028 import java.util.Iterator;
0029 import java.util.Objects;
0030 import java.util.concurrent.CompletableFuture;
0031 import java.util.concurrent.Executor;
0032 import java.util.concurrent.ForkJoinPool;
0033 import java.util.function.Function;
0034 import java.util.function.Predicate;
0035 import java.util.function.Supplier;
0036 import java.util.function.UnaryOperator;
0037 import java.util.stream.Stream;
0038
0039 import io.jenetics.Alterer;
0040 import io.jenetics.AltererResult;
0041 import io.jenetics.Chromosome;
0042 import io.jenetics.Gene;
0043 import io.jenetics.Genotype;
0044 import io.jenetics.Mutator;
0045 import io.jenetics.Optimize;
0046 import io.jenetics.Phenotype;
0047 import io.jenetics.Selector;
0048 import io.jenetics.SinglePointCrossover;
0049 import io.jenetics.TournamentSelector;
0050 import io.jenetics.internal.util.require;
0051 import io.jenetics.util.Copyable;
0052 import io.jenetics.util.Factory;
0053 import io.jenetics.util.ISeq;
0054 import io.jenetics.util.MSeq;
0055 import io.jenetics.util.NanoClock;
0056 import io.jenetics.util.Seq;
0057
0058 /**
0059 * Genetic algorithm <em>engine</em> which is the main class. The following
0060 * example shows the main steps in initializing and executing the GA.
0061 *
0062 * <pre>{@code
0063 * public class RealFunction {
0064 * // Definition of the fitness function.
0065 * private static Double eval(final Genotype<DoubleGene> gt) {
0066 * final double x = gt.getGene().doubleValue();
0067 * return cos(0.5 + sin(x))*cos(x);
0068 * }
0069 *
0070 * public static void main(String[] args) {
0071 * // Create/configuring the engine via its builder.
0072 * final Engine<DoubleGene, Double> engine = Engine
0073 * .builder(
0074 * RealFunction::eval,
0075 * DoubleChromosome.of(0.0, 2.0*PI))
0076 * .populationSize(500)
0077 * .optimize(Optimize.MINIMUM)
0078 * .alterers(
0079 * new Mutator<>(0.03),
0080 * new MeanAlterer<>(0.6))
0081 * .build();
0082 *
0083 * // Execute the GA (engine).
0084 * final Phenotype<DoubleGene, Double> result = engine.stream()
0085 * // Truncate the evolution stream if no better individual could
0086 * // be found after 5 consecutive generations.
0087 * .limit(bySteadyFitness(5))
0088 * // Terminate the evolution after maximal 100 generations.
0089 * .limit(100)
0090 * .collect(toBestPhenotype());
0091 * }
0092 * }
0093 * }</pre>
0094 *
0095 * The architecture allows to decouple the configuration of the engine from the
0096 * execution. The {@code Engine} is configured via the {@code Engine.Builder}
0097 * class and can't be changed after creation. The actual <i>evolution</i> is
0098 * performed by the {@link EvolutionStream}, which is created by the
0099 * {@code Engine}.
0100 *
0101 * @implNote
0102 * This class is thread safe:
0103 * No mutable state is maintained by the engine. Therefore it is save to
0104 * create multiple evolution streams with one engine, which may be actually
0105 * used in different threads.
0106 *
0107 * @see Engine.Builder
0108 * @see EvolutionStart
0109 * @see EvolutionResult
0110 * @see EvolutionStream
0111 * @see EvolutionStatistics
0112 * @see Codec
0113 *
0114 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
0115 * @since 3.0
0116 * @version 4.1
0117 */
0118 @SuppressWarnings("deprecation")
0119 public final class Engine<
0120 G extends Gene<?, G>,
0121 C extends Comparable<? super C>
0122 >
0123 implements
0124 Function<EvolutionStart<G, C>, EvolutionResult<G, C>>,
0125 EvolutionStreamable<G, C>,
0126 EvolutionIterable<G, C>
0127 {
0128
0129 // Problem definition.
0130 private final Function<? super Genotype<G>, ? extends C> _fitnessFunction;
0131 private final Factory<Genotype<G>> _genotypeFactory;
0132
0133 // Evolution parameters.
0134 private final Function<? super C, ? extends C> _fitnessScaler;
0135 private final Selector<G, C> _survivorsSelector;
0136 private final Selector<G, C> _offspringSelector;
0137 private final Alterer<G, C> _alterer;
0138 private final Predicate<? super Phenotype<G, C>> _validator;
0139 private final Optimize _optimize;
0140 private final int _offspringCount;
0141 private final int _survivorsCount;
0142 private final long _maximalPhenotypeAge;
0143
0144 // Execution context for concurrent execution of evolving steps.
0145 private final TimedExecutor _executor;
0146 private final Evaluator<G, C> _evaluator;
0147 private final Clock _clock;
0148
0149 // Additional parameters.
0150 private final int _individualCreationRetries;
0151 private final UnaryOperator<EvolutionResult<G, C>> _mapper;
0152
0153
0154 /**
0155 * Create a new GA engine with the given parameters.
0156 *
0157 * @param fitnessFunction the fitness function this GA is using.
0158 * @param genotypeFactory the genotype factory this GA is working with.
0159 * @param fitnessScaler the fitness scaler this GA is using.
0160 * @param survivorsSelector the selector used for selecting the survivors
0161 * @param offspringSelector the selector used for selecting the offspring
0162 * @param alterer the alterer used for altering the offspring
0163 * @param validator phenotype validator which can override the default
0164 * implementation the {@link Phenotype#isValid()} method.
0165 * @param optimize the kind of optimization (minimize or maximize)
0166 * @param offspringCount the number of the offspring individuals
0167 * @param survivorsCount the number of the survivor individuals
0168 * @param maximalPhenotypeAge the maximal age of an individual
0169 * @param executor the executor used for executing the single evolve steps
0170 * @param evaluator the population fitness evaluator
0171 * @param clock the clock used for calculating the timing results
0172 * @param individualCreationRetries the maximal number of attempts for
0173 * creating a valid individual.
0174 * @throws NullPointerException if one of the arguments is {@code null}
0175 * @throws IllegalArgumentException if the given integer values are smaller
0176 * than one.
0177 */
0178 Engine(
0179 final Function<? super Genotype<G>, ? extends C> fitnessFunction,
0180 final Factory<Genotype<G>> genotypeFactory,
0181 final Function<? super C, ? extends C> fitnessScaler,
0182 final Selector<G, C> survivorsSelector,
0183 final Selector<G, C> offspringSelector,
0184 final Alterer<G, C> alterer,
0185 final Predicate<? super Phenotype<G, C>> validator,
0186 final Optimize optimize,
0187 final int offspringCount,
0188 final int survivorsCount,
0189 final long maximalPhenotypeAge,
0190 final Executor executor,
0191 final Evaluator<G, C> evaluator,
0192 final Clock clock,
0193 final int individualCreationRetries,
0194 final UnaryOperator<EvolutionResult<G, C>> mapper
0195 ) {
0196 _fitnessFunction = requireNonNull(fitnessFunction);
0197 _fitnessScaler = requireNonNull(fitnessScaler);
0198 _genotypeFactory = requireNonNull(genotypeFactory);
0199 _survivorsSelector = requireNonNull(survivorsSelector);
0200 _offspringSelector = requireNonNull(offspringSelector);
0201 _alterer = requireNonNull(alterer);
0202 _validator = requireNonNull(validator);
0203 _optimize = requireNonNull(optimize);
0204
0205 _offspringCount = require.nonNegative(offspringCount);
0206 _survivorsCount = require.nonNegative(survivorsCount);
0207 _maximalPhenotypeAge = require.positive(maximalPhenotypeAge);
0208
0209 _executor = new TimedExecutor(requireNonNull(executor));
0210 _evaluator = requireNonNull(evaluator);
0211 _clock = requireNonNull(clock);
0212
0213 if (individualCreationRetries < 0) {
0214 throw new IllegalArgumentException(format(
0215 "Retry count must not be negative: %d",
0216 individualCreationRetries
0217 ));
0218 }
0219 _individualCreationRetries = individualCreationRetries;
0220 _mapper = requireNonNull(mapper);
0221 }
0222
0223 /**
0224 * Perform one evolution step with the given {@code population} and
0225 * {@code generation}. New phenotypes are created with the fitness function
0226 * and fitness scaler defined by this <em>engine</em>
0227 * <p>
0228 * <em>This method is thread-safe.</em>
0229 *
0230 * @see #evolve(EvolutionStart)
0231 *
0232 * @param population the population to evolve
0233 * @param generation the current generation; used for calculating the
0234 * phenotype age.
0235 * @return the evolution result
0236 * @throws java.lang.NullPointerException if the given {@code population} is
0237 * {@code null}
0238 * @throws IllegalArgumentException if the given {@code generation} is
0239 * smaller then one
0240 */
0241 public EvolutionResult<G, C> evolve(
0242 final ISeq<Phenotype<G, C>> population,
0243 final long generation
0244 ) {
0245 return evolve(EvolutionStart.of(population, generation));
0246 }
0247
0248 /**
0249 * Perform one evolution step with the given evolution {@code start} object
0250 * New phenotypes are created with the fitness function and fitness scaler
0251 * defined by this <em>engine</em>
0252 * <p>
0253 * <em>This method is thread-safe.</em>
0254 *
0255 * @since 3.1
0256 * @see #evolve(ISeq, long)
0257 *
0258 * @param start the evolution start object
0259 * @return the evolution result
0260 * @throws java.lang.NullPointerException if the given evolution
0261 * {@code start} is {@code null}
0262 */
0263 public EvolutionResult<G, C> evolve(final EvolutionStart<G, C> start) {
0264 final Timer timer = Timer.of(_clock).start();
0265
0266 // Initial evaluation of the population.
0267 final Timer evaluateTimer = Timer.of(_clock).start();
0268 final ISeq<Phenotype<G, C>> evalPop =
0269 _evaluator.evaluate(start.getPopulation());
0270
0271 if (start.getPopulation().size() != evalPop.size()) {
0272 throw new IllegalStateException(format(
0273 "Expected %d individuals, but got %d. " +
0274 "Check your evaluator function.",
0275 start.getPopulation().size(), evalPop.size()
0276 ));
0277 }
0278
0279 evaluateTimer.stop();
0280
0281 // Select the offspring population.
0282 final CompletableFuture<TimedResult<ISeq<Phenotype<G, C>>>> offspring =
0283 _executor.async(() ->
0284 selectOffspring(evalPop),
0285 _clock
0286 );
0287
0288 // Select the survivor population.
0289 final CompletableFuture<TimedResult<ISeq<Phenotype<G, C>>>> survivors =
0290 _executor.async(() ->
0291 selectSurvivors(evalPop),
0292 _clock
0293 );
0294
0295 // Altering the offspring population.
0296 final CompletableFuture<TimedResult<AltererResult<G, C>>> alteredOffspring =
0297 _executor.thenApply(offspring, p ->
0298 _alterer.alter(p.result, start.getGeneration()),
0299 _clock
0300 );
0301
0302 // Filter and replace invalid and old survivor individuals.
0303 final CompletableFuture<TimedResult<FilterResult<G, C>>> filteredSurvivors =
0304 _executor.thenApply(survivors, pop ->
0305 filter(pop.result, start.getGeneration()),
0306 _clock
0307 );
0308
0309 // Filter and replace invalid and old offspring individuals.
0310 final CompletableFuture<TimedResult<FilterResult<G, C>>> filteredOffspring =
0311 _executor.thenApply(alteredOffspring, pop ->
0312 filter(pop.result.getPopulation(), start.getGeneration()),
0313 _clock
0314 );
0315
0316 // Combining survivors and offspring to the new population.
0317 final CompletableFuture<ISeq<Phenotype<G, C>>> population =
0318 filteredSurvivors.thenCombineAsync(filteredOffspring, (s, o) ->
0319 ISeq.of(s.result.population.append(o.result.population)),
0320 _executor.get()
0321 );
0322
0323 // Evaluate the fitness-function and wait for result.
0324 final ISeq<Phenotype<G, C>> pop = population.join();
0325 final TimedResult<ISeq<Phenotype<G, C>>> result = TimedResult
0326 .of(() -> _evaluator.evaluate(pop), _clock)
0327 .get();
0328
0329
0330 final EvolutionDurations durations = EvolutionDurations.of(
0331 offspring.join().duration,
0332 survivors.join().duration,
0333 alteredOffspring.join().duration,
0334 filteredOffspring.join().duration,
0335 filteredSurvivors.join().duration,
0336 result.duration.plus(evaluateTimer.getTime()),
0337 timer.stop().getTime()
0338 );
0339
0340 final int killCount =
0341 filteredOffspring.join().result.killCount +
0342 filteredSurvivors.join().result.killCount;
0343
0344 final int invalidCount =
0345 filteredOffspring.join().result.invalidCount +
0346 filteredSurvivors.join().result.invalidCount;
0347
0348 return _mapper.apply(
0349 EvolutionResult.of(
0350 _optimize,
0351 result.result,
0352 start.getGeneration(),
0353 durations,
0354 killCount,
0355 invalidCount,
0356 alteredOffspring.join().result.getAlterations()
0357 )
0358 );
0359 }
0360
0361 /**
0362 * This method is an <i>alias</i> for the {@link #evolve(EvolutionStart)}
0363 * method.
0364 *
0365 * @since 3.1
0366 */
0367 @Override
0368 public EvolutionResult<G, C> apply(final EvolutionStart<G, C> start) {
0369 return evolve(start);
0370 }
0371
0372 // Selects the survivors population. A new population object is returned.
0373 private ISeq<Phenotype<G, C>>
0374 selectSurvivors(final ISeq<Phenotype<G, C>> population) {
0375 return _survivorsCount > 0
0376 ?_survivorsSelector.select(population, _survivorsCount, _optimize)
0377 : ISeq.empty();
0378 }
0379
0380 // Selects the offspring population. A new population object is returned.
0381 private ISeq<Phenotype<G, C>>
0382 selectOffspring(final ISeq<Phenotype<G, C>> population) {
0383 return _offspringCount > 0
0384 ? _offspringSelector.select(population, _offspringCount, _optimize)
0385 : ISeq.empty();
0386 }
0387
0388 // Filters out invalid and old individuals. Filtering is done in place.
0389 private FilterResult<G, C> filter(
0390 final Seq<Phenotype<G, C>> population,
0391 final long generation
0392 ) {
0393 int killCount = 0;
0394 int invalidCount = 0;
0395
0396 final MSeq<Phenotype<G, C>> pop = MSeq.of(population);
0397 for (int i = 0, n = pop.size(); i < n; ++i) {
0398 final Phenotype<G, C> individual = pop.get(i);
0399
0400 if (!_validator.test(individual)) {
0401 pop.set(i, newPhenotype(generation));
0402 ++invalidCount;
0403 } else if (individual.getAge(generation) > _maximalPhenotypeAge) {
0404 pop.set(i, newPhenotype(generation));
0405 ++killCount;
0406 }
0407 }
0408
0409 return new FilterResult<>(pop.toISeq(), killCount, invalidCount);
0410 }
0411
0412 // Create a new and valid phenotype
0413 private Phenotype<G, C> newPhenotype(final long generation) {
0414 int count = 0;
0415 Phenotype<G, C> phenotype;
0416 do {
0417 phenotype = Phenotype.of(
0418 _genotypeFactory.newInstance(),
0419 generation,
0420 _fitnessFunction,
0421 _fitnessScaler
0422 );
0423 } while (++count < _individualCreationRetries &&
0424 !_validator.test(phenotype));
0425
0426 return phenotype;
0427 }
0428
0429
0430 /* *************************************************************************
0431 * Evolution Stream/Iterator creation.
0432 **************************************************************************/
0433
0434 @Deprecated
0435 @Override
0436 public Iterator<EvolutionResult<G, C>>
0437 iterator(final Supplier<EvolutionStart<G, C>> start) {
0438 return new EvolutionIterator<>(evolutionStart(start), this::evolve);
0439 }
0440
0441 @Deprecated
0442 @Override
0443 public Iterator<EvolutionResult<G, C>> iterator(final EvolutionInit<G> init) {
0444 return iterator(evolutionStart(init));
0445 }
0446
0447 @Override
0448 public EvolutionStream<G, C>
0449 stream(final Supplier<EvolutionStart<G, C>> start) {
0450 return EvolutionStream.of(evolutionStart(start), this::evolve);
0451 }
0452
0453 @Override
0454 public EvolutionStream<G, C> stream(final EvolutionInit<G> init) {
0455 return stream(evolutionStart(init));
0456 }
0457
0458 private Supplier<EvolutionStart<G, C>>
0459 evolutionStart(final Supplier<EvolutionStart<G, C>> start) {
0460 return () -> {
0461 final EvolutionStart<G, C> es = start.get();
0462 final ISeq<Phenotype<G, C>> population = es.getPopulation();
0463 final long generation = es.getGeneration();
0464
0465 final Stream<Phenotype<G, C>> stream = Stream.concat(
0466 population.stream().map(this::toFixedPhenotype),
0467 Stream.generate(() -> newPhenotype(generation))
0468 );
0469
0470 final ISeq<Phenotype<G, C>> pop = stream
0471 .limit(getPopulationSize())
0472 .collect(ISeq.toISeq());
0473
0474 return EvolutionStart.of(pop, generation);
0475 };
0476 }
0477
0478 private Phenotype<G, C> toFixedPhenotype(final Phenotype<G, C> pt) {
0479 return
0480 pt.getFitnessFunction() == _fitnessFunction &&
0481 pt.getFitnessScaler() == _fitnessScaler
0482 ? pt
0483 : pt.newInstance(
0484 pt.getGeneration(),
0485 _fitnessFunction,
0486 _fitnessScaler
0487 );
0488 }
0489
0490 private Supplier<EvolutionStart<G, C>>
0491 evolutionStart(final EvolutionInit<G> init) {
0492 return evolutionStart(() -> EvolutionStart.of(
0493 init.getPopulation()
0494 .map(gt -> Phenotype.of(
0495 gt,
0496 init.getGeneration(),
0497 _fitnessFunction,
0498 _fitnessScaler)
0499 ),
0500 init.getGeneration())
0501 );
0502 }
0503
0504 /* *************************************************************************
0505 * Property access methods.
0506 **************************************************************************/
0507
0508 /**
0509 * Return the fitness function of the GA engine.
0510 *
0511 * @return the fitness function
0512 */
0513 public Function<? super Genotype<G>, ? extends C> getFitnessFunction() {
0514 return _fitnessFunction;
0515 }
0516
0517 /**
0518 * Return the fitness scaler of the GA engine.
0519 *
0520 * @return the fitness scaler
0521 */
0522 public Function<? super C, ? extends C> getFitnessScaler() {
0523 return _fitnessScaler;
0524 }
0525
0526 /**
0527 * Return the used genotype {@link Factory} of the GA. The genotype factory
0528 * is used for creating the initial population and new, random individuals
0529 * when needed (as replacement for invalid and/or died genotypes).
0530 *
0531 * @return the used genotype {@link Factory} of the GA.
0532 */
0533 public Factory<Genotype<G>> getGenotypeFactory() {
0534 return _genotypeFactory;
0535 }
0536
0537 /**
0538 * Return the used survivor {@link Selector} of the GA.
0539 *
0540 * @return the used survivor {@link Selector} of the GA.
0541 */
0542 public Selector<G, C> getSurvivorsSelector() {
0543 return _survivorsSelector;
0544 }
0545
0546 /**
0547 * Return the used offspring {@link Selector} of the GA.
0548 *
0549 * @return the used offspring {@link Selector} of the GA.
0550 */
0551 public Selector<G, C> getOffspringSelector() {
0552 return _offspringSelector;
0553 }
0554
0555 /**
0556 * Return the used {@link Alterer} of the GA.
0557 *
0558 * @return the used {@link Alterer} of the GA.
0559 */
0560 public Alterer<G, C> getAlterer() {
0561 return _alterer;
0562 }
0563
0564 /**
0565 * Return the number of selected offsprings.
0566 *
0567 * @return the number of selected offsprings
0568 */
0569 public int getOffspringCount() {
0570 return _offspringCount;
0571 }
0572
0573 /**
0574 * The number of selected survivors.
0575 *
0576 * @return the number of selected survivors
0577 */
0578 public int getSurvivorsCount() {
0579 return _survivorsCount;
0580 }
0581
0582 /**
0583 * Return the number of individuals of a population.
0584 *
0585 * @return the number of individuals of a population
0586 */
0587 public int getPopulationSize() {
0588 return _offspringCount + _survivorsCount;
0589 }
0590
0591 /**
0592 * Return the maximal allowed phenotype age.
0593 *
0594 * @return the maximal allowed phenotype age
0595 */
0596 public long getMaximalPhenotypeAge() {
0597 return _maximalPhenotypeAge;
0598 }
0599
0600 /**
0601 * Return the optimization strategy.
0602 *
0603 * @return the optimization strategy
0604 */
0605 public Optimize getOptimize() {
0606 return _optimize;
0607 }
0608
0609 /**
0610 * Return the {@link Clock} the engine is using for measuring the execution
0611 * time.
0612 *
0613 * @return the clock used for measuring the execution time
0614 */
0615 public Clock getClock() {
0616 return _clock;
0617 }
0618
0619 /**
0620 * Return the {@link Executor} the engine is using for executing the
0621 * evolution steps.
0622 *
0623 * @return the executor used for performing the evolution steps
0624 */
0625 public Executor getExecutor() {
0626 return _executor.get();
0627 }
0628
0629
0630 /**
0631 * Return the maximal number of attempt before the {@code Engine} gives
0632 * up creating a valid individual ({@code Phenotype}).
0633 *
0634 * @since 4.0
0635 *
0636 * @return the maximal number of {@code Phenotype} creation attempts
0637 */
0638 public int getIndividualCreationRetries() {
0639 return _individualCreationRetries;
0640 }
0641
0642 /**
0643 * Return the evolution result mapper.
0644 *
0645 * @since 4.0
0646 *
0647 * @return the evolution result mapper
0648 */
0649 public UnaryOperator<EvolutionResult<G, C>> getMapper() {
0650 return _mapper;
0651 }
0652
0653 /* *************************************************************************
0654 * Builder methods.
0655 **************************************************************************/
0656
0657 /**
0658 * Create a new evolution {@code Engine.Builder} initialized with the values
0659 * of the current evolution {@code Engine}. With this method, the evolution
0660 * engine can serve as a template for a new one.
0661 *
0662 * @return a new engine builder
0663 */
0664 public Builder<G, C> builder() {
0665 return new Builder<G, C>(_genotypeFactory, _fitnessFunction)
0666 .alterers(_alterer)
0667 .clock(_clock)
0668 .evaluator(_evaluator)
0669 .executor(_executor.get())
0670 .fitnessScaler(_fitnessScaler)
0671 .maximalPhenotypeAge(_maximalPhenotypeAge)
0672 .offspringFraction((double)_offspringCount/(double)getPopulationSize())
0673 .offspringSelector(_offspringSelector)
0674 .optimize(_optimize)
0675 .phenotypeValidator(_validator)
0676 .populationSize(getPopulationSize())
0677 .survivorsSelector(_survivorsSelector)
0678 .individualCreationRetries(_individualCreationRetries)
0679 .mapping(_mapper);
0680 }
0681
0682 /**
0683 * Create a new evolution {@code Engine.Builder} for the given
0684 * {@link Problem}.
0685 *
0686 * @since 3.4
0687 *
0688 * @param problem the problem to be solved by the evolution {@code Engine}
0689 * @param <T> the (<i>native</i>) argument type of the problem fitness function
0690 * @param <G> the gene type the evolution engine is working with
0691 * @param <C> the result type of the fitness function
0692 * @return Create a new evolution {@code Engine.Builder}
0693 */
0694 public static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
0695 Builder<G, C> builder(final Problem<T, G, C> problem) {
0696 return builder(problem.fitness(), problem.codec());
0697 }
0698
0699 /**
0700 * Create a new evolution {@code Engine.Builder} with the given fitness
0701 * function and genotype factory.
0702 *
0703 * @param ff the fitness function
0704 * @param genotypeFactory the genotype factory
0705 * @param <G> the gene type
0706 * @param <C> the fitness function result type
0707 * @return a new engine builder
0708 * @throws java.lang.NullPointerException if one of the arguments is
0709 * {@code null}.
0710 */
0711 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
0712 Builder<G, C> builder(
0713 final Function<? super Genotype<G>, ? extends C> ff,
0714 final Factory<Genotype<G>> genotypeFactory
0715 ) {
0716 return new Builder<>(genotypeFactory, ff);
0717 }
0718
0719 /**
0720 * Create a new evolution {@code Engine.Builder} with the given fitness
0721 * function and chromosome templates.
0722 *
0723 * @param ff the fitness function
0724 * @param chromosome the first chromosome
0725 * @param chromosomes the chromosome templates
0726 * @param <G> the gene type
0727 * @param <C> the fitness function result type
0728 * @return a new engine builder
0729 * @throws java.lang.NullPointerException if one of the arguments is
0730 * {@code null}.
0731 */
0732 @SafeVarargs
0733 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
0734 Builder<G, C> builder(
0735 final Function<? super Genotype<G>, ? extends C> ff,
0736 final Chromosome<G> chromosome,
0737 final Chromosome<G>... chromosomes
0738 ) {
0739 return new Builder<>(Genotype.of(chromosome, chromosomes), ff);
0740 }
0741
0742 /**
0743 * Create a new evolution {@code Engine.Builder} with the given fitness
0744 * function and problem {@code codec}.
0745 *
0746 * @since 3.2
0747 *
0748 * @param ff the fitness function
0749 * @param codec the problem codec
0750 * @param <T> the fitness function input type
0751 * @param <C> the fitness function result type
0752 * @param <G> the gene type
0753 * @return a new engine builder
0754 * @throws java.lang.NullPointerException if one of the arguments is
0755 * {@code null}.
0756 */
0757 public static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
0758 Builder<G, C> builder(
0759 final Function<? super T, ? extends C> ff,
0760 final Codec<T, G> codec
0761 ) {
0762 return builder(ff.compose(codec.decoder()), codec.encoding());
0763 }
0764
0765
0766 /* *************************************************************************
0767 * Inner classes
0768 **************************************************************************/
0769
0770
0771 /**
0772 * This interface allows to define different strategies for evaluating the
0773 * fitness functions of a given population. <em>Normally</em>, there is no
0774 * need for <em>overriding</em> the default evaluation strategy, but it might
0775 * be necessary if you have performance problems and a <em>batched</em>
0776 * fitness evaluation would solve the problem.
0777 * <p>
0778 * The implementer is free to do the evaluation <em>in place</em>, or create
0779 * new {@link Phenotype} instance and return the newly created one. A simple
0780 * serial evaluator can easily implemented:
0781 *
0782 * <pre>{@code
0783 * final Evaluator<G, C> evaluator = population -> {
0784 * population.forEach(Phenotype::evaluate);
0785 * return population.asISeq();
0786 * };
0787 * }</pre>
0788 *
0789 * @implSpec
0790 * The size of the returned, evaluated, phenotype sequence must be exactly
0791 * the size of the input phenotype sequence. It is allowed to return the
0792 * input sequence, after evaluation, as well a newly created one.
0793 *
0794 * @apiNote
0795 * This interface is an <em>advanced</em> {@code Engine} configuration
0796 * feature, which should be only used when there is a performance gain from
0797 * implementing a different evaluation strategy. Another use case is, when
0798 * the fitness value of an individual also depends on the current composition
0799 * of the population.
0800 *
0801 * @see GenotypeEvaluator
0802 * @see Engine.Builder#evaluator(Engine.Evaluator)
0803 *
0804 * @param <G> the gene type
0805 * @param <C> the fitness result type
0806 *
0807 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
0808 * @version 4.2
0809 * @since 4.2
0810 */
0811 @FunctionalInterface
0812 public static interface Evaluator<
0813 G extends Gene<?, G>,
0814 C extends Comparable<? super C>
0815 > {
0816
0817 /**
0818 * Evaluates the fitness values of the given {@code population}. The
0819 * given {@code population} might contain already evaluated individuals.
0820 * It is the responsibility of the implementer to filter out already
0821 * evaluated individuals, if desired.
0822 *
0823 * @param population the population to evaluate
0824 * @return the evaluated population. Implementers are free to return the
0825 * the input population or a newly created one.
0826 */
0827 public ISeq<Phenotype<G, C>> evaluate(final Seq<Phenotype<G, C>> population);
0828
0829 /**
0830 * Create a new phenotype evaluator from a given genotype {@code evaluator}.
0831 *
0832 * @implNote
0833 * The returned {@link Evaluator} will only forward <em>un</em>-evaluated
0834 * individuals to the given genotype {@code evaluator}. This means, that
0835 * already evaluated individuals are filtered from the population, which
0836 * is then forwarded to the underlying genotype {@code evaluator}.
0837 *
0838 * @param evaluator the genotype evaluator
0839 * @param <G> the gene type
0840 * @param <C> the fitness result type
0841 * @return a <em>normal</em> phenotype evaluator from the given genotype
0842 * evaluator
0843 * @throws NullPointerException if the given {@code evaluator} is
0844 * {@code null}
0845 */
0846 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
0847 Evaluator<G, C> of(final GenotypeEvaluator<G, C> evaluator) {
0848 requireNonNull(evaluator);
0849
0850 return population -> {
0851 final ISeq<Genotype<G>> genotypes = population.stream()
0852 .filter(pt -> !pt.isEvaluated())
0853 .map(Phenotype::getGenotype)
0854 .collect(ISeq.toISeq());
0855
0856 if (genotypes.nonEmpty()) {
0857 final ISeq<C> results = evaluator.evaluate(
0858 genotypes,
0859 population.get(0).getFitnessFunction()
0860 );
0861
0862 if (genotypes.size() != results.size()) {
0863 throw new IllegalStateException(format(
0864 "Expected %d results, but got %d. " +
0865 "Check your evaluator function.",
0866 genotypes.size(), results.size()
0867 ));
0868 }
0869
0870 final MSeq<Phenotype<G, C>> evaluated = population.asMSeq();
0871 for (int i = 0, j = 0; i < evaluated.length(); ++i) {
0872 if (!population.get(i).isEvaluated()) {
0873 evaluated.set(
0874 i,
0875 population.get(i).withFitness(results.get(j++))
0876 );
0877 }
0878 }
0879
0880 return evaluated.toISeq();
0881 } else {
0882 return population.asISeq();
0883 }
0884 };
0885 }
0886
0887 }
0888
0889 /**
0890 * This interface gives a different possibility in evaluating the fitness
0891 * values of a population. Sometimes it is necessary (mostly for performance
0892 * reason) to calculate the fitness for the whole population at once. This
0893 * interface allows you to do so. A simple serial evaluator can easily
0894 * implemented:
0895 *
0896 * <pre>{@code
0897 * final GenotypeEvaluator<G, C> gte = (g, f) -> g.map(f).asISeq()
0898 * final Evaluator<G, C> evaluator = Evaluator.of(gte);
0899 * }</pre>
0900 *
0901 * @implSpec
0902 * The size of the returned result sequence must be exactly the size of the
0903 * input genotype sequence.
0904 *
0905 * @apiNote
0906 * This interface is an <em>advanced</em> {@code Engine} configuration
0907 * feature, which should be only used when there is a performance gain from
0908 * implementing a different evaluation strategy.
0909 *
0910 * @see Evaluator
0911 * @see Engine.Builder#evaluator(Engine.GenotypeEvaluator)
0912 *
0913 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
0914 * @version 4.2
0915 * @since 4.2
0916 */
0917 @FunctionalInterface
0918 public static interface GenotypeEvaluator<
0919 G extends Gene<?, G>,
0920 C extends Comparable<? super C>
0921 > {
0922
0923 /**
0924 * Calculate the fitness values for the given sequence of genotypes.
0925 *
0926 * @see Engine.Evaluator#of(Engine.GenotypeEvaluator)
0927 *
0928 * @param genotypes the genotypes to evaluate the fitness value for
0929 * @param function the fitness function
0930 * @return the fitness values for the given {@code genotypes} The length
0931 * of the fitness result sequence must match with the size of
0932 * the given {@code genotypes}.
0933 */
0934 public ISeq<C> evaluate(
0935 final Seq<Genotype<G>> genotypes,
0936 final Function<? super Genotype<G>, ? extends C> function
0937 );
0938
0939 }
0940
0941
0942 /**
0943 * Builder class for building GA {@code Engine} instances.
0944 *
0945 * @see Engine
0946 *
0947 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
0948 * @since 3.0
0949 * @version 4.0
0950 */
0951 public static final class Builder<
0952 G extends Gene<?, G>,
0953 C extends Comparable<? super C>
0954 >
0955 implements Copyable<Builder<G, C>>
0956 {
0957
0958 // No default values for this properties.
0959 private Function<? super Genotype<G>, ? extends C> _fitnessFunction;
0960 private Factory<Genotype<G>> _genotypeFactory;
0961
0962 // This are the properties which default values.
0963 private Function<? super C, ? extends C> _fitnessScaler = a -> a;
0964 private Selector<G, C> _survivorsSelector = new TournamentSelector<>(3);
0965 private Selector<G, C> _offspringSelector = new TournamentSelector<>(3);
0966 private Alterer<G, C> _alterer = Alterer.of(
0967 new SinglePointCrossover<G, C>(0.2),
0968 new Mutator<>(0.15)
0969 );
0970 private Predicate<? super Phenotype<G, C>> _validator = Phenotype::isValid;
0971 private Optimize _optimize = Optimize.MAXIMUM;
0972 private double _offspringFraction = 0.6;
0973 private int _populationSize = 50;
0974 private long _maximalPhenotypeAge = 70;
0975
0976 // Engine execution environment.
0977 private Executor _executor = ForkJoinPool.commonPool();
0978 private Clock _clock = NanoClock.systemUTC();
0979 private Evaluator<G, C> _evaluator;
0980
0981 private int _individualCreationRetries = 10;
0982 private UnaryOperator<EvolutionResult<G, C>> _mapper = r -> r;
0983
0984 private Builder(
0985 final Factory<Genotype<G>> genotypeFactory,
0986 final Function<? super Genotype<G>, ? extends C> fitnessFunction
0987 ) {
0988 _genotypeFactory = requireNonNull(genotypeFactory);
0989 _fitnessFunction = requireNonNull(fitnessFunction);
0990 }
0991
0992 /**
0993 * Set the fitness function of the evolution {@code Engine}.
0994 *
0995 * @param function the fitness function to use in the GA {@code Engine}
0996 * @return {@code this} builder, for command chaining
0997 */
0998 public Builder<G, C> fitnessFunction(
0999 final Function<? super Genotype<G>, ? extends C> function
1000 ) {
1001 _fitnessFunction = requireNonNull(function);
1002 return this;
1003 }
1004
1005 /**
1006 * Set the fitness scaler of the evolution {@code Engine}. <i>Default
1007 * value is set to the identity function.</i>
1008 *
1009 * @param scaler the fitness scale to use in the GA {@code Engine}
1010 * @return {@code this} builder, for command chaining
1011 */
1012 public Builder<G, C> fitnessScaler(
1013 final Function<? super C, ? extends C> scaler
1014 ) {
1015 _fitnessScaler = requireNonNull(scaler);
1016 return this;
1017 }
1018
1019 /**
1020 * The genotype factory used for creating new individuals.
1021 *
1022 * @param genotypeFactory the genotype factory for creating new
1023 * individuals.
1024 * @return {@code this} builder, for command chaining
1025 */
1026 public Builder<G, C> genotypeFactory(
1027 final Factory<Genotype<G>> genotypeFactory
1028 ) {
1029 _genotypeFactory = requireNonNull(genotypeFactory);
1030 return this;
1031 }
1032
1033 /**
1034 * The selector used for selecting the offspring population. <i>Default
1035 * values is set to {@code TournamentSelector<>(3)}.</i>
1036 *
1037 * @param selector used for selecting the offspring population
1038 * @return {@code this} builder, for command chaining
1039 */
1040 public Builder<G, C> offspringSelector(
1041 final Selector<G, C> selector
1042 ) {
1043 _offspringSelector = requireNonNull(selector);
1044 return this;
1045 }
1046
1047 /**
1048 * The selector used for selecting the survivors population. <i>Default
1049 * values is set to {@code TournamentSelector<>(3)}.</i>
1050 *
1051 * @param selector used for selecting survivors population
1052 * @return {@code this} builder, for command chaining
1053 */
1054 public Builder<G, C> survivorsSelector(
1055 final Selector<G, C> selector
1056 ) {
1057 _survivorsSelector = requireNonNull(selector);
1058 return this;
1059 }
1060
1061 /**
1062 * The selector used for selecting the survivors and offspring
1063 * population. <i>Default values is set to
1064 * {@code TournamentSelector<>(3)}.</i>
1065 *
1066 * @param selector used for selecting survivors and offspring population
1067 * @return {@code this} builder, for command chaining
1068 */
1069 public Builder<G, C> selector(final Selector<G, C> selector) {
1070 _offspringSelector = requireNonNull(selector);
1071 _survivorsSelector = requireNonNull(selector);
1072 return this;
1073 }
1074
1075 /**
1076 * The alterers used for alter the offspring population. <i>Default
1077 * values is set to {@code new SinglePointCrossover<>(0.2)} followed by
1078 * {@code new Mutator<>(0.15)}.</i>
1079 *
1080 * @param first the first alterer used for alter the offspring
1081 * population
1082 * @param rest the rest of the alterers used for alter the offspring
1083 * population
1084 * @return {@code this} builder, for command chaining
1085 * @throws java.lang.NullPointerException if one of the alterers is
1086 * {@code null}.
1087 */
1088 @SafeVarargs
1089 public final Builder<G, C> alterers(
1090 final Alterer<G, C> first,
1091 final Alterer<G, C>... rest
1092 ) {
1093 requireNonNull(first);
1094 Stream.of(rest).forEach(Objects::requireNonNull);
1095
1096 _alterer = rest.length == 0
1097 ? first
1098 : Alterer.of(rest).compose(first);
1099
1100 return this;
1101 }
1102
1103 /**
1104 * The phenotype validator used for detecting invalid individuals.
1105 * Alternatively it is also possible to set the genotype validator with
1106 * {@link #genotypeFactory(Factory)}, which will replace any
1107 * previously set phenotype validators.
1108 *
1109 * <p><i>Default value is set to {@code Phenotype::isValid}.</i></p>
1110 *
1111 * @since 3.1
1112 *
1113 * @see #genotypeValidator(Predicate)
1114 *
1115 * @param validator the {@code validator} used for validating the
1116 * individuals (phenotypes).
1117 * @return {@code this} builder, for command chaining
1118 * @throws java.lang.NullPointerException if the {@code validator} is
1119 * {@code null}.
1120 */
1121 public Builder<G, C> phenotypeValidator(
1122 final Predicate<? super Phenotype<G, C>> validator
1123 ) {
1124 _validator = requireNonNull(validator);
1125 return this;
1126 }
1127
1128 /**
1129 * The genotype validator used for detecting invalid individuals.
1130 * Alternatively it is also possible to set the phenotype validator with
1131 * {@link #phenotypeValidator(Predicate)}, which will replace any
1132 * previously set genotype validators.
1133 *
1134 * <p><i>Default value is set to {@code Genotype::isValid}.</i></p>
1135 *
1136 * @since 3.1
1137 *
1138 * @see #phenotypeValidator(Predicate)
1139 *
1140 * @param validator the {@code validator} used for validating the
1141 * individuals (genotypes).
1142 * @return {@code this} builder, for command chaining
1143 * @throws java.lang.NullPointerException if the {@code validator} is
1144 * {@code null}.
1145 */
1146 public Builder<G, C> genotypeValidator(
1147 final Predicate<? super Genotype<G>> validator
1148 ) {
1149 requireNonNull(validator);
1150
1151 _validator = pt -> validator.test(pt.getGenotype());
1152 return this;
1153 }
1154
1155 /**
1156 * The optimization strategy used by the engine. <i>Default values is
1157 * set to {@code Optimize.MAXIMUM}.</i>
1158 *
1159 * @param optimize the optimization strategy used by the engine
1160 * @return {@code this} builder, for command chaining
1161 */
1162 public Builder<G, C> optimize(final Optimize optimize) {
1163 _optimize = requireNonNull(optimize);
1164 return this;
1165 }
1166
1167 /**
1168 * Set to a fitness maximizing strategy.
1169 *
1170 * @since 3.4
1171 *
1172 * @return {@code this} builder, for command chaining
1173 */
1174 public Builder<G, C> maximizing() {
1175 return optimize(Optimize.MAXIMUM);
1176 }
1177
1178 /**
1179 * Set to a fitness minimizing strategy.
1180 *
1181 * @since 3.4
1182 *
1183 * @return {@code this} builder, for command chaining
1184 */
1185 public Builder<G, C> minimizing() {
1186 return optimize(Optimize.MINIMUM);
1187 }
1188
1189 /**
1190 * The offspring fraction. <i>Default values is set to {@code 0.6}.</i>
1191 * This method call is equivalent to
1192 * {@code survivorsFraction(1 - offspringFraction)} and will override
1193 * any previously set survivors-fraction.
1194 *
1195 * @see #survivorsFraction(double)
1196 *
1197 * @param fraction the offspring fraction
1198 * @return {@code this} builder, for command chaining
1199 * @throws java.lang.IllegalArgumentException if the fraction is not
1200 * within the range [0, 1].
1201 */
1202 public Builder<G, C> offspringFraction(final double fraction) {
1203 _offspringFraction = probability(fraction);
1204 return this;
1205 }
1206
1207 /**
1208 * The survivors fraction. <i>Default values is set to {@code 0.4}.</i>
1209 * This method call is equivalent to
1210 * {@code offspringFraction(1 - survivorsFraction)} and will override
1211 * any previously set offspring-fraction.
1212 *
1213 * @since 3.8
1214 *
1215 * @see #offspringFraction(double)
1216 *
1217 * @param fraction the survivors fraction
1218 * @return {@code this} builder, for command chaining
1219 * @throws java.lang.IllegalArgumentException if the fraction is not
1220 * within the range [0, 1].
1221 */
1222 public Builder<G, C> survivorsFraction(final double fraction) {
1223 _offspringFraction = 1.0 - probability(fraction);
1224 return this;
1225 }
1226
1227 /**
1228 * The number of offspring individuals.
1229 *
1230 * @since 3.8
1231 *
1232 * @param size the number of offspring individuals.
1233 * @return {@code this} builder, for command chaining
1234 * @throws java.lang.IllegalArgumentException if the size is not
1235 * within the range [0, population-size].
1236 */
1237 public Builder<G, C> offspringSize(final int size) {
1238 if (size < 0) {
1239 throw new IllegalArgumentException(format(
1240 "Offspring size must be greater or equal zero, but was %s.",
1241 size
1242 ));
1243 }
1244
1245 return offspringFraction((double)size/(double)_populationSize);
1246 }
1247
1248 /**
1249 * The number of survivors.
1250 *
1251 * @since 3.8
1252 *
1253 * @param size the number of survivors.
1254 * @return {@code this} builder, for command chaining
1255 * @throws java.lang.IllegalArgumentException if the size is not
1256 * within the range [0, population-size].
1257 */
1258 public Builder<G, C> survivorsSize(final int size) {
1259 if (size < 0) {
1260 throw new IllegalArgumentException(format(
1261 "Survivors must be greater or equal zero, but was %s.",
1262 size
1263 ));
1264 }
1265
1266 return survivorsFraction((double)size/(double)_populationSize);
1267 }
1268
1269 /**
1270 * The number of individuals which form the population. <i>Default
1271 * values is set to {@code 50}.</i>
1272 *
1273 * @param size the number of individuals of a population
1274 * @return {@code this} builder, for command chaining
1275 * @throws java.lang.IllegalArgumentException if {@code size < 1}
1276 */
1277 public Builder<G, C> populationSize(final int size) {
1278 if (size < 1) {
1279 throw new IllegalArgumentException(format(
1280 "Population size must be greater than zero, but was %s.",
1281 size
1282 ));
1283 }
1284 _populationSize = size;
1285 return this;
1286 }
1287
1288 /**
1289 * The maximal allowed age of a phenotype. <i>Default values is set to
1290 * {@code 70}.</i>
1291 *
1292 * @param age the maximal phenotype age
1293 * @return {@code this} builder, for command chaining
1294 * @throws java.lang.IllegalArgumentException if {@code age < 1}
1295 */
1296 public Builder<G, C> maximalPhenotypeAge(final long age) {
1297 if (age < 1) {
1298 throw new IllegalArgumentException(format(
1299 "Phenotype age must be greater than one, but was %s.", age
1300 ));
1301 }
1302 _maximalPhenotypeAge = age;
1303 return this;
1304 }
1305
1306 /**
1307 * The executor used by the engine.
1308 *
1309 * @param executor the executor used by the engine
1310 * @return {@code this} builder, for command chaining
1311 */
1312 public Builder<G, C> executor(final Executor executor) {
1313 _executor = requireNonNull(executor);
1314 return this;
1315 }
1316
1317 /**
1318 * The clock used for calculating the execution durations.
1319 *
1320 * @param clock the clock used for calculating the execution durations
1321 * @return {@code this} builder, for command chaining
1322 */
1323 public Builder<G, C> clock(final Clock clock) {
1324 _clock = requireNonNull(clock);
1325 return this;
1326 }
1327
1328 /**
1329 * The phenotype evaluator allows to change the evaluation strategy.
1330 * By default, the population is evaluated concurrently using the
1331 * defined {@link Executor} implementation.
1332 *
1333 * @apiNote
1334 * This is an <em>advanced</em> {@code Engine} configuration feature,
1335 * which should be only used when there is a performance gain from
1336 * implementing a different evaluation strategy.
1337 *
1338 * @since 4.2
1339 *
1340 * @param evaluator the population evaluation strategy
1341 * @return {@code this} builder, for command chaining
1342 */
1343 public Builder<G, C> evaluator(final Evaluator<G, C> evaluator) {
1344 _evaluator = requireNonNull(evaluator);
1345 return this;
1346 }
1347
1348 /**
1349 * Setting the <em>genotype</em> evaluator used for evaluating the
1350 * fitness function of the population.
1351 *
1352 * @apiNote
1353 * This is an <em>advanced</em> {@code Engine} configuration feature,
1354 * which should be only used when there is a performance gain from
1355 * implementing a different evaluation strategy.
1356 *
1357 * @since 4.2
1358 *
1359 * @param evaluator the genotype evaluator
1360 * @return {@code this} builder, for command chaining
1361 */
1362 public Builder<G, C> evaluator(final GenotypeEvaluator<G, C> evaluator) {
1363 _evaluator = Evaluator.of(evaluator);
1364 return this;
1365 }
1366
1367 /**
1368 * The maximal number of attempt before the {@code Engine} gives up
1369 * creating a valid individual ({@code Phenotype}). <i>Default values is
1370 * set to {@code 10}.</i>
1371 *
1372 * @since 3.1
1373 *
1374 * @param retries the maximal retry count
1375 * @throws IllegalArgumentException if the given retry {@code count} is
1376 * smaller than zero.
1377 * @return {@code this} builder, for command chaining
1378 */
1379 public Builder<G, C> individualCreationRetries(final int retries) {
1380 if (retries < 0) {
1381 throw new IllegalArgumentException(format(
1382 "Retry count must not be negative: %d",
1383 retries
1384 ));
1385 }
1386 _individualCreationRetries = retries;
1387 return this;
1388 }
1389
1390 /**
1391 * The result mapper, which allows to change the evolution result after
1392 * each generation.
1393 *
1394 * @since 4.0
1395 * @see EvolutionResult#toUniquePopulation()
1396 *
1397 * @param mapper the evolution result mapper
1398 * @return {@code this} builder, for command chaining
1399 * @throws NullPointerException if the given {@code resultMapper} is
1400 * {@code null}
1401 */
1402 public Builder<G, C> mapping(
1403 final Function<
1404 ? super EvolutionResult<G, C>,
1405 EvolutionResult<G, C>
1406 > mapper
1407 ) {
1408 _mapper = requireNonNull(mapper::apply);
1409 return this;
1410 }
1411
1412 /**
1413 * Builds an new {@code Engine} instance from the set properties.
1414 *
1415 * @return an new {@code Engine} instance from the set properties
1416 */
1417 public Engine<G, C> build() {
1418 return new Engine<>(
1419 _fitnessFunction,
1420 _genotypeFactory,
1421 _fitnessScaler,
1422 _survivorsSelector,
1423 _offspringSelector,
1424 _alterer,
1425 _validator,
1426 _optimize,
1427 getOffspringCount(),
1428 getSurvivorsCount(),
1429 _maximalPhenotypeAge,
1430 _executor,
1431 _evaluator != null
1432 ? _evaluator
1433 : new ConcurrentEvaluator<>(_executor),
1434 _clock,
1435 _individualCreationRetries,
1436 _mapper
1437 );
1438 }
1439
1440 private int getSurvivorsCount() {
1441 return _populationSize - getOffspringCount();
1442 }
1443
1444 private int getOffspringCount() {
1445 return (int)round(_offspringFraction*_populationSize);
1446 }
1447
1448 /**
1449 * Return the used {@link Alterer} of the GA.
1450 *
1451 * @return the used {@link Alterer} of the GA.
1452 */
1453 public Alterer<G, C> getAlterers() {
1454 return _alterer;
1455 }
1456
1457 /**
1458 * Return the {@link Clock} the engine is using for measuring the execution
1459 * time.
1460 *
1461 * @since 3.1
1462 *
1463 * @return the clock used for measuring the execution time
1464 */
1465 public Clock getClock() {
1466 return _clock;
1467 }
1468
1469 /**
1470 * Return the {@link Executor} the engine is using for executing the
1471 * evolution steps.
1472 *
1473 * @since 3.1
1474 *
1475 * @return the executor used for performing the evolution steps
1476 */
1477 public Executor getExecutor() {
1478 return _executor;
1479 }
1480
1481 /**
1482 * Return the fitness function of the GA engine.
1483 *
1484 * @since 3.1
1485 *
1486 * @return the fitness function
1487 */
1488 public Function<? super Genotype<G>, ? extends C> getFitnessFunction() {
1489 return _fitnessFunction;
1490 }
1491
1492 /**
1493 * Return the fitness scaler of the GA engine.
1494 *
1495 * @since 3.1
1496 *
1497 * @return the fitness scaler
1498 */
1499 public Function<? super C, ? extends C> getFitnessScaler() {
1500 return _fitnessScaler;
1501 }
1502
1503 /**
1504 * Return the used genotype {@link Factory} of the GA. The genotype factory
1505 * is used for creating the initial population and new, random individuals
1506 * when needed (as replacement for invalid and/or died genotypes).
1507 *
1508 * @since 3.1
1509 *
1510 * @return the used genotype {@link Factory} of the GA.
1511 */
1512 public Factory<Genotype<G>> getGenotypeFactory() {
1513 return _genotypeFactory;
1514 }
1515
1516 /**
1517 * Return the maximal allowed phenotype age.
1518 *
1519 * @since 3.1
1520 *
1521 * @return the maximal allowed phenotype age
1522 */
1523 public long getMaximalPhenotypeAge() {
1524 return _maximalPhenotypeAge;
1525 }
1526
1527 /**
1528 * Return the offspring fraction.
1529 *
1530 * @return the offspring fraction.
1531 */
1532 public double getOffspringFraction() {
1533 return _offspringFraction;
1534 }
1535
1536 /**
1537 * Return the used offspring {@link Selector} of the GA.
1538 *
1539 * @since 3.1
1540 *
1541 * @return the used offspring {@link Selector} of the GA.
1542 */
1543 public Selector<G, C> getOffspringSelector() {
1544 return _offspringSelector;
1545 }
1546
1547 /**
1548 * Return the used survivor {@link Selector} of the GA.
1549 *
1550 * @since 3.1
1551 *
1552 * @return the used survivor {@link Selector} of the GA.
1553 */
1554 public Selector<G, C> getSurvivorsSelector() {
1555 return _survivorsSelector;
1556 }
1557
1558 /**
1559 * Return the optimization strategy.
1560 *
1561 * @since 3.1
1562 *
1563 * @return the optimization strategy
1564 */
1565 public Optimize getOptimize() {
1566 return _optimize;
1567 }
1568
1569 /**
1570 * Return the number of individuals of a population.
1571 *
1572 * @since 3.1
1573 *
1574 * @return the number of individuals of a population
1575 */
1576 public int getPopulationSize() {
1577 return _populationSize;
1578 }
1579
1580 /**
1581 * Return the maximal number of attempt before the {@code Engine} gives
1582 * up creating a valid individual ({@code Phenotype}).
1583 *
1584 * @since 3.1
1585 *
1586 * @return the maximal number of {@code Phenotype} creation attempts
1587 */
1588 public int getIndividualCreationRetries() {
1589 return _individualCreationRetries;
1590 }
1591
1592 /**
1593 * Return the evolution result mapper.
1594 *
1595 * @since 4.0
1596 *
1597 * @return the evolution result mapper
1598 */
1599 public UnaryOperator<EvolutionResult<G, C>> getMapper() {
1600 return _mapper;
1601 }
1602
1603 /**
1604 * Create a new builder, with the current configuration.
1605 *
1606 * @since 3.1
1607 *
1608 * @return a new builder, with the current configuration
1609 */
1610 @Override
1611 public Builder<G, C> copy() {
1612 return new Builder<G, C>(_genotypeFactory, _fitnessFunction)
1613 .alterers(_alterer)
1614 .clock(_clock)
1615 .executor(_executor)
1616 .evaluator(_evaluator)
1617 .fitnessScaler(_fitnessScaler)
1618 .maximalPhenotypeAge(_maximalPhenotypeAge)
1619 .offspringFraction(_offspringFraction)
1620 .offspringSelector(_offspringSelector)
1621 .phenotypeValidator(_validator)
1622 .optimize(_optimize)
1623 .populationSize(_populationSize)
1624 .survivorsSelector(_survivorsSelector)
1625 .individualCreationRetries(_individualCreationRetries)
1626 .mapping(_mapper);
1627 }
1628
1629 }
1630
1631 }
|