001/*
002 * Java Genetic Algorithm Library (jenetics-8.0.0).
003 * Copyright (c) 2007-2024 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019 */
020package io.jenetics.engine;
021
022import static java.lang.String.format;
023import static java.util.Objects.requireNonNull;
024import static java.util.concurrent.CompletableFuture.supplyAsync;
025import static java.util.concurrent.ForkJoinPool.commonPool;
026
027import java.time.InstantSource;
028import java.util.concurrent.CompletableFuture;
029import java.util.concurrent.Executor;
030import java.util.concurrent.ForkJoinPool;
031import java.util.function.Function;
032import java.util.function.Supplier;
033import java.util.stream.Stream;
034
035import io.jenetics.Alterer;
036import io.jenetics.AltererResult;
037import io.jenetics.Chromosome;
038import io.jenetics.Gene;
039import io.jenetics.Genotype;
040import io.jenetics.Optimize;
041import io.jenetics.Phenotype;
042import io.jenetics.Selector;
043import io.jenetics.util.BatchExecutor;
044import io.jenetics.util.Copyable;
045import io.jenetics.util.Factory;
046import io.jenetics.util.ISeq;
047import io.jenetics.util.MSeq;
048import io.jenetics.util.NanoClock;
049import io.jenetics.util.Seq;
050
051/**
052 * Genetic algorithm <em>engine</em> which is the main class. The following
053 * example shows the main steps in initializing and executing the GA.
054 *
055 * {@snippet lang="java":
056 * public class RealFunction {
057 *    // Definition of the fitness function.
058 *    private static Double eval(final Genotype<DoubleGene> gt) {
059 *        final double x = gt.gene().doubleValue();
060 *        return cos(0.5 + sin(x))*cos(x);
061 *    }
062 *
063 *    public static void main(String[] args) {
064 *        // Create/configuring the engine via its builder.
065 *        final Engine<DoubleGene, Double> engine = Engine
066 *            .builder(
067 *                RealFunction::eval,
068 *                DoubleChromosome.of(0.0, 2.0*PI))
069 *            .populationSize(500)
070 *            .optimize(Optimize.MINIMUM)
071 *            .alterers(
072 *                new Mutator<>(0.03),
073 *                new MeanAlterer<>(0.6))
074 *            .build();
075 *
076 *        // Execute the GA (engine).
077 *        final Phenotype<DoubleGene, Double> result = engine.stream()
078 *             // Truncate the evolution stream if no better individual could
079 *             // be found after 5 consecutive generations.
080 *            .limit(bySteadyFitness(5))
081 *             // Terminate the evolution after maximal 100 generations.
082 *            .limit(100)
083 *            .collect(toBestPhenotype());
084 *     }
085 * }
086 * }
087 *
088 * The architecture allows to decouple the configuration of the engine from the
089 * execution. The {@code Engine} is configured via the {@code Engine.Builder}
090 * class and can't be changed after creation. The actual <i>evolution</i> is
091 * performed by the {@link EvolutionStream}, which is created by the
092 * {@code Engine}.
093 *
094 * <H2>Concurrency</H2>
095 * By default, the engine uses the {@link ForkJoinPool#commonPool()} for
096 * executing the evolution steps and evaluating the fitness function concurrently.
097 * You can change the used execution services with the {@link Builder#executor(Executor)}
098 * method. If you want to use a different executor for evaluating the fitness
099 * functions, you have to set the {@link Builder#fitnessExecutor(BatchExecutor)}.
100 *
101 * {@snippet lang="java":
102 * final Engine<DoubleGene, Double> engine = Engine
103 *     .builder(null) // @replace substring='null' replacement="..."
104 *     // Using this execution service for parallelize the evolution steps.
105 *     .executor(Executors.newFixedThreadPool(5))
106 *     // Using one virtual thread for every fitness function evaluation.
107 *     .fitnessExecutor(BatchExecutor.ofVirtualThreads())
108 *     .build();
109 * }
110 *
111 * @implNote
112 *     This class is thread safe: The engine maintains no mutable state.
113 *     Therefore, it is safe to create multiple evolution streams with one
114 *     engine, which may be actually used in different threads.
115 *
116 * @see Engine.Builder
117 * @see EvolutionStart
118 * @see EvolutionResult
119 * @see EvolutionStream
120 * @see EvolutionStatistics
121 * @see Codec
122 * @see Constraint
123 *
124 * @param <G> the gene type
125 * @param <C> the fitness result type
126 *
127 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
128 * @since 3.0
129 * @version 7.0
130 */
131public final class Engine<
132        G extends Gene<?, G>,
133        C extends Comparable<? super C>
134>
135        implements
136                Evolution<G, C>,
137                EvolutionStreamable<G, C>,
138                Evaluator<G, C>
139{
140
141        // Problem definition.
142        private final Evaluator<G, C> _evaluator;
143        private final Factory<Genotype<G>> _genotypeFactory;
144        private final Constraint<G, C> _constraint;
145        private final Optimize _optimize;
146
147        // Evolution parameters.
148        private final EvolutionParams<G, C> _evolutionParams;
149
150        // Execution context for concurrent execution of evolving steps.
151        private final Executor _executor;
152        private final InstantSource _clock;
153        private final EvolutionInterceptor<G, C> _interceptor;
154
155
156        /**
157         * Create a new GA engine with the given parameters.
158         *
159         * @param evaluator the population fitness evaluator
160         * @param genotypeFactory the genotype factory this GA is working with.
161         * @param constraint phenotype constraint which can override the default
162         *        implementation the {@link Phenotype#isValid()} method and repairs
163         *        invalid phenotypes when needed.
164         * @param optimize the kind of optimization (minimize or maximize)
165         * @param evolutionParams the evolution parameters, which influences the
166         *        evolution process
167         * @param executor the executor used for executing the single evolved steps
168         * @param clock the clock used for calculating the timing results
169         * @param interceptor the evolution interceptor, which gives additional
170         *        possibilities to influence the actual evolution
171         * @throws NullPointerException if one of the arguments is {@code null}
172         * @throws IllegalArgumentException if the given integer values are smaller
173         *         than one.
174         */
175        Engine(
176                final Evaluator<G, C> evaluator,
177                final Factory<Genotype<G>> genotypeFactory,
178                final Constraint<G, C> constraint,
179                final Optimize optimize,
180                final EvolutionParams<G, C> evolutionParams,
181                final Executor executor,
182                final InstantSource clock,
183                final EvolutionInterceptor<G, C> interceptor
184        ) {
185                _evaluator = requireNonNull(evaluator);
186                _genotypeFactory = requireNonNull(genotypeFactory);
187                _constraint = requireNonNull(constraint);
188                _optimize = requireNonNull(optimize);
189                _evolutionParams = requireNonNull(evolutionParams);
190                _executor = requireNonNull(executor);
191                _clock = requireNonNull(clock);
192                _interceptor = requireNonNull(interceptor);
193        }
194
195        @Override
196        public EvolutionResult<G, C> evolve(final EvolutionStart<G, C> start) {
197                final EvolutionTiming timing = new EvolutionTiming(_clock);
198                timing.evolve.start();
199
200                final EvolutionStart<G, C> interceptedStart = _interceptor.before(start);
201
202                // Create initial population if `start` is empty.
203                final EvolutionStart<G, C> es = interceptedStart.population().isEmpty()
204                        ? evolutionStart(interceptedStart)
205                        : interceptedStart;
206
207                // Initial evaluation of the population.
208                final ISeq<Phenotype<G, C>> population = es.isDirty()
209                        ? timing.evaluation.timing(() -> eval(es.population()))
210                        : es.population();
211
212                // Select the offspring population.
213                final CompletableFuture<ISeq<Phenotype<G, C>>> offspring =
214                        supplyAsync(() ->
215                                timing.offspringSelection.timing(() ->
216                                        selectOffspring(population)
217                                ),
218                                _executor
219                        );
220
221                // Select the survivor population.
222                final CompletableFuture<ISeq<Phenotype<G, C>>> survivors =
223                        supplyAsync(() ->
224                                timing.survivorsSelection.timing(() ->
225                                        selectSurvivors(population)
226                                ),
227                                _executor
228                        );
229
230                // Altering the offspring population.
231                final CompletableFuture<AltererResult<G, C>> alteredOffspring =
232                        offspring.thenApplyAsync(off ->
233                                timing.offspringAlter.timing(() ->
234                                        _evolutionParams.alterer().alter(off, es.generation())
235                                ),
236                                _executor
237                        );
238
239                // Filter and replace invalid and old survivor individuals.
240                final CompletableFuture<FilterResult<G, C>> filteredSurvivors =
241                        survivors.thenApplyAsync(sur ->
242                                timing.survivorFilter.timing(() ->
243                                        filter(sur, es.generation())
244                                ),
245                                _executor
246                        );
247
248                // Filter and replace invalid and old offspring individuals.
249                final CompletableFuture<FilterResult<G, C>> filteredOffspring =
250                        alteredOffspring.thenApplyAsync(off ->
251                                timing.offspringFilter.timing(() ->
252                                        filter(off.population(), es.generation())
253                                ),
254                                _executor
255                        );
256
257                // Combining survivors and offspring to the new population.
258                final CompletableFuture<ISeq<Phenotype<G, C>>> nextPopulation =
259                        filteredSurvivors.thenCombineAsync(
260                                filteredOffspring,
261                                (s, o) -> ISeq.of(s.population().append(o.population())),
262                                _executor
263                        );
264
265                // Evaluate the fitness-function and wait for a result.
266                final ISeq<Phenotype<G, C>> pop = nextPopulation.join();
267                final ISeq<Phenotype<G, C>> result = timing.evaluation.timing(() ->
268                        eval(pop)
269                );
270
271                final int killCount =
272                        filteredOffspring.join().killCount() +
273                        filteredSurvivors.join().killCount();
274
275                final int invalidCount =
276                        filteredOffspring.join().invalidCount() +
277                        filteredSurvivors.join().invalidCount();
278
279                final int alterationCount = alteredOffspring.join().alterations();
280
281                EvolutionResult<G, C> er = EvolutionResult.of(
282                        _optimize,
283                        result,
284                        es.generation(),
285                        timing.toDurations(),
286                        killCount,
287                        invalidCount,
288                        alterationCount
289                );
290
291                final EvolutionResult<G, C> interceptedResult = _interceptor.after(er);
292                if (er != interceptedResult) {
293                        er = interceptedResult.withPopulation(
294                                timing.evaluation.timing(() ->
295                                        eval(interceptedResult.population())
296                        ));
297                }
298
299                timing.evolve.stop();
300
301                return er
302                        .withDurations(timing.toDurations())
303                        .clean();
304        }
305
306        // Selects the survivor population. A new population object is returned.
307        private ISeq<Phenotype<G, C>>
308        selectSurvivors(final ISeq<Phenotype<G, C>> population) {
309                return _evolutionParams.survivorsSize() > 0
310                        ? _evolutionParams.survivorsSelector()
311                                .select(population, _evolutionParams.survivorsSize(), _optimize)
312                        : ISeq.empty();
313        }
314
315        // Selects the offspring population. A new population object is returned.
316        private ISeq<Phenotype<G, C>>
317        selectOffspring(final ISeq<Phenotype<G, C>> population) {
318                return _evolutionParams.offspringSize() > 0
319                        ? _evolutionParams.offspringSelector()
320                                .select(population, _evolutionParams.offspringSize(), _optimize)
321                        : ISeq.empty();
322        }
323
324        // Filters out invalid and old individuals. Filtering is done in place.
325        private FilterResult<G, C> filter(
326                final Seq<Phenotype<G, C>> population,
327                final long generation
328        ) {
329                int killCount = 0;
330                int invalidCount = 0;
331
332                final MSeq<Phenotype<G, C>> pop = MSeq.of(population);
333                for (int i = 0, n = pop.size(); i < n; ++i) {
334                        final Phenotype<G, C> individual = pop.get(i);
335
336                        if (!_constraint.test(individual)) {
337                                pop.set(i, _constraint.repair(individual, generation));
338                                ++invalidCount;
339                        } else if (individual.age(generation) >
340                                                _evolutionParams.maximalPhenotypeAge())
341                        {
342                                pop.set(i, Phenotype.of(_genotypeFactory.newInstance(), generation));
343                                ++killCount;
344                        }
345                }
346
347                return new FilterResult<>(pop.toISeq(), killCount, invalidCount);
348        }
349
350
351        /* *************************************************************************
352         * Evaluation methods.
353         **************************************************************************/
354
355        /**
356         * Evaluates the fitness function of the given population with the configured
357         * {@link Evaluator} of this engine and returns a new population
358         * with its fitness value assigned.
359         *
360         * @since 5.0
361         *
362         * @see Evaluator
363         * @see Evaluator#eval(Seq)
364         *
365         * @param population the population to evaluate
366         * @return a new population with assigned fitness values
367         * @throws IllegalStateException if the configured fitness function doesn't
368         *         return a population with the same size as the input population.
369         *         This exception is also thrown if one of the populations
370         *         phenotype has no fitness value assigned.
371         */
372        @Override
373        public ISeq<Phenotype<G, C>> eval(final Seq<Phenotype<G, C>> population) {
374                final ISeq<Phenotype<G, C>> evaluated = _evaluator.eval(population);
375
376                if (population.size() != evaluated.size()) {
377                        throw new IllegalStateException(format(
378                                "Expected %d individuals, but got %d. " +
379                                        "Check your evaluator function.",
380                                population.size(), evaluated.size()
381                        ));
382                }
383                if (!evaluated.forAll(Phenotype::isEvaluated)) {
384                        throw new IllegalStateException(
385                                "Some phenotypes have no assigned fitness value. " +
386                                        "Check your evaluator function."
387                        );
388                }
389
390                return evaluated;
391        }
392
393
394        /* *************************************************************************
395         * Evolution Stream creation.
396         **************************************************************************/
397
398        @Override
399        public EvolutionStream<G, C>
400        stream(final Supplier<EvolutionStart<G, C>> start) {
401                return EvolutionStream.ofEvolution(
402                        () -> evolutionStart(start.get()),
403                        this
404                );
405        }
406
407        @Override
408        public EvolutionStream<G, C> stream(final EvolutionInit<G> init) {
409                return stream(evolutionStart(init));
410        }
411
412        private EvolutionStart<G, C>
413        evolutionStart(final EvolutionStart<G, C> start) {
414                final ISeq<Phenotype<G, C>> population = start.population();
415                final long gen = start.generation();
416
417                final Stream<Phenotype<G, C>> stream = Stream.concat(
418                        population.stream(),
419                        _genotypeFactory.instances()
420                                .map(gt -> Phenotype.of(gt, gen))
421                );
422
423                final ISeq<Phenotype<G, C>> pop = stream
424                        .limit(populationSize())
425                        .collect(ISeq.toISeq());
426
427                return EvolutionStart.of(pop, gen);
428        }
429
430        private EvolutionStart<G, C>
431        evolutionStart(final EvolutionInit<G> init) {
432                final ISeq<Genotype<G>> pop = init.population();
433                final long gen = init.generation();
434
435                return evolutionStart(
436                        EvolutionStart.of(
437                                pop.map(gt -> Phenotype.of(gt, gen)),
438                                gen
439                        )
440                );
441        }
442
443        /* *************************************************************************
444         * Property access methods.
445         **************************************************************************/
446
447        /**
448         * Return the used genotype {@link Factory} of the GA. The genotype factory
449         * is used for creating the initial population and new, random individuals
450         * when needed (as replacement for invalid and/or died genotypes).
451         *
452         * @return the used genotype {@link Factory} of the GA.
453         */
454        public Factory<Genotype<G>> genotypeFactory() {
455                return _genotypeFactory;
456        }
457
458        /**
459         * Return the constraint of the evolution problem.
460         *
461         * @since 5.0
462         *
463         * @return the constraint of the evolution problem
464         */
465        public Constraint<G, C> constraint() {
466                return _constraint;
467        }
468
469        /**
470         * Return the used survivor {@link Selector} of the GA.
471         *
472         * @return the used survivor {@link Selector} of the GA.
473         */
474        public Selector<G, C> survivorsSelector() {
475                return _evolutionParams.survivorsSelector();
476        }
477
478        /**
479         * Return the used offspring {@link Selector} of the GA.
480         *
481         * @return the used offspring {@link Selector} of the GA.
482         */
483        public Selector<G, C> offspringSelector() {
484                return _evolutionParams.offspringSelector();
485        }
486
487        /**
488         * Return the used {@link Alterer} of the GA.
489         *
490         * @return the used {@link Alterer} of the GA.
491         */
492        public Alterer<G, C> alterer() {
493                return _evolutionParams.alterer();
494        }
495
496        /**
497         * Return the number of selected offspring.
498         *
499         * @return the number of selected offspring
500         */
501        public int offspringSize() {
502                return _evolutionParams.offspringSize();
503        }
504
505        /**
506         * The number of selected survivors.
507         *
508         * @return the number of selected survivors
509         */
510        public int survivorsSize() {
511                return _evolutionParams.survivorsSize();
512        }
513
514        /**
515         * Return the number of individuals of a population.
516         *
517         * @return the number of individuals of a population
518         */
519        public int populationSize() {
520                return _evolutionParams.populationSize();
521        }
522
523        /**
524         * Return the maximal allowed phenotype age.
525         *
526         * @return the maximal allowed phenotype age
527         */
528        public long maximalPhenotypeAge() {
529                return _evolutionParams.maximalPhenotypeAge();
530        }
531
532        /**
533         * Return the optimization strategy.
534         *
535         * @return the optimization strategy
536         */
537        public Optimize optimize() {
538                return _optimize;
539        }
540
541        /**
542         * Return the {@link InstantSource} the engine is using for measuring the
543         * execution time.
544         *
545         * @return the clock used for measuring the execution time
546         */
547        public InstantSource clock() {
548                return _clock;
549        }
550
551        /**
552         * Return the {@link Executor} the engine is using for executing the
553         * evolution steps.
554         *
555         * @return the executor used for performing the evolution steps
556         */
557        public Executor executor() {
558                return _executor;
559        }
560
561        /**
562         * Return the evolution interceptor.
563         *
564         * @since 6.0
565         *
566         * @return the evolution result mapper
567         */
568        public EvolutionInterceptor<G, C> interceptor() {
569                return _interceptor;
570        }
571
572        /**
573         * Create a new evolution {@code Engine.Builder} initialized with the values
574         * of the current evolution {@code Engine}. With this method, the evolution
575         * engine can serve as a template for a new one.
576         *
577         * @return a new engine builder
578         */
579        public Builder<G, C> toBuilder() {
580                return new Builder<>(_evaluator, _genotypeFactory)
581                        .clock(_clock)
582                        .executor(_executor)
583                        .optimize(_optimize)
584                        .constraint(_constraint)
585                        .evolutionParams(_evolutionParams)
586                        .interceptor(_interceptor);
587        }
588
589
590        /* *************************************************************************
591         * Static Builder methods.
592         **************************************************************************/
593
594        /**
595         * Create a new evolution {@code Engine.Builder} with the given fitness
596         * function and genotype factory.
597         *
598         * @param ff the fitness function
599         * @param gtf the genotype factory
600         * @param <G> the gene type
601         * @param <C> the fitness function result type
602         * @return a new engine builder
603         * @throws java.lang.NullPointerException if one of the arguments is
604         *         {@code null}.
605         */
606        public static <G extends Gene<?, G>, C extends Comparable<? super C>>
607        Builder<G, C> builder(
608                final Function<? super Genotype<G>, ? extends C> ff,
609                final Factory<Genotype<G>> gtf
610        ) {
611                return new Builder<>(
612                        new FitnessEvaluator<>(ff, BatchExecutor.of(commonPool())),
613                        gtf
614                );
615        }
616
617        /**
618         * Create a new evolution {@code Engine.Builder} with the given fitness
619         * function and problem {@code codec}.
620         *
621         * @since 3.2
622         *
623         * @param ff the fitness evaluator
624         * @param codec the problem codec
625         * @param <T> the fitness function input type
626         * @param <C> the fitness function result type
627         * @param <G> the gene type
628         * @return a new engine builder
629         * @throws java.lang.NullPointerException if one of the arguments is
630         *         {@code null}.
631         */
632        public static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
633        Builder<G, C> builder(
634                final Function<? super T, ? extends C> ff,
635                final Codec<T, G> codec
636        ) {
637                return builder(ff.compose(codec.decoder()), codec.encoding());
638        }
639
640        /**
641         * Create a new evolution {@code Engine.Builder} for the given
642         * {@link Problem}.
643         *
644         * @since 3.4
645         *
646         * @param problem the problem to be solved by the evolution {@code Engine}
647         * @param <T> the (<i>native</i>) argument type of the problem fitness function
648         * @param <G> the gene type the evolution engine is working with
649         * @param <C> the result type of the fitness function
650         * @return Create a new evolution {@code Engine.Builder}
651         */
652        public static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
653        Builder<G, C> builder(final Problem<T, G, C> problem) {
654                final var builder = builder(problem.fitness(), problem.codec());
655                problem.constraint().ifPresent(builder::constraint);
656                return builder;
657        }
658
659        /**
660         * Create a new evolution {@code Engine.Builder} with the given fitness
661         * function and chromosome templates.
662         *
663         * @param ff the fitness function
664         * @param chromosome the first chromosome
665         * @param chromosomes the chromosome templates
666         * @param <G> the gene type
667         * @param <C> the fitness function result type
668         * @return a new engine builder
669         * @throws java.lang.NullPointerException if one of the arguments is
670         *         {@code null}.
671         */
672        @SafeVarargs
673        public static <G extends Gene<?, G>, C extends Comparable<? super C>>
674        Builder<G, C> builder(
675                final Function<? super Genotype<G>, ? extends C> ff,
676                final Chromosome<G> chromosome,
677                final Chromosome<G>... chromosomes
678        ) {
679                return builder(ff, Genotype.of(chromosome, chromosomes));
680        }
681
682
683        /* *************************************************************************
684         * Engine builder
685         **************************************************************************/
686
687
688        /**
689         * Builder class for building GA {@code Engine} instances.
690         *
691         * @see Engine
692         *
693         * @param <G> the gene type
694         * @param <C> the fitness function result type
695         *
696         * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
697         * @since 3.0
698         * @version 6.0
699         */
700        public static final class Builder<
701                G extends Gene<?, G>,
702                C extends Comparable<? super C>
703        >
704                implements Copyable<Builder<G, C>>
705        {
706
707                // No default values for this properties.
708                private final Evaluator<G, C> _evaluator;
709                private final Factory<Genotype<G>> _genotypeFactory;
710                private Constraint<G, C> _constraint;
711                private Optimize _optimize = Optimize.MAXIMUM;
712
713                // Evolution parameters.
714                private final EvolutionParams.Builder<G, C> _evolutionParams =
715                        EvolutionParams.builder();
716
717
718                // Engine execution environment.
719                private Executor _executor = commonPool();
720                private BatchExecutor _fitnessExecutor = null;
721                private InstantSource _clock = NanoClock.systemUTC();
722
723                private EvolutionInterceptor<G, C> _interceptor =
724                        EvolutionInterceptor.identity();
725
726                /**
727                 * Create a new evolution {@code Engine.Builder} with the given fitness
728                 * evaluator and genotype factory. This is the most general way of
729                 * creating an engine builder.
730                 *
731                 * @since 5.0
732                 *
733                 * @see Engine#builder(Function, Codec)
734                 * @see Engine#builder(Function, Factory)
735                 * @see Engine#builder(Problem)
736                 * @see Engine#builder(Function, Chromosome, Chromosome[])
737                 *
738                 * @param evaluator the fitness evaluator
739                 * @param gtf the genotype factory
740                 * @throws NullPointerException if one of the arguments is {@code null}.
741                 */
742                public Builder(
743                        final Evaluator<G, C> evaluator,
744                        final Factory<Genotype<G>> gtf
745                ) {
746                        _genotypeFactory = requireNonNull(gtf);
747                        _evaluator = requireNonNull(evaluator);
748                }
749
750                /**
751                 * Applies the given {@code setup} recipe to {@code this} engine builder.
752                 *
753                 * @since 6.0
754                 *
755                 * @param setup the setup recipe applying to {@code this} builder
756                 * @return {@code this} builder, for command chaining
757                 * @throws NullPointerException if the {@code setup} is {@code null}.
758                 */
759                public Builder<G, C> setup(final Setup<G, C> setup) {
760                        setup.apply(this);
761                        return this;
762                }
763
764                /**
765                 * Set the evolution parameters used by the engine.
766                 *
767                 * @since 5.2
768                 *
769                 * @param params the evolution parameter
770                 * @return {@code this} builder, for command chaining
771                 * @throws NullPointerException if the {@code params} is {@code null}.
772                 */
773                public Builder<G, C> evolutionParams(final EvolutionParams<G, C> params) {
774                        _evolutionParams.evolutionParams(params);
775                        return this;
776                }
777
778                /**
779                 * The selector used for selecting the offspring population. <i>Default
780                 * values is set to {@code TournamentSelector<>(3)}.</i>
781                 *
782                 * @param selector used for selecting the offspring population
783                 * @return {@code this} builder, for command chaining
784                 * @throws NullPointerException if one of the {@code selector} is
785                 *         {@code null}.
786                 */
787                public Builder<G, C> offspringSelector(final Selector<G, C> selector) {
788                        _evolutionParams.offspringSelector(selector);
789                        return this;
790                }
791
792                /**
793                 * The selector used for selecting the survivor population. <i>Default
794                 * values is set to {@code TournamentSelector<>(3)}.</i>
795                 *
796                 * @param selector used for selecting survivor population
797                 * @return {@code this} builder, for command chaining
798                 * @throws NullPointerException if one of the {@code selector} is
799                 *         {@code null}.
800                 */
801                public Builder<G, C> survivorsSelector(final Selector<G, C> selector) {
802                        _evolutionParams.survivorsSelector(selector);
803                        return this;
804                }
805
806                /**
807                 * The selector used for selecting the survivors and offspring
808                 * population. <i>Default values is set to
809                 * {@code TournamentSelector<>(3)}.</i>
810                 *
811                 * @param selector used for selecting survivors and offspring population
812                 * @return {@code this} builder, for command chaining
813                 * @throws NullPointerException if one of the {@code selector} is
814                 *         {@code null}.
815                 */
816                public Builder<G, C> selector(final Selector<G, C> selector) {
817                        _evolutionParams.selector(selector);
818                        return this;
819                }
820
821                /**
822                 * The alterers used for alter the offspring population. <i>Default
823                 * values is set to {@code new SinglePointCrossover<>(0.2)} followed by
824                 * {@code new Mutator<>(0.15)}.</i>
825                 *
826                 * @param first the first alterer used for alter the offspring
827                 *        population
828                 * @param rest the rest of the alterers used for alter the offspring
829                 *        population
830                 * @return {@code this} builder, for command chaining
831                 * @throws NullPointerException if one of the alterers is {@code null}.
832                 */
833                @SafeVarargs
834                public final Builder<G, C> alterers(
835                        final Alterer<G, C> first,
836                        final Alterer<G, C>... rest
837                ) {
838                        _evolutionParams.alterers(first, rest);
839                        return this;
840                }
841
842                /**
843                 * The phenotype constraint is used for detecting invalid individuals
844                 * and repairing them.
845                 *
846                 * <p><i>Default implementation uses {@code Phenotype::isValid} for
847                 * validating the phenotype.</i></p>
848                 *
849                 * @since 5.0
850                 *
851                 * @param constraint phenotype constraint which can override the default
852                 *        implementation the {@link Phenotype#isValid()} method and repairs
853                 *        invalid phenotypes when needed.
854                 * @return {@code this} builder, for command chaining
855                 * @throws NullPointerException if one of the {@code constraint} is
856                 *         {@code null}.
857                 */
858                public Builder<G, C> constraint(final Constraint<G, C> constraint) {
859                        _constraint = constraint;
860                        return this;
861                }
862
863                /**
864                 * The optimization strategy used by the engine. <i>Default values is
865                 * set to {@code Optimize.MAXIMUM}.</i>
866                 *
867                 * @param optimize the optimization strategy used by the engine
868                 * @return {@code this} builder, for command chaining
869                 * @throws NullPointerException if one of the {@code optimize} is
870                 *         {@code null}.
871                 */
872                public Builder<G, C> optimize(final Optimize optimize) {
873                        _optimize = requireNonNull(optimize);
874                        return this;
875                }
876
877                /**
878                 * Set to a fitness-maximizing strategy.
879                 *
880                 * @since 3.4
881                 *
882                 * @return {@code this} builder, for command chaining
883                 */
884                public Builder<G, C> maximizing() {
885                        return optimize(Optimize.MAXIMUM);
886                }
887
888                /**
889                 * Set to a fitness minimizing strategy.
890                 *
891                 * @since 3.4
892                 *
893                 * @return {@code this} builder, for command chaining
894                 */
895                public Builder<G, C> minimizing() {
896                        return optimize(Optimize.MINIMUM);
897                }
898
899                /**
900                 * The offspring fraction. <i>Default values is set to {@code 0.6}.</i>
901                 * This method call is equivalent to
902                 * {@code survivorsFraction(1 - offspringFraction)} and will override
903                 * any previously set survivors-fraction.
904                 *
905                 * @see #survivorsFraction(double)
906                 *
907                 * @param fraction the offspring fraction
908                 * @return {@code this} builder, for command chaining
909                 * @throws java.lang.IllegalArgumentException if the fraction is not
910                 *         within the range [0, 1].
911                 */
912                public Builder<G, C> offspringFraction(final double fraction) {
913                        _evolutionParams.offspringFraction(fraction);
914                        return this;
915                }
916
917                /**
918                 * The survivor fraction. <i>Default values is set to {@code 0.4}.</i>
919                 * This method call is equivalent to
920                 * {@code offspringFraction(1 - survivorsFraction)} and will override
921                 * any previously set offspring-fraction.
922                 *
923                 * @since 3.8
924                 *
925                 * @see #offspringFraction(double)
926                 *
927                 * @param fraction the survivor fraction
928                 * @return {@code this} builder, for command chaining
929                 * @throws java.lang.IllegalArgumentException if the fraction is not
930                 *         within the range [0, 1].
931                 */
932                public Builder<G, C> survivorsFraction(final double fraction) {
933                        return offspringFraction(1 - fraction);
934                }
935
936                /**
937                 * The number of offspring individuals.
938                 *
939                 * @since 3.8
940                 *
941                 * @param size the number of offspring individuals.
942                 * @return {@code this} builder, for command chaining
943                 * @throws java.lang.IllegalArgumentException if the size is not
944                 *         within the range [0, population-size].
945                 */
946                public Builder<G, C> offspringSize(final int size) {
947                        if (size < 0) {
948                                throw new IllegalArgumentException(format(
949                                        "Offspring size must be greater or equal zero, but was %s.",
950                                        size
951                                ));
952                        }
953
954                        return offspringFraction(size/(double)_evolutionParams.populationSize());
955                }
956
957                /**
958                 * The number of survivors.
959                 *
960                 * @since 3.8
961                 *
962                 * @param size the number of survivors.
963                 * @return {@code this} builder, for command chaining
964                 * @throws java.lang.IllegalArgumentException if the size is not
965                 *         within the range [0, population-size].
966                 */
967                public Builder<G, C> survivorsSize(final int size) {
968                        if (size < 0) {
969                                throw new IllegalArgumentException(format(
970                                        "Survivors must be greater or equal zero, but was %s.",
971                                        size
972                                ));
973                        }
974
975                        return survivorsFraction(size/(double)_evolutionParams.populationSize());
976                }
977
978                /**
979                 * The number of individuals which form the population. <i>Default
980                 * values is set to {@code 50}.</i>
981                 *
982                 * @param size the number of individuals of a population
983                 * @return {@code this} builder, for command chaining
984                 * @throws java.lang.IllegalArgumentException if {@code size < 1}
985                 */
986                public Builder<G, C> populationSize(final int size) {
987                        _evolutionParams.populationSize(size);
988                        return this;
989                }
990
991                /**
992                 * The maximal allowed age of a phenotype. <i>Default values is set to
993                 * {@code 70}.</i>
994                 *
995                 * @param age the maximal phenotype age
996                 * @return {@code this} builder, for command chaining
997                 * @throws java.lang.IllegalArgumentException if {@code age < 1}
998                 */
999                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                G extends Gene<?, G>,
1305                C 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
1319