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