0001 /*
0002 * Java Genetic Algorithm Library (jenetics-6.2.0).
0003 * Copyright (c) 2007-2021 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.String.format;
0023 import static java.util.Objects.requireNonNull;
0024 import static java.util.concurrent.CompletableFuture.supplyAsync;
0025 import static java.util.concurrent.ForkJoinPool.commonPool;
0026
0027 import java.time.Clock;
0028 import java.util.concurrent.CompletableFuture;
0029 import java.util.concurrent.Executor;
0030 import java.util.function.Function;
0031 import java.util.function.Supplier;
0032 import java.util.stream.Stream;
0033
0034 import io.jenetics.Alterer;
0035 import io.jenetics.AltererResult;
0036 import io.jenetics.Chromosome;
0037 import io.jenetics.Gene;
0038 import io.jenetics.Genotype;
0039 import io.jenetics.Optimize;
0040 import io.jenetics.Phenotype;
0041 import io.jenetics.Selector;
0042 import io.jenetics.util.Copyable;
0043 import io.jenetics.util.Factory;
0044 import io.jenetics.util.ISeq;
0045 import io.jenetics.util.MSeq;
0046 import io.jenetics.util.NanoClock;
0047 import io.jenetics.util.Seq;
0048
0049 /**
0050 * Genetic algorithm <em>engine</em> which is the main class. The following
0051 * example shows the main steps in initializing and executing the GA.
0052 *
0053 * <pre>{@code
0054 * public class RealFunction {
0055 * // Definition of the fitness function.
0056 * private static Double eval(final Genotype<DoubleGene> gt) {
0057 * final double x = gt.gene().doubleValue();
0058 * return cos(0.5 + sin(x))*cos(x);
0059 * }
0060 *
0061 * public static void main(String[] args) {
0062 * // Create/configuring the engine via its builder.
0063 * final Engine<DoubleGene, Double> engine = Engine
0064 * .builder(
0065 * RealFunction::eval,
0066 * DoubleChromosome.of(0.0, 2.0*PI))
0067 * .populationSize(500)
0068 * .optimize(Optimize.MINIMUM)
0069 * .alterers(
0070 * new Mutator<>(0.03),
0071 * new MeanAlterer<>(0.6))
0072 * .build();
0073 *
0074 * // Execute the GA (engine).
0075 * final Phenotype<DoubleGene, Double> result = engine.stream()
0076 * // Truncate the evolution stream if no better individual could
0077 * // be found after 5 consecutive generations.
0078 * .limit(bySteadyFitness(5))
0079 * // Terminate the evolution after maximal 100 generations.
0080 * .limit(100)
0081 * .collect(toBestPhenotype());
0082 * }
0083 * }
0084 * }</pre>
0085 *
0086 * The architecture allows to decouple the configuration of the engine from the
0087 * execution. The {@code Engine} is configured via the {@code Engine.Builder}
0088 * class and can't be changed after creation. The actual <i>evolution</i> is
0089 * performed by the {@link EvolutionStream}, which is created by the
0090 * {@code Engine}.
0091 *
0092 * @implNote
0093 * This class is thread safe:
0094 * No mutable state is maintained by the engine. Therefore it is save to
0095 * create multiple evolution streams with one engine, which may be actually
0096 * used in different threads.
0097 *
0098 * @see Engine.Builder
0099 * @see EvolutionStart
0100 * @see EvolutionResult
0101 * @see EvolutionStream
0102 * @see EvolutionStatistics
0103 * @see Codec
0104 * @see Constraint
0105 *
0106 * @param <G> the gene type
0107 * @param <C> the fitness result type
0108 *
0109 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
0110 * @since 3.0
0111 * @version 6.0
0112 */
0113 public final class Engine<
0114 G extends Gene<?, G>,
0115 C extends Comparable<? super C>
0116 >
0117 implements
0118 Evolution<G, C>,
0119 EvolutionStreamable<G, C>,
0120 Evaluator<G, C>
0121 {
0122
0123 // Problem definition.
0124 private final Evaluator<G, C> _evaluator;
0125 private final Factory<Genotype<G>> _genotypeFactory;
0126 private final Constraint<G, C> _constraint;
0127 private final Optimize _optimize;
0128
0129 // Evolution parameters.
0130 private final EvolutionParams<G, C> _evolutionParams;
0131
0132 // Execution context for concurrent execution of evolving steps.
0133 private final Executor _executor;
0134 private final Clock _clock;
0135 private final EvolutionInterceptor<G, C> _interceptor;
0136
0137
0138 /**
0139 * Create a new GA engine with the given parameters.
0140 *
0141 * @param evaluator the population fitness evaluator
0142 * @param genotypeFactory the genotype factory this GA is working with.
0143 * @param constraint phenotype constraint which can override the default
0144 * implementation the {@link Phenotype#isValid()} method and repairs
0145 * invalid phenotypes when needed.
0146 * @param optimize the kind of optimization (minimize or maximize)
0147 * @param evolutionParams the evolution parameters, which influences the
0148 * evolution process
0149 * @param executor the executor used for executing the single evolve steps
0150 * @param clock the clock used for calculating the timing results
0151 * @param interceptor the evolution interceptor, which gives additional
0152 * possibilities to influence the actual evolution
0153 * @throws NullPointerException if one of the arguments is {@code null}
0154 * @throws IllegalArgumentException if the given integer values are smaller
0155 * than one.
0156 */
0157 Engine(
0158 final Evaluator<G, C> evaluator,
0159 final Factory<Genotype<G>> genotypeFactory,
0160 final Constraint<G, C> constraint,
0161 final Optimize optimize,
0162 final EvolutionParams<G, C> evolutionParams,
0163 final Executor executor,
0164 final Clock clock,
0165 final EvolutionInterceptor<G, C> interceptor
0166 ) {
0167 _evaluator = requireNonNull(evaluator);
0168 _genotypeFactory = requireNonNull(genotypeFactory);
0169 _constraint = requireNonNull(constraint);
0170 _optimize = requireNonNull(optimize);
0171 _evolutionParams = requireNonNull(evolutionParams);
0172 _executor = requireNonNull(executor);
0173 _clock = requireNonNull(clock);
0174 _interceptor = requireNonNull(interceptor);
0175 }
0176
0177 @Override
0178 public EvolutionResult<G, C> evolve(final EvolutionStart<G, C> start) {
0179 final EvolutionTiming timing = new EvolutionTiming(_clock);
0180 timing.evolve.start();
0181
0182 final EvolutionStart<G, C> interceptedStart = _interceptor.before(start);
0183
0184 // Create initial population if `start` is empty.
0185 final EvolutionStart<G, C> es = interceptedStart.population().isEmpty()
0186 ? evolutionStart(interceptedStart)
0187 : interceptedStart;
0188
0189 // Initial evaluation of the population.
0190 final ISeq<Phenotype<G, C>> population = es.isDirty()
0191 ? timing.evaluation.timing(() -> eval(es.population()))
0192 : es.population();
0193
0194 // Select the offspring population.
0195 final CompletableFuture<ISeq<Phenotype<G, C>>> offspring =
0196 supplyAsync(() ->
0197 timing.offspringSelection.timing(() ->
0198 selectOffspring(population)
0199 ),
0200 _executor
0201 );
0202
0203 // Select the survivor population.
0204 final CompletableFuture<ISeq<Phenotype<G, C>>> survivors =
0205 supplyAsync(() ->
0206 timing.survivorsSelection.timing(() ->
0207 selectSurvivors(population)
0208 ),
0209 _executor
0210 );
0211
0212 // Altering the offspring population.
0213 final CompletableFuture<AltererResult<G, C>> alteredOffspring =
0214 offspring.thenApplyAsync(off ->
0215 timing.offspringAlter.timing(() ->
0216 _evolutionParams.alterer().alter(off, es.generation())
0217 ),
0218 _executor
0219 );
0220
0221 // Filter and replace invalid and old survivor individuals.
0222 final CompletableFuture<FilterResult<G, C>> filteredSurvivors =
0223 survivors.thenApplyAsync(sur ->
0224 timing.survivorFilter.timing(() ->
0225 filter(sur, es.generation())
0226 ),
0227 _executor
0228 );
0229
0230 // Filter and replace invalid and old offspring individuals.
0231 final CompletableFuture<FilterResult<G, C>> filteredOffspring =
0232 alteredOffspring.thenApplyAsync(off ->
0233 timing.offspringFilter.timing(() ->
0234 filter(off.population(), es.generation())
0235 ),
0236 _executor
0237 );
0238
0239 // Combining survivors and offspring to the new population.
0240 final CompletableFuture<ISeq<Phenotype<G, C>>> nextPopulation =
0241 filteredSurvivors.thenCombineAsync(
0242 filteredOffspring,
0243 (s, o) -> ISeq.of(s.population.append(o.population)),
0244 _executor
0245 );
0246
0247 // Evaluate the fitness-function and wait for result.
0248 final ISeq<Phenotype<G, C>> pop = nextPopulation.join();
0249 final ISeq<Phenotype<G, C>> result = timing.evaluation.timing(() ->
0250 eval(pop)
0251 );
0252
0253 final int killCount =
0254 filteredOffspring.join().killCount +
0255 filteredSurvivors.join().killCount;
0256
0257 final int invalidCount =
0258 filteredOffspring.join().invalidCount +
0259 filteredSurvivors.join().invalidCount;
0260
0261 final int alterationCount = alteredOffspring.join().alterations();
0262
0263 EvolutionResult<G, C> er = EvolutionResult.of(
0264 _optimize,
0265 result,
0266 es.generation(),
0267 timing.toDurations(),
0268 killCount,
0269 invalidCount,
0270 alterationCount
0271 );
0272
0273 final EvolutionResult<G, C> interceptedResult = _interceptor.after(er);
0274 if (er != interceptedResult) {
0275 er = interceptedResult.withPopulation(
0276 timing.evaluation.timing(() ->
0277 eval(interceptedResult.population())
0278 ));
0279 }
0280
0281 timing.evolve.stop();
0282
0283 return er
0284 .withDurations(timing.toDurations())
0285 .clean();
0286 }
0287
0288 // Selects the survivors population. A new population object is returned.
0289 private ISeq<Phenotype<G, C>>
0290 selectSurvivors(final ISeq<Phenotype<G, C>> population) {
0291 return _evolutionParams.survivorsSize() > 0
0292 ? _evolutionParams.survivorsSelector()
0293 .select(population, _evolutionParams.survivorsSize(), _optimize)
0294 : ISeq.empty();
0295 }
0296
0297 // Selects the offspring population. A new population object is returned.
0298 private ISeq<Phenotype<G, C>>
0299 selectOffspring(final ISeq<Phenotype<G, C>> population) {
0300 return _evolutionParams.offspringSize() > 0
0301 ? _evolutionParams.offspringSelector()
0302 .select(population, _evolutionParams.offspringSize(), _optimize)
0303 : ISeq.empty();
0304 }
0305
0306 // Filters out invalid and old individuals. Filtering is done in place.
0307 private FilterResult<G, C> filter(
0308 final Seq<Phenotype<G, C>> population,
0309 final long generation
0310 ) {
0311 int killCount = 0;
0312 int invalidCount = 0;
0313
0314 final MSeq<Phenotype<G, C>> pop = MSeq.of(population);
0315 for (int i = 0, n = pop.size(); i < n; ++i) {
0316 final Phenotype<G, C> individual = pop.get(i);
0317
0318 if (!_constraint.test(individual)) {
0319 pop.set(i, _constraint.repair(individual, generation));
0320 ++invalidCount;
0321 } else if (individual.age(generation) >
0322 _evolutionParams.maximalPhenotypeAge())
0323 {
0324 pop.set(i, Phenotype.of(_genotypeFactory.newInstance(), generation));
0325 ++killCount;
0326 }
0327 }
0328
0329 return new FilterResult<>(pop.toISeq(), killCount, invalidCount);
0330 }
0331
0332
0333 /* *************************************************************************
0334 * Evaluation methods.
0335 **************************************************************************/
0336
0337 /**
0338 * Evaluates the fitness function of the given population with the configured
0339 * {@link Evaluator} of this engine and returns a new population
0340 * with its fitness value assigned.
0341 *
0342 * @since 5.0
0343 *
0344 * @see Evaluator
0345 * @see Evaluator#eval(Seq)
0346 *
0347 * @param population the population to evaluate
0348 * @return a new population with assigned fitness values
0349 * @throws IllegalStateException if the configured fitness function doesn't
0350 * return a population with the same size as the input population.
0351 * This exception is also thrown if one of the populations
0352 * phenotype has no fitness value assigned.
0353 */
0354 @Override
0355 public ISeq<Phenotype<G, C>> eval(final Seq<Phenotype<G, C>> population) {
0356 final ISeq<Phenotype<G, C>> evaluated = _evaluator.eval(population);
0357
0358 if (population.size() != evaluated.size()) {
0359 throw new IllegalStateException(format(
0360 "Expected %d individuals, but got %d. " +
0361 "Check your evaluator function.",
0362 population.size(), evaluated.size()
0363 ));
0364 }
0365 if (!evaluated.forAll(Phenotype::isEvaluated)) {
0366 throw new IllegalStateException(
0367 "Some phenotypes have no assigned fitness value. " +
0368 "Check your evaluator function."
0369 );
0370 }
0371
0372 return evaluated;
0373 }
0374
0375
0376 /* *************************************************************************
0377 * Evolution Stream creation.
0378 **************************************************************************/
0379
0380 @Override
0381 public EvolutionStream<G, C>
0382 stream(final Supplier<EvolutionStart<G, C>> start) {
0383 return EvolutionStream.ofEvolution(
0384 () -> evolutionStart(start.get()),
0385 this
0386 );
0387 }
0388
0389 @Override
0390 public EvolutionStream<G, C> stream(final EvolutionInit<G> init) {
0391 return stream(evolutionStart(init));
0392 }
0393
0394 private EvolutionStart<G, C>
0395 evolutionStart(final EvolutionStart<G, C> start) {
0396 final ISeq<Phenotype<G, C>> population = start.population();
0397 final long gen = start.generation();
0398
0399 final Stream<Phenotype<G, C>> stream = Stream.concat(
0400 population.stream(),
0401 _genotypeFactory.instances()
0402 .map(gt -> Phenotype.of(gt, gen))
0403 );
0404
0405 final ISeq<Phenotype<G, C>> pop = stream
0406 .limit(populationSize())
0407 .collect(ISeq.toISeq());
0408
0409 return EvolutionStart.of(pop, gen);
0410 }
0411
0412 private EvolutionStart<G, C>
0413 evolutionStart(final EvolutionInit<G> init) {
0414 final ISeq<Genotype<G>> pop = init.population();
0415 final long gen = init.generation();
0416
0417 return evolutionStart(
0418 EvolutionStart.of(
0419 pop.map(gt -> Phenotype.of(gt, gen)),
0420 gen
0421 )
0422 );
0423 }
0424
0425 /* *************************************************************************
0426 * Property access methods.
0427 **************************************************************************/
0428
0429 /**
0430 * Return the used genotype {@link Factory} of the GA. The genotype factory
0431 * is used for creating the initial population and new, random individuals
0432 * when needed (as replacement for invalid and/or died genotypes).
0433 *
0434 * @return the used genotype {@link Factory} of the GA.
0435 */
0436 public Factory<Genotype<G>> genotypeFactory() {
0437 return _genotypeFactory;
0438 }
0439
0440 /**
0441 * Return the constraint of the evolution problem.
0442 *
0443 * @since 5.0
0444 *
0445 * @return the constraint of the evolution problem
0446 */
0447 public Constraint<G, C> constraint() {
0448 return _constraint;
0449 }
0450
0451 /**
0452 * Return the used survivor {@link Selector} of the GA.
0453 *
0454 * @return the used survivor {@link Selector} of the GA.
0455 */
0456 public Selector<G, C> survivorsSelector() {
0457 return _evolutionParams.survivorsSelector();
0458 }
0459
0460 /**
0461 * Return the used offspring {@link Selector} of the GA.
0462 *
0463 * @return the used offspring {@link Selector} of the GA.
0464 */
0465 public Selector<G, C> offspringSelector() {
0466 return _evolutionParams.offspringSelector();
0467 }
0468
0469 /**
0470 * Return the used {@link Alterer} of the GA.
0471 *
0472 * @return the used {@link Alterer} of the GA.
0473 */
0474 public Alterer<G, C> alterer() {
0475 return _evolutionParams.alterer();
0476 }
0477
0478 /**
0479 * Return the number of selected offspring.
0480 *
0481 * @return the number of selected offspring
0482 */
0483 public int offspringSize() {
0484 return _evolutionParams.offspringSize();
0485 }
0486
0487 /**
0488 * The number of selected survivors.
0489 *
0490 * @return the number of selected survivors
0491 */
0492 public int survivorsSize() {
0493 return _evolutionParams.survivorsSize();
0494 }
0495
0496 /**
0497 * Return the number of individuals of a population.
0498 *
0499 * @return the number of individuals of a population
0500 */
0501 public int populationSize() {
0502 return _evolutionParams.populationSize();
0503 }
0504
0505 /**
0506 * Return the maximal allowed phenotype age.
0507 *
0508 * @return the maximal allowed phenotype age
0509 */
0510 public long maximalPhenotypeAge() {
0511 return _evolutionParams.maximalPhenotypeAge();
0512 }
0513
0514 /**
0515 * Return the optimization strategy.
0516 *
0517 * @return the optimization strategy
0518 */
0519 public Optimize optimize() {
0520 return _optimize;
0521 }
0522
0523 /**
0524 * Return the {@link Clock} the engine is using for measuring the execution
0525 * time.
0526 *
0527 * @return the clock used for measuring the execution time
0528 */
0529 public Clock clock() {
0530 return _clock;
0531 }
0532
0533 /**
0534 * Return the {@link Executor} the engine is using for executing the
0535 * evolution steps.
0536 *
0537 * @return the executor used for performing the evolution steps
0538 */
0539 public Executor executor() {
0540 return _executor;
0541 }
0542
0543 /**
0544 * Return the evolution interceptor.
0545 *
0546 * @since 6.0
0547 *
0548 * @return the evolution result mapper
0549 */
0550 public EvolutionInterceptor<G, C> interceptor() {
0551 return _interceptor;
0552 }
0553
0554 /**
0555 * Create a new evolution {@code Engine.Builder} initialized with the values
0556 * of the current evolution {@code Engine}. With this method, the evolution
0557 * engine can serve as a template for a new one.
0558 *
0559 * @return a new engine builder
0560 */
0561 public Builder<G, C> toBuilder() {
0562 return new Builder<>(_evaluator, _genotypeFactory)
0563 .clock(_clock)
0564 .executor(_executor)
0565 .optimize(_optimize)
0566 .constraint(_constraint)
0567 .evolutionParams(_evolutionParams)
0568 .interceptor(_interceptor);
0569 }
0570
0571
0572 /* *************************************************************************
0573 * Static Builder methods.
0574 **************************************************************************/
0575
0576 /**
0577 * Create a new evolution {@code Engine.Builder} with the given fitness
0578 * function and genotype factory.
0579 *
0580 * @param ff the fitness function
0581 * @param gtf the genotype factory
0582 * @param <G> the gene type
0583 * @param <C> the fitness function result type
0584 * @return a new engine builder
0585 * @throws java.lang.NullPointerException if one of the arguments is
0586 * {@code null}.
0587 */
0588 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
0589 Builder<G, C> builder(
0590 final Function<? super Genotype<G>, ? extends C> ff,
0591 final Factory<Genotype<G>> gtf
0592 ) {
0593 return new Builder<>(Evaluators.concurrent(ff, commonPool()), gtf);
0594 }
0595
0596 /**
0597 * Create a new evolution {@code Engine.Builder} with the given fitness
0598 * function and problem {@code codec}.
0599 *
0600 * @since 3.2
0601 *
0602 * @param ff the fitness evaluator
0603 * @param codec the problem codec
0604 * @param <T> the fitness function input type
0605 * @param <C> the fitness function result type
0606 * @param <G> the gene type
0607 * @return a new engine builder
0608 * @throws java.lang.NullPointerException if one of the arguments is
0609 * {@code null}.
0610 */
0611 public static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
0612 Builder<G, C> builder(
0613 final Function<? super T, ? extends C> ff,
0614 final Codec<T, G> codec
0615 ) {
0616 return builder(ff.compose(codec.decoder()), codec.encoding());
0617 }
0618
0619 /**
0620 * Create a new evolution {@code Engine.Builder} for the given
0621 * {@link Problem}.
0622 *
0623 * @since 3.4
0624 *
0625 * @param problem the problem to be solved by the evolution {@code Engine}
0626 * @param <T> the (<i>native</i>) argument type of the problem fitness function
0627 * @param <G> the gene type the evolution engine is working with
0628 * @param <C> the result type of the fitness function
0629 * @return Create a new evolution {@code Engine.Builder}
0630 */
0631 public static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
0632 Builder<G, C> builder(final Problem<T, G, C> problem) {
0633 final var builder = builder(problem.fitness(), problem.codec());
0634 problem.constraint().ifPresent(builder::constraint);
0635 return builder;
0636 }
0637
0638 /**
0639 * Create a new evolution {@code Engine.Builder} with the given fitness
0640 * function and chromosome templates.
0641 *
0642 * @param ff the fitness function
0643 * @param chromosome the first chromosome
0644 * @param chromosomes the chromosome templates
0645 * @param <G> the gene type
0646 * @param <C> the fitness function result type
0647 * @return a new engine builder
0648 * @throws java.lang.NullPointerException if one of the arguments is
0649 * {@code null}.
0650 */
0651 @SafeVarargs
0652 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
0653 Builder<G, C> builder(
0654 final Function<? super Genotype<G>, ? extends C> ff,
0655 final Chromosome<G> chromosome,
0656 final Chromosome<G>... chromosomes
0657 ) {
0658 return builder(ff, Genotype.of(chromosome, chromosomes));
0659 }
0660
0661
0662 /* *************************************************************************
0663 * Engine builder
0664 **************************************************************************/
0665
0666
0667 /**
0668 * Builder class for building GA {@code Engine} instances.
0669 *
0670 * @see Engine
0671 *
0672 * @param <G> the gene type
0673 * @param <C> the fitness function result type
0674 *
0675 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
0676 * @since 3.0
0677 * @version 6.0
0678 */
0679 public static final class Builder<
0680 G extends Gene<?, G>,
0681 C extends Comparable<? super C>
0682 >
0683 implements Copyable<Builder<G, C>>
0684 {
0685
0686 // No default values for this properties.
0687 private final Evaluator<G, C> _evaluator;
0688 private final Factory<Genotype<G>> _genotypeFactory;
0689 private Constraint<G, C> _constraint;
0690 private Optimize _optimize = Optimize.MAXIMUM;
0691
0692 // Evolution parameters.
0693 private final EvolutionParams.Builder<G, C> _evolutionParams =
0694 EvolutionParams.builder();
0695
0696
0697 // Engine execution environment.
0698 private Executor _executor = commonPool();
0699 private Clock _clock = NanoClock.systemUTC();
0700
0701 private EvolutionInterceptor<G, C> _interceptor =
0702 EvolutionInterceptor.identity();
0703
0704 /**
0705 * Create a new evolution {@code Engine.Builder} with the given fitness
0706 * evaluator and genotype factory. This is the most general way for
0707 * creating an engine builder.
0708 *
0709 * @since 5.0
0710 *
0711 * @see Engine#builder(Function, Codec)
0712 * @see Engine#builder(Function, Factory)
0713 * @see Engine#builder(Problem)
0714 * @see Engine#builder(Function, Chromosome, Chromosome[])
0715 *
0716 * @param evaluator the fitness evaluator
0717 * @param genotypeFactory the genotype factory
0718 * @throws NullPointerException if one of the arguments is {@code null}.
0719 */
0720 public Builder(
0721 final Evaluator<G, C> evaluator,
0722 final Factory<Genotype<G>> genotypeFactory
0723 ) {
0724 _genotypeFactory = requireNonNull(genotypeFactory);
0725 _evaluator = requireNonNull(evaluator);
0726 }
0727
0728 /**
0729 * Applies the given {@code setup} recipe to {@code this} engine builder.
0730 *
0731 * @since 6.0
0732 *
0733 * @param setup the setup recipe applying to {@code this} builder
0734 * @return {@code this} builder, for command chaining
0735 * @throws NullPointerException if the {@code setup} is {@code null}.
0736 */
0737 public Builder<G, C> setup(final Setup<G, C> setup) {
0738 setup.apply(this);
0739 return this;
0740 }
0741
0742 /**
0743 * Set the evolution parameters used by the engine.
0744 *
0745 * @since 5.2
0746 *
0747 * @param params the evolution parameter
0748 * @return {@code this} builder, for command chaining
0749 * @throws NullPointerException if the {@code params} is {@code null}.
0750 */
0751 public Builder<G, C> evolutionParams(final EvolutionParams<G, C> params) {
0752 _evolutionParams.evolutionParams(params);
0753 return this;
0754 }
0755
0756 /**
0757 * The selector used for selecting the offspring population. <i>Default
0758 * values is set to {@code TournamentSelector<>(3)}.</i>
0759 *
0760 * @param selector used for selecting the offspring population
0761 * @return {@code this} builder, for command chaining
0762 * @throws NullPointerException if one of the {@code selector} is
0763 * {@code null}.
0764 */
0765 public Builder<G, C> offspringSelector(final Selector<G, C> selector) {
0766 _evolutionParams.offspringSelector(selector);
0767 return this;
0768 }
0769
0770 /**
0771 * The selector used for selecting the survivors population. <i>Default
0772 * values is set to {@code TournamentSelector<>(3)}.</i>
0773 *
0774 * @param selector used for selecting survivors population
0775 * @return {@code this} builder, for command chaining
0776 * @throws NullPointerException if one of the {@code selector} is
0777 * {@code null}.
0778 */
0779 public Builder<G, C> survivorsSelector(final Selector<G, C> selector) {
0780 _evolutionParams.survivorsSelector(selector);
0781 return this;
0782 }
0783
0784 /**
0785 * The selector used for selecting the survivors and offspring
0786 * population. <i>Default values is set to
0787 * {@code TournamentSelector<>(3)}.</i>
0788 *
0789 * @param selector used for selecting survivors and offspring population
0790 * @return {@code this} builder, for command chaining
0791 * @throws NullPointerException if one of the {@code selector} is
0792 * {@code null}.
0793 */
0794 public Builder<G, C> selector(final Selector<G, C> selector) {
0795 _evolutionParams.selector(selector);
0796 return this;
0797 }
0798
0799 /**
0800 * The alterers used for alter the offspring population. <i>Default
0801 * values is set to {@code new SinglePointCrossover<>(0.2)} followed by
0802 * {@code new Mutator<>(0.15)}.</i>
0803 *
0804 * @param first the first alterer used for alter the offspring
0805 * population
0806 * @param rest the rest of the alterers used for alter the offspring
0807 * population
0808 * @return {@code this} builder, for command chaining
0809 * @throws NullPointerException if one of the alterers is {@code null}.
0810 */
0811 @SafeVarargs
0812 public final Builder<G, C> alterers(
0813 final Alterer<G, C> first,
0814 final Alterer<G, C>... rest
0815 ) {
0816 _evolutionParams.alterers(first, rest);
0817 return this;
0818 }
0819
0820 /**
0821 * The phenotype constraint is used for detecting invalid individuals
0822 * and repairing them.
0823 *
0824 * <p><i>Default implementation uses {@code Phenotype::isValid} for
0825 * validating the phenotype.</i></p>
0826 *
0827 * @since 5.0
0828 *
0829 * @param constraint phenotype constraint which can override the default
0830 * implementation the {@link Phenotype#isValid()} method and repairs
0831 * invalid phenotypes when needed.
0832 * @return {@code this} builder, for command chaining
0833 * @throws NullPointerException if one of the {@code constraint} is
0834 * {@code null}.
0835 */
0836 public Builder<G, C> constraint(final Constraint<G, C> constraint) {
0837 _constraint = constraint;
0838 return this;
0839 }
0840
0841 /**
0842 * The optimization strategy used by the engine. <i>Default values is
0843 * set to {@code Optimize.MAXIMUM}.</i>
0844 *
0845 * @param optimize the optimization strategy used by the engine
0846 * @return {@code this} builder, for command chaining
0847 * @throws NullPointerException if one of the {@code optimize} is
0848 * {@code null}.
0849 */
0850 public Builder<G, C> optimize(final Optimize optimize) {
0851 _optimize = requireNonNull(optimize);
0852 return this;
0853 }
0854
0855 /**
0856 * Set to a fitness maximizing strategy.
0857 *
0858 * @since 3.4
0859 *
0860 * @return {@code this} builder, for command chaining
0861 */
0862 public Builder<G, C> maximizing() {
0863 return optimize(Optimize.MAXIMUM);
0864 }
0865
0866 /**
0867 * Set to a fitness minimizing strategy.
0868 *
0869 * @since 3.4
0870 *
0871 * @return {@code this} builder, for command chaining
0872 */
0873 public Builder<G, C> minimizing() {
0874 return optimize(Optimize.MINIMUM);
0875 }
0876
0877 /**
0878 * The offspring fraction. <i>Default values is set to {@code 0.6}.</i>
0879 * This method call is equivalent to
0880 * {@code survivorsFraction(1 - offspringFraction)} and will override
0881 * any previously set survivors-fraction.
0882 *
0883 * @see #survivorsFraction(double)
0884 *
0885 * @param fraction the offspring fraction
0886 * @return {@code this} builder, for command chaining
0887 * @throws java.lang.IllegalArgumentException if the fraction is not
0888 * within the range [0, 1].
0889 */
0890 public Builder<G, C> offspringFraction(final double fraction) {
0891 _evolutionParams.offspringFraction(fraction);
0892 return this;
0893 }
0894
0895 /**
0896 * The survivors fraction. <i>Default values is set to {@code 0.4}.</i>
0897 * This method call is equivalent to
0898 * {@code offspringFraction(1 - survivorsFraction)} and will override
0899 * any previously set offspring-fraction.
0900 *
0901 * @since 3.8
0902 *
0903 * @see #offspringFraction(double)
0904 *
0905 * @param fraction the survivors fraction
0906 * @return {@code this} builder, for command chaining
0907 * @throws java.lang.IllegalArgumentException if the fraction is not
0908 * within the range [0, 1].
0909 */
0910 public Builder<G, C> survivorsFraction(final double fraction) {
0911 return offspringFraction(1 - fraction);
0912 }
0913
0914 /**
0915 * The number of offspring individuals.
0916 *
0917 * @since 3.8
0918 *
0919 * @param size the number of offspring individuals.
0920 * @return {@code this} builder, for command chaining
0921 * @throws java.lang.IllegalArgumentException if the size is not
0922 * within the range [0, population-size].
0923 */
0924 public Builder<G, C> offspringSize(final int size) {
0925 if (size < 0) {
0926 throw new IllegalArgumentException(format(
0927 "Offspring size must be greater or equal zero, but was %s.",
0928 size
0929 ));
0930 }
0931
0932 return offspringFraction(size/(double)_evolutionParams.populationSize());
0933 }
0934
0935 /**
0936 * The number of survivors.
0937 *
0938 * @since 3.8
0939 *
0940 * @param size the number of survivors.
0941 * @return {@code this} builder, for command chaining
0942 * @throws java.lang.IllegalArgumentException if the size is not
0943 * within the range [0, population-size].
0944 */
0945 public Builder<G, C> survivorsSize(final int size) {
0946 if (size < 0) {
0947 throw new IllegalArgumentException(format(
0948 "Survivors must be greater or equal zero, but was %s.",
0949 size
0950 ));
0951 }
0952
0953 return survivorsFraction(size/(double)_evolutionParams.populationSize());
0954 }
0955
0956 /**
0957 * The number of individuals which form the population. <i>Default
0958 * values is set to {@code 50}.</i>
0959 *
0960 * @param size the number of individuals of a population
0961 * @return {@code this} builder, for command chaining
0962 * @throws java.lang.IllegalArgumentException if {@code size < 1}
0963 */
0964 public Builder<G, C> populationSize(final int size) {
0965 _evolutionParams.populationSize(size);
0966 return this;
0967 }
0968
0969 /**
0970 * The maximal allowed age of a phenotype. <i>Default values is set to
0971 * {@code 70}.</i>
0972 *
0973 * @param age the maximal phenotype age
0974 * @return {@code this} builder, for command chaining
0975 * @throws java.lang.IllegalArgumentException if {@code age < 1}
0976 */
0977 public Builder<G, C> maximalPhenotypeAge(final long age) {
0978 _evolutionParams.maximalPhenotypeAge(age);
0979 return this;
0980 }
0981
0982 /**
0983 * The executor used by the engine.
0984 *
0985 * @param executor the executor used by the engine
0986 * @return {@code this} builder, for command chaining
0987 */
0988 public Builder<G, C> executor(final Executor executor) {
0989 _executor = requireNonNull(executor);
0990 return this;
0991 }
0992
0993 /**
0994 * The clock used for calculating the execution durations.
0995 *
0996 * @param clock the clock used for calculating the execution durations
0997 * @return {@code this} builder, for command chaining
0998 */
0999 public Builder<G, C> clock(final Clock clock) {
1000 _clock = requireNonNull(clock);
1001 return this;
1002 }
1003
1004 /**
1005 * The evolution interceptor, which allows to change the evolution start
1006 * and result.
1007 *
1008 * @since 6.0
1009 * @see EvolutionResult#toUniquePopulation()
1010 *
1011 * @param interceptor the evolution interceptor
1012 * @return {@code this} builder, for command chaining
1013 * @throws NullPointerException if the given {@code interceptor} is
1014 * {@code null}
1015 */
1016 public Builder<G, C>
1017 interceptor(final EvolutionInterceptor<G, C> interceptor) {
1018 _interceptor = requireNonNull(interceptor);
1019 return this;
1020 }
1021
1022 /**
1023 * Builds an new {@code Engine} instance from the set properties.
1024 *
1025 * @return an new {@code Engine} instance from the set properties
1026 */
1027 public Engine<G, C> build() {
1028 return new Engine<>(
1029 __evaluator(),
1030 _genotypeFactory,
1031 __constraint(),
1032 _optimize,
1033 _evolutionParams.build(),
1034 _executor,
1035 _clock,
1036 _interceptor
1037 );
1038 }
1039
1040 private Evaluator<G, C> __evaluator() {
1041 return _evaluator instanceof ConcurrentEvaluator
1042 ? ((ConcurrentEvaluator<G, C>)_evaluator).with(_executor)
1043 : _evaluator;
1044 }
1045
1046 private Constraint<G, C> __constraint() {
1047 return _constraint == null
1048 ? RetryConstraint.of(_genotypeFactory)
1049 : _constraint;
1050 }
1051
1052 /* *********************************************************************
1053 * Current properties
1054 ***********************************************************************/
1055
1056 /**
1057 * Return the used {@link Alterer} of the GA.
1058 *
1059 * @return the used {@link Alterer} of the GA.
1060 */
1061 public Alterer<G, C> alterer() {
1062 return _evolutionParams.alterer();
1063 }
1064
1065 /**
1066 * Return the {@link Clock} the engine is using for measuring the execution
1067 * time.
1068 *
1069 * @since 3.1
1070 *
1071 * @return the clock used for measuring the execution time
1072 */
1073 public Clock clock() {
1074 return _clock;
1075 }
1076
1077 /**
1078 * Return the {@link Executor} the engine is using for executing the
1079 * evolution steps.
1080 *
1081 * @since 3.1
1082 *
1083 * @return the executor used for performing the evolution steps
1084 */
1085 public Executor executor() {
1086 return _executor;
1087 }
1088
1089 /**
1090 * Return the used genotype {@link Factory} of the GA. The genotype factory
1091 * is used for creating the initial population and new, random individuals
1092 * when needed (as replacement for invalid and/or died genotypes).
1093 *
1094 * @since 3.1
1095 *
1096 * @return the used genotype {@link Factory} of the GA.
1097 */
1098 public Factory<Genotype<G>> genotypeFactory() {
1099 return _genotypeFactory;
1100 }
1101
1102 /**
1103 * Return the constraint of the evolution problem.
1104 *
1105 * @since 5.0
1106 *
1107 * @return the constraint of the evolution problem
1108 */
1109 public Constraint<G, C> constraint() {
1110 return _constraint;
1111 }
1112
1113 /**
1114 * Return the currently set evolution parameters.
1115 *
1116 * @since 5.2
1117 *
1118 * @return the currently set evolution parameters
1119 */
1120 public EvolutionParams<G, C> evolutionParams() {
1121 return _evolutionParams.build();
1122 }
1123
1124 /**
1125 * Return the maximal allowed phenotype age.
1126 *
1127 * @since 3.1
1128 *
1129 * @return the maximal allowed phenotype age
1130 */
1131 public long maximalPhenotypeAge() {
1132 return _evolutionParams.maximalPhenotypeAge();
1133 }
1134
1135 /**
1136 * Return the offspring fraction.
1137 *
1138 * @return the offspring fraction.
1139 */
1140 public double offspringFraction() {
1141 return _evolutionParams.offspringFraction();
1142 }
1143
1144 /**
1145 * Return the used offspring {@link Selector} of the GA.
1146 *
1147 * @since 3.1
1148 *
1149 * @return the used offspring {@link Selector} of the GA.
1150 */
1151 public Selector<G, C> offspringSelector() {
1152 return _evolutionParams.offspringSelector();
1153 }
1154
1155 /**
1156 * Return the used survivor {@link Selector} of the GA.
1157 *
1158 * @since 3.1
1159 *
1160 * @return the used survivor {@link Selector} of the GA.
1161 */
1162 public Selector<G, C> survivorsSelector() {
1163 return _evolutionParams.survivorsSelector();
1164 }
1165
1166 /**
1167 * Return the optimization strategy.
1168 *
1169 * @since 3.1
1170 *
1171 * @return the optimization strategy
1172 */
1173 public Optimize optimize() {
1174 return _optimize;
1175 }
1176
1177 /**
1178 * Return the number of individuals of a population.
1179 *
1180 * @since 3.1
1181 *
1182 * @return the number of individuals of a population
1183 */
1184 public int populationSize() {
1185 return _evolutionParams.populationSize();
1186 }
1187
1188 /**
1189 * Return the evolution interceptor.
1190 *
1191 * @since 6.0
1192 *
1193 * @return the evolution interceptor
1194 */
1195 public EvolutionInterceptor<G, C> interceptor() {
1196 return _interceptor;
1197 }
1198
1199 /**
1200 * Create a new builder, with the current configuration.
1201 *
1202 * @since 3.1
1203 *
1204 * @return a new builder, with the current configuration
1205 */
1206 @Override
1207 public Builder<G, C> copy() {
1208 return new Builder<>(_evaluator, _genotypeFactory)
1209 .clock(_clock)
1210 .executor(_executor)
1211 .constraint(_constraint)
1212 .optimize(_optimize)
1213 .evolutionParams(_evolutionParams.build())
1214 .interceptor(_interceptor);
1215 }
1216
1217 }
1218
1219
1220 /* *************************************************************************
1221 * Engine setup
1222 **************************************************************************/
1223
1224
1225 /**
1226 * This interface represents a recipe for configuring (setup) a given
1227 * {@link Builder}. It is mainly used for grouping mutually dependent
1228 * engine configurations. The following code snippet shows a possible usage
1229 * example.
1230 *
1231 * <pre>{@code
1232 * final Engine<CharacterGene, Integer> engine = Engine.builder(problem)
1233 * .setup(new WeaselProgram<>())
1234 * .build();
1235 * }</pre>
1236 *
1237 * @see Builder#setup(Setup)
1238 *
1239 * @param <G> the gene type
1240 * @param <C> the fitness result type
1241 *
1242 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
1243 * @version 6.0
1244 * @since 6.0
1245 */
1246 @FunctionalInterface
1247 public interface Setup<
1248 G extends Gene<?, G>,
1249 C extends Comparable<? super C>
1250 > {
1251
1252 /**
1253 * Applies {@code this} setup to the given engine {@code builder}.
1254 *
1255 * @param builder the engine builder to setup (configure)
1256 */
1257 void apply(final Builder<G, C> builder);
1258
1259 }
1260 }
1261
1262
|